mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-23 14:08:40 +00:00
Merge branch 'master' into bug3677
This commit is contained in:
@@ -111,6 +111,7 @@ SAP is at the center of today’s technology revolution, developing innovations
|
||||
* [[Linking Race Videos|wiki/howto/eventmanagers/linking-race-videos]]
|
||||
* [[Import official results|wiki/howto/eventmanagers/results-import]]
|
||||
* [[Pairing lists|wiki/howto/eventmanagers/pairing-lists]]
|
||||
* [[Manage media content|wiki/howto/eventmanagers/Manage-media-content]]
|
||||
|
||||
### Setup
|
||||
|
||||
@@ -140,6 +141,7 @@ SAP is at the center of today’s technology revolution, developing innovations
|
||||
* [[Kieler Woche event page|wiki/events/kieler-woche-2015]]
|
||||
* [[Charleston Race Week 2016|wiki/events/Charleston-Race-Week-2016]]
|
||||
* [[Sailing Leagues 2016|wiki/events/sailing-Leagues-2016]]
|
||||
* [[Media Content|wiki/events/Sailing-events-media-content]]
|
||||
|
||||
## Planning
|
||||
* [[Overview|https://wiki.sapsailing.com/pages/wiki/planning/]]
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ public class BoatDTO extends NamedDTO implements Serializable {
|
||||
public String getSailId() {
|
||||
return sailId;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package com.sap.sailing.domain.common.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
|
||||
public class PairingListDTO implements Serializable{
|
||||
|
||||
private static final long serialVersionUID = 102220422437194196L;
|
||||
private List<List<List<Pair<CompetitorDTO, BoatDTO>>>> pairingList;
|
||||
private List<String> raceColumnNames;
|
||||
|
||||
public PairingListDTO() { }
|
||||
|
||||
public PairingListDTO(List<List<List<Pair<CompetitorDTO, BoatDTO>>>> result) {
|
||||
this(result, null);
|
||||
}
|
||||
|
||||
public PairingListDTO(List<List<List<Pair<CompetitorDTO, BoatDTO>>>> result, List<String> raceColumnNames) {
|
||||
this.pairingList = result;
|
||||
this.raceColumnNames = raceColumnNames;
|
||||
}
|
||||
|
||||
public List<List<List<Pair<CompetitorDTO, BoatDTO>>>> getPairingList() {
|
||||
return pairingList;
|
||||
}
|
||||
|
||||
public List<BoatDTO> getBoats() {
|
||||
List<BoatDTO> boats = new ArrayList<>();
|
||||
for (List<Pair<CompetitorDTO, BoatDTO>> fleet : this.pairingList.get(0)) {
|
||||
for (Pair<CompetitorDTO, BoatDTO> competitorAndBoatPair : fleet) {
|
||||
if (!boats.contains(competitorAndBoatPair.getB())) {
|
||||
boats.add(competitorAndBoatPair.getB());
|
||||
}
|
||||
}
|
||||
}
|
||||
return boats;
|
||||
}
|
||||
|
||||
public List<String> getRaceColumnNames() {
|
||||
return raceColumnNames;
|
||||
}
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
package com.sap.sailing.domain.common.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class PairingListTemplateDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 7155851765154315798L;
|
||||
|
||||
private int flightCount = 0;
|
||||
private int groupCount = 0;
|
||||
private int competitorCount = 0;
|
||||
private int flightMultiplier = 0;
|
||||
private int[][] pairingListTemplate;
|
||||
private double quality;
|
||||
|
||||
private Iterable<String> selectedFlightNames;
|
||||
|
||||
public PairingListTemplateDTO() { }
|
||||
|
||||
public PairingListTemplateDTO(int competitorCount, int flightMultiplier) {
|
||||
this(0, 0, competitorCount, flightMultiplier, null, 0.0, null);
|
||||
}
|
||||
|
||||
public PairingListTemplateDTO(int competitorCount, int flightMultiplier, int[][] pairingListTemplate, double quality) {
|
||||
this(0, 0, competitorCount, flightMultiplier, pairingListTemplate, quality, null);
|
||||
}
|
||||
|
||||
public PairingListTemplateDTO(int competitorCount, int[][] pairingListTemplate, double quality) {
|
||||
this(0, 0, competitorCount, 0, pairingListTemplate, quality, null);
|
||||
}
|
||||
|
||||
public PairingListTemplateDTO(int flightCount, int groupCount, int competitorCount, int flightMultiplier, int[][] pairingListTemplate, double quality) {
|
||||
this(flightCount, groupCount, competitorCount, flightMultiplier, pairingListTemplate, quality, null);
|
||||
}
|
||||
|
||||
public PairingListTemplateDTO(int flightCount, int groupCount, int competitorCount, int flightMultiplier, int[][] pairingListTemplate, double quality, Iterable<String> selectedFlightNames) {
|
||||
this.flightCount = flightCount;
|
||||
this.groupCount = groupCount;
|
||||
this.competitorCount = competitorCount;
|
||||
this.flightMultiplier = flightMultiplier;
|
||||
this.quality = quality;
|
||||
this.pairingListTemplate = pairingListTemplate;
|
||||
this.selectedFlightNames = selectedFlightNames;
|
||||
}
|
||||
|
||||
public void setFlightCount(int flightCount){
|
||||
this.flightCount=flightCount;
|
||||
}
|
||||
public void setGroupCount(int groupCount) {
|
||||
this.groupCount = groupCount;
|
||||
}
|
||||
|
||||
public void setFlightMultiplier(int flightMultiplier) {
|
||||
this.flightMultiplier = flightMultiplier;
|
||||
}
|
||||
|
||||
public void setSelectedFlightNames(Iterable<String> selectedFlightNames) {
|
||||
this.selectedFlightNames = selectedFlightNames;
|
||||
}
|
||||
|
||||
public int[][] getPairingListTemplate() {
|
||||
return this.pairingListTemplate;
|
||||
}
|
||||
|
||||
public double getQuality() {
|
||||
return this.quality;
|
||||
}
|
||||
|
||||
public int getFlightCount() {
|
||||
return this.flightCount;
|
||||
}
|
||||
|
||||
public int getGroupCount() {
|
||||
return this.groupCount;
|
||||
}
|
||||
|
||||
public int getCompetitorCount() {
|
||||
return this.competitorCount;
|
||||
}
|
||||
|
||||
public int getFlightMultiplier() {
|
||||
return flightMultiplier;
|
||||
}
|
||||
|
||||
public Iterable<String> getSelectedFlightNames() {
|
||||
return selectedFlightNames;
|
||||
}
|
||||
|
||||
}
|
||||
+1
@@ -6,6 +6,7 @@ package com.sap.sailing.domain.common.security;
|
||||
public enum Permission implements com.sap.sse.security.shared.Permission {
|
||||
// AdminConsole permissions
|
||||
MANAGE_EVENTS,
|
||||
MANAGE_PAIRING_LISTS,
|
||||
MANAGE_REGATTAS,
|
||||
MANAGE_TRACKED_RACES,
|
||||
SHOW_TRACKED_RACES,
|
||||
|
||||
+36
-21
@@ -4,7 +4,6 @@ import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@@ -19,7 +18,9 @@ import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifierImpl;
|
||||
import com.sap.sailing.domain.trackimport.FormatNotSupportedException;
|
||||
import com.sap.sailing.domain.trackimport.GPSFixImporter;
|
||||
import com.sap.sailing.server.trackfiles.impl.CompressedStreamsUtil;
|
||||
import com.sap.sailing.server.trackfiles.impl.ExpeditionExtendedDataImporterImpl;
|
||||
import com.sap.sailing.server.trackfiles.impl.ExpeditionImportFileHandler;
|
||||
|
||||
public class ExpeditionGPSFixImporter implements GPSFixImporter {
|
||||
private static final String LAT_COLUMN_HEADING = ExpeditionExtendedDataImporterImpl.COL_NAME_LAT;
|
||||
@@ -32,36 +33,50 @@ public class ExpeditionGPSFixImporter implements GPSFixImporter {
|
||||
final String sourceName)
|
||||
throws FormatNotSupportedException, IOException {
|
||||
TrackFileImportDeviceIdentifier device = new TrackFileImportDeviceIdentifierImpl(sourceName, getType() + "@" + new Date());
|
||||
final BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
|
||||
final String headerLine = br.readLine();
|
||||
final Map<String, Integer> columnDefinitions = ExpeditionExtendedDataImporterImpl.parseHeader(headerLine);
|
||||
final AtomicInteger lineNr = new AtomicInteger(0);
|
||||
final AtomicBoolean importedFixes = new AtomicBoolean(false);
|
||||
br.lines().forEach(line->{
|
||||
if (!line.trim().isEmpty()) {
|
||||
ExpeditionExtendedDataImporterImpl.parseLine(lineNr.incrementAndGet(), sourceName, line, columnDefinitions,
|
||||
(timePoint, columnValues, columns)->{
|
||||
final double latDeg = Double.parseDouble(columnValues[columns.get(LAT_COLUMN_HEADING)]);
|
||||
final double lonDeg = Double.parseDouble(columnValues[columns.get(LON_COLUMN_HEADING)]);
|
||||
final double cogDeg = Double.parseDouble(columnValues[columns.get(COG_COLUMN_HEADING)]);
|
||||
final double sogKnots = Double.parseDouble(columnValues[columns.get(SOG_COLUMN_HEADING)]);
|
||||
final GPSFixMoving fix = new GPSFixMovingImpl(new DegreePosition(latDeg, lonDeg), timePoint,
|
||||
new KnotSpeedWithBearingImpl(sogKnots, new DegreeBearingImpl(cogDeg)));
|
||||
callback.addFix(fix, device);
|
||||
importedFixes.set(true);
|
||||
CompressedStreamsUtil.handlePotentiallyCompressedFiles(sourceName, inputStream,
|
||||
new ExpeditionImportFileHandler() {
|
||||
|
||||
@Override
|
||||
protected void handleExpeditionFile(String fileName, InputStream stream) throws IOException {
|
||||
final BufferedReader br = new BufferedReader(new InputStreamReader(stream));
|
||||
final String headerLine = br.readLine();
|
||||
final Map<String, Integer> columnDefinitions = ExpeditionExtendedDataImporterImpl
|
||||
.parseHeader(headerLine);
|
||||
final AtomicInteger lineNr = new AtomicInteger(0);
|
||||
br.lines().forEach(line -> {
|
||||
if (!line.trim().isEmpty()) {
|
||||
ExpeditionExtendedDataImporterImpl.parseLine(lineNr.incrementAndGet(), fileName, line,
|
||||
columnDefinitions, (timePoint, columnValues, columns) -> {
|
||||
final double latDeg = Double
|
||||
.parseDouble(columnValues[columns.get(LAT_COLUMN_HEADING)]);
|
||||
final double lonDeg = Double
|
||||
.parseDouble(columnValues[columns.get(LON_COLUMN_HEADING)]);
|
||||
final double cogDeg = Double
|
||||
.parseDouble(columnValues[columns.get(COG_COLUMN_HEADING)]);
|
||||
final double sogKnots = Double
|
||||
.parseDouble(columnValues[columns.get(SOG_COLUMN_HEADING)]);
|
||||
final GPSFixMoving fix = new GPSFixMovingImpl(
|
||||
new DegreePosition(latDeg, lonDeg), timePoint,
|
||||
new KnotSpeedWithBearingImpl(sogKnots,
|
||||
new DegreeBearingImpl(cogDeg)));
|
||||
callback.addFix(fix, device);
|
||||
importedFixes.set(true);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return importedFixes.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<String> getSupportedFileExtensions() {
|
||||
return Arrays.asList(new String[] { "csv", "log", "txt" });
|
||||
return ExpeditionImportFileHandler.supportedExpeditionLogFileExtensions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "Expedition";
|
||||
return GPSFixImporter.EXPEDITION_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-1
@@ -74,8 +74,12 @@ public interface RaceLogTrackingAdapter {
|
||||
* Denotes the entire {@link Leaderboard} for racelog-tracking, by calling the
|
||||
* {@link #denoteRaceForRaceLogTracking(RacingEventService, Leaderboard, RaceColumn, Fleet, String)} method for each
|
||||
* {@link RaceLog}.
|
||||
*
|
||||
* @param prefix Use this parameter to set the racename in the denoteEvent. The prefix will be used for all races.
|
||||
* Additional to the prefix there will be a serial number that gives every race a individual name. You can pass null
|
||||
* to get the default denote name. The default looks like: regatta name + racecolumn name + race name.
|
||||
*/
|
||||
void denoteAllRacesForRaceLogTracking(RacingEventService service, Leaderboard leaderboard)
|
||||
void denoteAllRacesForRaceLogTracking(RacingEventService service, Leaderboard leaderboard, String prefix)
|
||||
throws NotDenotableForRaceLogTrackingException;
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -81,7 +81,7 @@ public class RaceLogConnectivityParams extends AbstractRaceTrackingConnectivityP
|
||||
throw new RaceNotCreatedException("No regatta for race-log tracked race");
|
||||
}
|
||||
DynamicTrackedRegatta trackedRegatta = trackedRegattaRegistry.getOrCreateTrackedRegatta(regatta);
|
||||
return new RaceLogRaceTracker(trackedRegatta, this, windStore, raceLogResolver, this);
|
||||
return new RaceLogRaceTracker(trackedRegatta, this, windStore, raceLogResolver, this, trackedRegattaRegistry);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+36
-4
@@ -1,5 +1,6 @@
|
||||
package com.sap.sailing.domain.racelogtracking.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -47,6 +48,7 @@ import com.sap.sailing.domain.base.Sideline;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.base.impl.CourseDataImpl;
|
||||
import com.sap.sailing.domain.base.impl.CourseImpl;
|
||||
import com.sap.sailing.domain.base.impl.RaceColumnListenerWithDefaultAction;
|
||||
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
|
||||
import com.sap.sailing.domain.common.PassingInstruction;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
@@ -61,6 +63,7 @@ import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.RaceHandle;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||
import com.sap.sailing.domain.tracking.WindStore;
|
||||
import com.sap.sailing.domain.tracking.WindTrack;
|
||||
import com.sap.sse.common.Util;
|
||||
@@ -91,12 +94,14 @@ public class RaceLogRaceTracker extends AbstractRaceTrackerBaseImpl {
|
||||
private final WindStore windStore;
|
||||
private final DynamicTrackedRegatta trackedRegatta;
|
||||
private final RaceLogResolver raceLogResolver;
|
||||
private final TrackedRegattaRegistry trackedRegattaRegistry;
|
||||
|
||||
private volatile DynamicTrackedRace trackedRace;
|
||||
|
||||
public RaceLogRaceTracker(DynamicTrackedRegatta regatta, RaceLogConnectivityParams params, WindStore windStore,
|
||||
RaceLogResolver raceLogResolver, RaceLogConnectivityParams connectivityParams) {
|
||||
RaceLogResolver raceLogResolver, RaceLogConnectivityParams connectivityParams, TrackedRegattaRegistry trackedRegattaRegistry) {
|
||||
super(connectivityParams);
|
||||
this.trackedRegattaRegistry = trackedRegattaRegistry;
|
||||
this.params = params;
|
||||
this.windStore = windStore;
|
||||
this.trackedRegatta = regatta;
|
||||
@@ -144,16 +149,13 @@ public class RaceLogRaceTracker extends AbstractRaceTrackerBaseImpl {
|
||||
public void visit(RegattaLogDefineMarkEvent event) {
|
||||
RaceLogRaceTracker.this.onDefineMarkEvent(event);
|
||||
}
|
||||
|
||||
};
|
||||
visitors.put(log, visitor);
|
||||
((RegattaLog) log).addListener(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(String.format("Created race-log tracker for: %s %s %s", params.getLeaderboard(),
|
||||
params.getRaceColumn(), params.getFleet()));
|
||||
|
||||
// load race for which tracking already started
|
||||
if (new RaceLogTrackingStateAnalyzer(params.getRaceLog()).analyze() == RaceLogTrackingState.TRACKING) {
|
||||
startTracking(null);
|
||||
@@ -309,5 +311,35 @@ public class RaceLogRaceTracker extends AbstractRaceTrackerBaseImpl {
|
||||
synchronized (this) {
|
||||
this.notifyAll();
|
||||
}
|
||||
registerListenerThatWillRemoveThisRaceWhenTheRaceColumnIsRemoved();
|
||||
}
|
||||
|
||||
private void registerListenerThatWillRemoveThisRaceWhenTheRaceColumnIsRemoved() {
|
||||
getRegatta().addRaceColumnListener(new RaceColumnListenerWithDefaultAction() {
|
||||
private static final long serialVersionUID = -2924864263579432528L;
|
||||
|
||||
@Override
|
||||
public void defaultAction() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void raceColumnRemovedFromContainer(RaceColumn raceColumn) {
|
||||
try {
|
||||
trackedRegattaRegistry.removeRace(getRegatta(), getRace());
|
||||
} catch (IOException | InterruptedException e) {
|
||||
logger.log(Level.WARNING, "Error trying to remove smart phone / race log tracked race whose race column was deleted: "+
|
||||
e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This listener is transient and will therefore not be serialized to any replicas or with
|
||||
* the master data import.
|
||||
*/
|
||||
@Override
|
||||
public boolean isTransient() {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+9
-3
@@ -172,11 +172,17 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void denoteAllRacesForRaceLogTracking(final RacingEventService service, final Leaderboard leaderboard)
|
||||
throws NotDenotableForRaceLogTrackingException {
|
||||
public void denoteAllRacesForRaceLogTracking(final RacingEventService service, final Leaderboard leaderboard,
|
||||
final String prefix) throws NotDenotableForRaceLogTrackingException {
|
||||
int fleetcount = 1;
|
||||
for (RaceColumn column : leaderboard.getRaceColumns()) {
|
||||
for (Fleet fleet : column.getFleets()) {
|
||||
denoteRaceForRaceLogTracking(service, leaderboard, column, fleet, null);
|
||||
if (prefix != null) {
|
||||
denoteRaceForRaceLogTracking(service, leaderboard, column, fleet, prefix + fleetcount);
|
||||
} else {
|
||||
denoteRaceForRaceLogTracking(service, leaderboard, column, fleet, null);
|
||||
}
|
||||
fleetcount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -49,4 +49,9 @@ public class RaceLogDenoteForTrackingEventImpl extends RaceLogEventImpl implemen
|
||||
public Serializable getRaceId() {
|
||||
return raceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getShortInfo() {
|
||||
return getRaceName();
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -550,6 +550,10 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
||||
public void setControlTrackingFromStartAndFinishTimes(
|
||||
boolean controlTrackingFromStartAndFinishTimes) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFleetsCanRunInParallelToTrue() {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ public class MockedTrackedRaceWithFixedRank extends MockedTrackedRace {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boat getBoatOfCompetitorById(Serializable competitorID) {
|
||||
public Boat getBoatOfCompetitor(Competitor competitor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ public class MockedTrackedRaceWithFixedRankAndManyCompetitors extends MockedTrac
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Boat getBoatOfCompetitorById(Serializable competitorID) {
|
||||
public Boat getBoatOfCompetitor(Competitor competitor) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.sap.sailing.domain.base;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.base.impl.BoatClassImpl;
|
||||
import com.sap.sailing.domain.base.impl.BoatImpl;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.pairinglist.PairingList;
|
||||
|
||||
public class PairingListLeaderboardAdapter implements PairingList<RaceColumn, Fleet, Competitor, Boat> {
|
||||
|
||||
@Override
|
||||
public Iterable<Pair<Competitor, Boat>> getCompetitors(RaceColumn raceColumn, Fleet fleet) {
|
||||
// TODO add boat to return value (bug4403)
|
||||
List<Pair<Competitor, Boat>> result = new ArrayList<>();
|
||||
int boatIndex = 0;
|
||||
for (Competitor competitor : raceColumn.getCompetitorsRegisteredInRacelog(fleet)) {
|
||||
result.add(new Pair<Competitor, Boat>(competitor,
|
||||
new BoatImpl("Boat " + (boatIndex + 1), new BoatClassImpl("49er", true), "DE" + boatIndex)));
|
||||
boatIndex++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -29,7 +29,7 @@ public interface RaceDefinition extends NamedWithID {
|
||||
/**
|
||||
* Gets the boat used by the competitor for this race.
|
||||
*/
|
||||
Boat getBoatOfCompetitorById(Serializable competitorID);
|
||||
Boat getBoatOfCompetitor(Competitor competitor);
|
||||
|
||||
/**
|
||||
* The MD5 hash as produced by
|
||||
|
||||
+4
-4
@@ -27,7 +27,7 @@ public class RaceDefinitionImpl extends NamedImpl implements RaceDefinition {
|
||||
private final Course course;
|
||||
private final LinkedHashMap<Serializable, Competitor> competitorsById;
|
||||
private final Set<Competitor> competitors;
|
||||
private final Map<Serializable, Boat> competitorBoats;
|
||||
private final Map<Competitor, Boat> competitorBoats;
|
||||
private final BoatClass boatClass;
|
||||
private final Serializable id;
|
||||
private final RaceCompetitorIdsAsStringWithMD5Hash raceCompetitorsMD5Hash;
|
||||
@@ -65,7 +65,7 @@ public class RaceDefinitionImpl extends NamedImpl implements RaceDefinition {
|
||||
for (Entry<Competitor, Boat> competitorAndBoat : competitorsAndTheirBoats.entrySet()) {
|
||||
Competitor competitor = competitorsById.get(competitorAndBoat.getKey().getId()); // only assign boat if competitor is part of race
|
||||
if (competitor != null && competitorAndBoat.getValue() != null) {
|
||||
competitorBoats.put(competitor.getId(), competitorAndBoat.getValue());
|
||||
competitorBoats.put(competitor, competitorAndBoat.getValue());
|
||||
} else {
|
||||
logger.warning("Trying to set boat "+competitorAndBoat.getValue()+" for competitor "+competitorAndBoat.getKey()+
|
||||
" which is not part of race "+getName()+"'s set of competitors");
|
||||
@@ -111,7 +111,7 @@ public class RaceDefinitionImpl extends NamedImpl implements RaceDefinition {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boat getBoatOfCompetitorById(Serializable competitorID) {
|
||||
return competitorBoats.get(competitorID);
|
||||
public Boat getBoatOfCompetitor(Competitor competitor) {
|
||||
return competitorBoats.get(competitor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,6 +256,11 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFleetsCanRunInParallelToTrue() {
|
||||
RegattaImpl.this.setFleetsCanRunInParallelToTrue();
|
||||
}
|
||||
};
|
||||
this.regattaLikeHelper.addListener(new RegattaLogEventAdditionForwarder(raceColumnListeners));
|
||||
this.raceExecutionOrderCache = new RaceExecutionOrderCache();
|
||||
@@ -856,4 +861,11 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
|
||||
deregisterer.deregister(deregisterer.analyze());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFleetsCanRunInParallelToTrue() {
|
||||
for (Series series : this.series) {
|
||||
series.setIsFleetsCanRunInParallel(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+10
@@ -104,6 +104,11 @@ public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements
|
||||
public RaceColumn getRaceColumnByName(String raceColumnName) {
|
||||
return getRaceColumnByName(raceColumnName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFleetsCanRunInParallelToTrue() {
|
||||
// no need to do anything; a FlexibleLeaderboard only has one (default) fleet
|
||||
}
|
||||
};
|
||||
this.regattaLikeHelper.addListener(new RegattaLogEventAdditionForwarder(getRaceColumnListeners()));
|
||||
this.raceExecutionOrderProvider = new RaceExecutionOrderCache();
|
||||
@@ -381,4 +386,9 @@ public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFleetsCanRunInParallelToTrue() {
|
||||
// no need to do anything because a FlexibleLeaderboard only has one (default) fleet
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -136,4 +136,8 @@ public class RegattaLeaderboardImpl extends AbstractLeaderboardImpl implements R
|
||||
public CompetitorProviderFromRaceColumnsAndRegattaLike getOrCreateCompetitorsProvider() {
|
||||
return getRegatta().getOrCreateCompetitorsProvider();
|
||||
}
|
||||
|
||||
public void setFleetsCanRunInParallelToTrue() {
|
||||
this.getRegattaLike().setFleetsCanRunInParallelToTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,4 +67,6 @@ public interface IsRegattaLike extends Serializable {
|
||||
* @see #getTimeOnTimeFactor(Competitor)
|
||||
*/
|
||||
Duration getTimeOnDistanceAllowancePerNauticalMile(Competitor competitor);
|
||||
|
||||
void setFleetsCanRunInParallelToTrue();
|
||||
}
|
||||
+4
-1
@@ -12,7 +12,10 @@ import com.sap.sse.common.TimePoint;
|
||||
/**
|
||||
* Definition of importers used by SensorDataImportServlet to do the import of a specific file type.
|
||||
*/
|
||||
public interface DoubleVectorFixImporter extends BaseDoubleVectorFixImporter {
|
||||
public interface DoubleVectorFixImporter extends BaseDoubleVectorFixImporter {
|
||||
|
||||
public static final String EXPEDITION_EXTENDED_TYPE = "EXPEDITION_EXTENDED";
|
||||
|
||||
/**
|
||||
* Creates the {@link RegattaLogEvent} for the DeviceMapping.
|
||||
*/
|
||||
|
||||
+3
-1
@@ -30,7 +30,9 @@ import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
|
||||
* @author Fredrik Teschke
|
||||
*
|
||||
*/
|
||||
public interface GPSFixImporter {
|
||||
public interface GPSFixImporter {
|
||||
public static final String EXPEDITION_TYPE = "Expedition";
|
||||
|
||||
String FILE_EXTENSION_PROPERTY = "fileExt";
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
/** Add css rules here for your application. */
|
||||
.clear {
|
||||
clear: both;
|
||||
font-size: 1px;
|
||||
height: 0px;
|
||||
line-height: 0px;
|
||||
margin: -1px 0 0;
|
||||
width: 100%; }
|
||||
|
||||
.cover {
|
||||
left: -1000px;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: -1000px; }
|
||||
|
||||
html {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
background: #fff;
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
line-height: 1;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/** Example rules used by the template application (remove for your app) */
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
color: #777777;
|
||||
margin: 40px 0px 70px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: separate; }
|
||||
|
||||
|
||||
.refreshAndSettings {
|
||||
background: #f2f2f2;
|
||||
border-bottom: 2px solid #fff;
|
||||
border-top: 2px solid #fff;
|
||||
height: 30px; }
|
||||
|
||||
.refreshAndSettings table td {
|
||||
padding: 0 10px 0 0;}
|
||||
|
||||
.refreshAndSettings table table td{
|
||||
padding: 0 0 0 0;}
|
||||
|
||||
input.magnifier{
|
||||
display: block;
|
||||
margin: 3px auto 0 auto !important;
|
||||
}
|
||||
|
||||
body, table td, select, button {
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.errorLabel {
|
||||
color: #FF0000;
|
||||
}
|
||||
|
||||
.abstractChartPanel-importantMessageOfChart {
|
||||
font-family: 'Open Sans',Arial,Verdana,sans-serif;
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
height: 70px;
|
||||
margin: 0 auto;
|
||||
padding: 49px 0 0 80px;
|
||||
width: 300px;
|
||||
color: #7c7c7c;
|
||||
background: url(images/important-message.png) left center no-repeat;
|
||||
}
|
||||
|
||||
.LeaderboardHeader {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
font-size: 18px;
|
||||
color: #fff;
|
||||
margin-top: 22px;
|
||||
}
|
||||
|
||||
.leaderboardHeading {
|
||||
font-size: 16px;
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.gwt-DialogBox {
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-family: 'Open Sans Condensed', sans-serif;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.trackingQuality-circle {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
-moz-border-radius-topleft: 50%;
|
||||
-webkit-border-top-left-radius: 50%;
|
||||
-o-border-top-left-radius: 50%;
|
||||
-ms-border-top-left-radius: 50%;
|
||||
border-top-left-radius: 50%;
|
||||
-moz-border-radius-topright: 50%;
|
||||
-webkit-border-top-right-radius: 50%;
|
||||
-o-border-top-right-radius: 50%;
|
||||
-ms-border-top-right-radius: 50%;
|
||||
border-top-right-radius: 50%;
|
||||
-moz-border-radius-bottomleft: 50%;
|
||||
-webkit-border-bottom-left-radius: 50%;
|
||||
-o-border-bottom-left-radius: 50%;
|
||||
-ms-border-bottom-left-radius: 50%;
|
||||
border-bottom-left-radius: 50%;
|
||||
-moz-border-radius-bottomright: 50%;
|
||||
-webkit-border-bottom-right-radius: 50%;
|
||||
-o-border-bottom-right-radius: 50%;
|
||||
-ms-border-bottom-right-radius: 50%;
|
||||
border-bottom-right-radius: 50%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.circleYellow {
|
||||
background: #fbba00;
|
||||
}
|
||||
|
||||
.circleGreen {
|
||||
background: #8ab54e;
|
||||
}
|
||||
|
||||
.circleRed {
|
||||
background: #f01010;
|
||||
}
|
||||
|
||||
.busyIndicator-Simple {
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
.busyIndicator-Circle {
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<!--[if lt IE 9]>
|
||||
<meta http-equiv="REFRESH" content="0; url=http://www.sapsailing.com/browser-info.html">
|
||||
<![endif]-->
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<title>SAP Sailing Analytics PairingList</title>
|
||||
<meta content='width = device-width, initial-scale = 1.0, user-scalable = yes' name='viewport'>
|
||||
<meta content='yes' name='apple-mobile-web-app-capable'>
|
||||
<meta content='black' name='apple-mobile-web-app-status-bar-style'>
|
||||
<!-- <link href='iphone-splash-screen.png' rel='apple-touch-startup-image'> -->
|
||||
<link href='images/sap-sailing-app-icon.png' rel='apple-touch-icon'>
|
||||
<link rel="shortcut icon" type="image/x-icon" href="images/sap.ico" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/sailing-normalize-3.0.2.cache.css">
|
||||
<link rel="stylesheet" type="text/css" href="/sailing-fontface-1.0.cache.css">
|
||||
<link rel="stylesheet" type="text/css" href="PairingList.css">
|
||||
|
||||
<script type="text/javascript" src="js/jquery-1.5.2.min.js"></script>
|
||||
|
||||
<script type="text/javascript" src="com.sap.sailing.gwt.ui.PairingList/com.sap.sailing.gwt.ui.PairingList.nocache.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe>
|
||||
<!-- RECOMMENDED if your web app will not function without JavaScript enabled -->
|
||||
<noscript>
|
||||
<div style="width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; background-color: white; border: 1px solid red; padding: 4px; font-family: sans-serif">
|
||||
Your web browser must have JavaScript enabled
|
||||
in order for this application to display correctly.
|
||||
</div>
|
||||
</noscript>
|
||||
</body>
|
||||
</html>
|
||||
@@ -61,7 +61,7 @@
|
||||
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-style PRETTY -incremental -workDir "${project_loc:com.sap.sailing.gwt.ui}/.tmp/gwt-work" -war "${project_loc:com.sap.sailing.gwt.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9876 -startupUrl /gwt/Home.html com.sap.sailing.gwt.home.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/EmbeddedMapAndWindChart com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup -startupUrl /gwt/YoutubePopup.html com.sap.sailing.gwt.ui.YoutubePopup -startupUrl /gwt/AutoPlay.html com.sap.sailing.gwt.autoplay.AutoPlay"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-style PRETTY -incremental -workDir "${project_loc:com.sap.sailing.gwt.ui}/.tmp/gwt-work" -war "${project_loc:com.sap.sailing.gwt.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9876 -startupUrl /gwt/Home.html com.sap.sailing.gwt.home.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.PairingList -startupUrl /gwt/PairingList.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/EmbeddedMapAndWindChart com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup -startupUrl /gwt/YoutubePopup.html com.sap.sailing.gwt.ui.YoutubePopup -startupUrl /gwt/AutoPlay.html com.sap.sailing.gwt.autoplay.AutoPlay"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms1024m -Xmx3072m -Dgwt.watchFileChanges=false"/>
|
||||
</launchConfiguration>
|
||||
|
||||
@@ -51,5 +51,8 @@ bin.includes = META-INF/,\
|
||||
com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart/,\
|
||||
Calendar.html,\
|
||||
imprint.json,\
|
||||
licenses/
|
||||
licenses/,\
|
||||
PairingList.css,\
|
||||
PairingList.html,\
|
||||
com.sap.sailing.gwt.ui.PairingList/
|
||||
output.. = WEB-INF/classes/
|
||||
|
||||
@@ -142,6 +142,7 @@
|
||||
<module>com.sap.sailing.gwt.ui.VideoPopup</module>
|
||||
<module>com.sap.sailing.gwt.ui.YoutubePopup</module>
|
||||
<module>com.sap.sailing.gwt.ui.Simulator</module>
|
||||
<module>com.sap.sailing.gwt.ui.PairingList</module>
|
||||
<module>com.sap.sailing.gwt.regattaoverview.RegattaOverview</module>
|
||||
</modules>
|
||||
<!-- uncomment the following for PRETTY-printed, non-obfuscated output
|
||||
|
||||
+1
-1
@@ -900,7 +900,7 @@ public class RegattaRaceStatesComponent extends AbstractCompositeComponent<Regat
|
||||
entryDTO.raceInfo.raceIdentifier.getRaceName(), entryDTO.leaderboardName, null, null, null);
|
||||
RaceBoardPerspectiveOwnSettings perspectiveOwnSettings = RaceBoardPerspectiveOwnSettings
|
||||
.createDefaultWithCanReplayDuringLiveRaces(true);
|
||||
;
|
||||
|
||||
PerspectiveCompositeSettings<RaceBoardPerspectiveOwnSettings> settings = new PerspectiveCompositeSettings<>(
|
||||
perspectiveOwnSettings, Collections.emptyMap());
|
||||
|
||||
|
||||
+14
@@ -1,6 +1,7 @@
|
||||
package com.sap.sailing.gwt.settings.client;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.sap.sailing.gwt.settings.client.leaderboard.LeaderboardContextDefinition;
|
||||
import com.sap.sailing.gwt.settings.client.leaderboard.LeaderboardPerspectiveOwnSettings;
|
||||
@@ -45,6 +46,19 @@ public class EntryPointWithSettingsLinkFactory extends AbstractEntryPointWithSet
|
||||
perspectiveOwnSettings, Collections.emptyMap());
|
||||
return linkWithSettingsGenerator.createUrl(settings);
|
||||
}
|
||||
|
||||
public static String createRaceBoardLinkWithDefaultSettings(UUID eventId, String leaderboardName, String leaderboardGroupName, String regattaName, String raceName) {
|
||||
return createRaceBoardLinkWithDefaultSettings(eventId, leaderboardName, leaderboardGroupName, regattaName, raceName, null);
|
||||
}
|
||||
|
||||
public static String createRaceBoardLinkWithDefaultSettings(UUID eventId, String leaderboardName, String leaderboardGroupName, String regattaName, String raceName, String mode) {
|
||||
RaceboardContextDefinition raceboardContext = new RaceboardContextDefinition(regattaName,
|
||||
raceName, leaderboardName, leaderboardGroupName, eventId, mode);
|
||||
RaceBoardPerspectiveOwnSettings perspectiveOwnSettings = new RaceBoardPerspectiveOwnSettings();
|
||||
PerspectiveCompositeSettings<RaceBoardPerspectiveOwnSettings> settings = new PerspectiveCompositeSettings<>(
|
||||
perspectiveOwnSettings, Collections.emptyMap());
|
||||
return EntryPointWithSettingsLinkFactory.createRaceBoardLink(raceboardContext, settings);
|
||||
}
|
||||
|
||||
public static String createRaceBoardLink(RaceboardContextDefinition ctx,
|
||||
PerspectiveCompositeSettings<RaceBoardPerspectiveOwnSettings> settings) {
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.7.0//EN" "http://gwtproject.org/doctype/2.7.0/gwt-module.dtd">
|
||||
<module>
|
||||
<inherits name='com.google.gwt.user.User'/>
|
||||
<inherits name='com.sap.sse.security.ui.Settings'/>
|
||||
<inherits name='com.sap.sailing.gwt.settings.Settings'/>
|
||||
|
||||
<source path="pairinglist"/>
|
||||
|
||||
</module>
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
|
||||
|
||||
public abstract class AbstractChooseNameDenoteEventDialog<T> extends DataEntryDialog<T> {
|
||||
protected StringMessages stringMessages;
|
||||
|
||||
public AbstractChooseNameDenoteEventDialog(String title, StringMessages stringMessages,
|
||||
Validator<T> validator, DialogCallback<T> callback) {
|
||||
|
||||
super(title, null, stringMessages.ok(), stringMessages.cancel(), validator, callback);
|
||||
this.stringMessages = stringMessages;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Widget getAdditionalWidget() {
|
||||
final VerticalPanel panel = new VerticalPanel();
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected T getResult() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
|
||||
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
|
||||
|
||||
public abstract class AbstractPairingListCreationSetupDialog<T> extends DataEntryDialog<T> {
|
||||
|
||||
protected StringMessages stringMessages;
|
||||
protected final StrippedLeaderboardDTO leaderboardDTO;
|
||||
|
||||
public AbstractPairingListCreationSetupDialog(StrippedLeaderboardDTO leaderboardDTO, String title, StringMessages stringMessages,
|
||||
Validator<T> validator, DialogCallback<T> callback) {
|
||||
|
||||
super(title, null, stringMessages.ok(), stringMessages.cancel(), validator, callback);
|
||||
this.stringMessages = stringMessages;
|
||||
this.leaderboardDTO = leaderboardDTO;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Widget getAdditionalWidget() {
|
||||
final VerticalPanel panel = new VerticalPanel();
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected T getResult() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import com.sap.sailing.domain.common.dto.PairingListTemplateDTO;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.gwt.client.dialog.DataEntryDialog.Validator;
|
||||
|
||||
public class AbstractPairingListParameterValidator implements Validator<PairingListTemplateDTO> {
|
||||
protected final StringMessages stringMessages;
|
||||
|
||||
public AbstractPairingListParameterValidator(StringMessages stringMessages) {
|
||||
this.stringMessages = stringMessages;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getErrorMessage(PairingListTemplateDTO valueToValidate) {
|
||||
String errorMessage = null;
|
||||
|
||||
if (valueToValidate.getCompetitorCount() < valueToValidate.getGroupCount()) {
|
||||
errorMessage = stringMessages.invalidCompetitorCount();
|
||||
} else if (valueToValidate.getFlightMultiplier() < 1) {
|
||||
errorMessage = stringMessages.invalidFlightMultiplier();
|
||||
} else if (valueToValidate.getFlightCount() % valueToValidate.getFlightMultiplier() != 0
|
||||
&& valueToValidate.getFlightMultiplier() > 0) {
|
||||
errorMessage = stringMessages.flightsMustBeAMultipleOfMultiplier();
|
||||
} else if (Util.size(valueToValidate.getSelectedFlightNames()) < 1) {
|
||||
errorMessage = stringMessages.invalidSeriesSelection();
|
||||
}
|
||||
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
}
|
||||
+220
@@ -0,0 +1,220 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.CaptionPanel;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.SimplePanel;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.google.gwt.view.client.SelectionChangeEvent;
|
||||
import com.google.gwt.view.client.SingleSelectionModel;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.MappableToDevice;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.shared.DeviceIdentifierDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.DeviceMappingDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.MarkDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.TrackFileImportDeviceIdentifierDTO;
|
||||
import com.sap.sse.gwt.client.ErrorReporter;
|
||||
import com.sap.sse.gwt.client.celltable.RefreshableSingleSelectionModel;
|
||||
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
|
||||
|
||||
public class AbstractRegattaLogFixesAddMappingsDialog extends DataEntryDialog<Collection<DeviceMappingDTO>> {
|
||||
private String leaderboardName;
|
||||
private final SimplePanel importWidgetHolder;
|
||||
protected final TrackFileImportDeviceIdentifierTableWrapper deviceIdTable;
|
||||
protected final CompetitorTableWrapper<RefreshableSingleSelectionModel<CompetitorDTO>> competitorTable;
|
||||
protected final MarkTableWrapper<RefreshableSingleSelectionModel<MarkDTO>> markTable;
|
||||
private final StringMessages stringMessages;
|
||||
|
||||
private final Map<TrackFileImportDeviceIdentifierDTO, MappableToDevice> mappings = new HashMap<>();
|
||||
|
||||
private TrackFileImportDeviceIdentifierDTO deviceToSelect;
|
||||
private CompetitorDTO compToSelect;
|
||||
private MarkDTO markToSelect;
|
||||
private boolean inInstableTransitionState = false;
|
||||
|
||||
public AbstractRegattaLogFixesAddMappingsDialog(SailingServiceAsync sailingService,
|
||||
final ErrorReporter errorReporter, final StringMessages stringMessages, String leaderboardName,
|
||||
DialogCallback<Collection<DeviceMappingDTO>> callback) {
|
||||
super(stringMessages.add(stringMessages.deviceMappings()), stringMessages.add(stringMessages.deviceMappings()),
|
||||
stringMessages.add(), stringMessages.cancel(),
|
||||
new DataEntryDialog.Validator<Collection<DeviceMappingDTO>>() {
|
||||
@Override
|
||||
public String getErrorMessage(Collection<DeviceMappingDTO> valueToValidate) {
|
||||
if (!valueToValidate.isEmpty()){
|
||||
return null;
|
||||
} else {
|
||||
return stringMessages.pleaseCreateAtLeastOneMappingBy();
|
||||
}
|
||||
}
|
||||
}, true, callback);
|
||||
this.stringMessages = stringMessages;
|
||||
deviceIdTable = new TrackFileImportDeviceIdentifierTableWrapper(sailingService, stringMessages, errorReporter);
|
||||
importWidgetHolder = new SimplePanel();
|
||||
deviceIdTable.getSelectionModel().addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
|
||||
@Override
|
||||
public void onSelectionChange(SelectionChangeEvent event) {
|
||||
deviceSelectionChanged(deviceIdTable.getSelectionModel().getSelectedObject());
|
||||
}
|
||||
});
|
||||
competitorTable = new CompetitorTableWrapper<>(sailingService, stringMessages, errorReporter, /* multiSelection */
|
||||
false, true);
|
||||
markTable = new MarkTableWrapper<RefreshableSingleSelectionModel<MarkDTO>>(
|
||||
/* multiSelection */false, sailingService, stringMessages, errorReporter);
|
||||
|
||||
competitorTable.getSelectionModel().addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
|
||||
@Override
|
||||
public void onSelectionChange(SelectionChangeEvent event) {
|
||||
mappedToSelectionChanged(competitorTable.getSelectionModel().getSelectedObject());
|
||||
}
|
||||
});
|
||||
markTable.getSelectionModel().addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
|
||||
@Override
|
||||
public void onSelectionChange(SelectionChangeEvent event) {
|
||||
mappedToSelectionChanged(markTable.getSelectionModel().getSelectedObject());
|
||||
}
|
||||
});
|
||||
|
||||
this.leaderboardName = leaderboardName;
|
||||
|
||||
getCompetitorRegistrations(sailingService, errorReporter);
|
||||
getMarks(sailingService, errorReporter);
|
||||
}
|
||||
|
||||
void getMarks(SailingServiceAsync sailingService, final ErrorReporter errorReporter) {
|
||||
sailingService.getMarksInRegattaLog(leaderboardName, new AsyncCallback<Iterable<MarkDTO>>() {
|
||||
@Override
|
||||
public void onSuccess(Iterable<MarkDTO> result) {
|
||||
markTable.refresh(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError("Could not load marks: " + caught.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void getCompetitorRegistrations(SailingServiceAsync sailingService, final ErrorReporter errorReporter) {
|
||||
sailingService.getCompetitorRegistrationsForLeaderboard(leaderboardName,
|
||||
new AsyncCallback<Collection<CompetitorDTO>>() {
|
||||
@Override
|
||||
public void onSuccess(Collection<CompetitorDTO> result) {
|
||||
competitorTable.refreshCompetitorList(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError("Could not load competitors: " + caught.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static <T> void selectOrClear(SingleSelectionModel<T> selectionModel, T object) {
|
||||
if (object == null) {
|
||||
selectionModel.clear();
|
||||
} else {
|
||||
selectionModel.setSelected(object, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid programmatic deselections that re-trigger the selection listeners and lead to a loop.
|
||||
*/
|
||||
private void select() {
|
||||
if (inInstableTransitionState) {
|
||||
if (deviceIdTable.getSelectionModel().getSelectedObject() == deviceToSelect
|
||||
&& competitorTable.getSelectionModel().getSelectedObject() == compToSelect
|
||||
&& markTable.getSelectionModel().getSelectedObject() == markToSelect) {
|
||||
inInstableTransitionState = false;
|
||||
}
|
||||
} else {
|
||||
inInstableTransitionState = true;
|
||||
selectOrClear(deviceIdTable.getSelectionModel(), deviceToSelect);
|
||||
selectOrClear(competitorTable.getSelectionModel(), compToSelect);
|
||||
selectOrClear(markTable.getSelectionModel(), markToSelect);
|
||||
}
|
||||
}
|
||||
|
||||
private void mappedToSelectionChanged(MappableToDevice mappedTo) {
|
||||
if (!inInstableTransitionState) {
|
||||
TrackFileImportDeviceIdentifierDTO device = deviceIdTable.getSelectionModel().getSelectedObject();
|
||||
if (device != null) {
|
||||
mappings.put(device, mappedTo);
|
||||
}
|
||||
|
||||
if (mappedTo instanceof CompetitorDTO) {
|
||||
markToSelect = null;
|
||||
compToSelect = (CompetitorDTO) mappedTo;
|
||||
} else {
|
||||
compToSelect = null;
|
||||
markToSelect = (MarkDTO) mappedTo;
|
||||
}
|
||||
}
|
||||
select();
|
||||
validateAndUpdate();
|
||||
}
|
||||
|
||||
private void deviceSelectionChanged(TrackFileImportDeviceIdentifierDTO deviceId) {
|
||||
if (!inInstableTransitionState) {
|
||||
deviceToSelect = deviceId;
|
||||
compToSelect = null;
|
||||
markToSelect = null;
|
||||
|
||||
if (deviceId != null) {
|
||||
MappableToDevice mappedTo = mappings.get(deviceId);
|
||||
if (mappedTo instanceof CompetitorDTO) {
|
||||
compToSelect = (CompetitorDTO) mappedTo;
|
||||
} else if (mappedTo instanceof MarkDTO) {
|
||||
markToSelect = (MarkDTO) mappedTo;
|
||||
}
|
||||
}
|
||||
}
|
||||
select();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Widget getAdditionalWidget() {
|
||||
HorizontalPanel panel = new HorizontalPanel();
|
||||
VerticalPanel leftPanel = new VerticalPanel();
|
||||
VerticalPanel tablesPanel = new VerticalPanel();
|
||||
CaptionPanel marksPanel = new CaptionPanel(stringMessages.mark());
|
||||
CaptionPanel competitorsPanel = new CaptionPanel(stringMessages.competitor());
|
||||
|
||||
leftPanel.add(importWidgetHolder);
|
||||
leftPanel.add(deviceIdTable);
|
||||
panel.add(leftPanel);
|
||||
panel.add(tablesPanel);
|
||||
tablesPanel.add(marksPanel);
|
||||
tablesPanel.add(competitorsPanel);
|
||||
|
||||
marksPanel.setContentWidget(markTable.asWidget());
|
||||
competitorsPanel.setContentWidget(competitorTable.asWidget());
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<DeviceMappingDTO> getResult() {
|
||||
List<DeviceMappingDTO> result = new ArrayList<>();
|
||||
for (TrackFileImportDeviceIdentifierDTO device : mappings.keySet()) {
|
||||
DeviceIdentifierDTO deviceIdDto = new DeviceIdentifierDTO("FILE", device.uuidAsString);
|
||||
MappableToDevice mappedTo = mappings.get(device);
|
||||
DeviceMappingDTO mapping = new DeviceMappingDTO(deviceIdDto, device.from, device.to, mappedTo, null);
|
||||
result.add(mapping);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void setImportWidget(Widget importWidget) {
|
||||
importWidgetHolder.setWidget(importWidget);
|
||||
}
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.CaptionPanel;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.SimplePanel;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.google.gwt.view.client.SelectionChangeEvent;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.MappableToDevice;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.shared.DeviceIdentifierDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.TrackFileImportDeviceIdentifierDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.TypedDeviceMappingDTO;
|
||||
import com.sap.sse.gwt.client.ErrorReporter;
|
||||
import com.sap.sse.gwt.client.celltable.RefreshableSingleSelectionModel;
|
||||
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
|
||||
|
||||
public abstract class AbstractRegattaLogSensorDataAddMappingsDialog extends DataEntryDialog<Collection<TypedDeviceMappingDTO>> {
|
||||
private final String leaderboardName;
|
||||
private final SimplePanel importWidgetHolder;
|
||||
protected final TrackFileImportDeviceIdentifierTableWrapper deviceIdTable;
|
||||
protected final CompetitorTableWrapper<RefreshableSingleSelectionModel<CompetitorDTO>> competitorTable;
|
||||
private final StringMessages stringMessages;
|
||||
|
||||
public AbstractRegattaLogSensorDataAddMappingsDialog(SailingServiceAsync sailingService,
|
||||
final ErrorReporter errorReporter, final StringMessages stringMessages, String leaderboardName,
|
||||
DialogCallback<Collection<TypedDeviceMappingDTO>> callback) {
|
||||
super(stringMessages.add(stringMessages.deviceMappings()), stringMessages.add(stringMessages.deviceMappings()),
|
||||
stringMessages.add(), stringMessages.cancel(),
|
||||
new DataEntryDialog.Validator<Collection<TypedDeviceMappingDTO>>() {
|
||||
@Override
|
||||
public String getErrorMessage(Collection<TypedDeviceMappingDTO> valueToValidate) {
|
||||
return valueToValidate.isEmpty() ? stringMessages.pleaseCreateAtLeastOneMappingForCompetitor() : null;
|
||||
}
|
||||
}, true, callback);
|
||||
this.stringMessages = stringMessages;
|
||||
deviceIdTable = new TrackFileImportDeviceIdentifierTableWrapper(sailingService, stringMessages, errorReporter);
|
||||
deviceIdTable.removeTrackNameColumn();
|
||||
|
||||
importWidgetHolder = new SimplePanel();
|
||||
deviceIdTable.getSelectionModel().addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
|
||||
@Override
|
||||
public void onSelectionChange(SelectionChangeEvent event) {
|
||||
CompetitorDTO mappedComp = deviceIdTable.getMappedCompetitorForCurrentSelection();
|
||||
if (mappedComp != null) {
|
||||
competitorTable.getSelectionModel().setSelected(mappedComp, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
competitorTable = new CompetitorTableWrapper<>(sailingService, stringMessages, errorReporter,
|
||||
/* multiSelection */ false, /* enablePager */ true);
|
||||
competitorTable.getSelectionModel().addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
|
||||
@Override
|
||||
public void onSelectionChange(SelectionChangeEvent event) {
|
||||
deviceIdTable.didSelectCompetitorForMapping(competitorTable.getSelectionModel().getSelectedObject());
|
||||
validateAndUpdate();
|
||||
}
|
||||
});
|
||||
|
||||
this.leaderboardName = leaderboardName;
|
||||
|
||||
getCompetitorRegistrations(sailingService, errorReporter);
|
||||
}
|
||||
|
||||
void getCompetitorRegistrations(SailingServiceAsync sailingService, final ErrorReporter errorReporter) {
|
||||
sailingService.getCompetitorRegistrationsForLeaderboard(leaderboardName,
|
||||
new AsyncCallback<Collection<CompetitorDTO>>() {
|
||||
@Override
|
||||
public void onSuccess(Collection<CompetitorDTO> result) {
|
||||
competitorTable.refreshCompetitorList(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError("Could not load competitors: " + caught.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Widget getAdditionalWidget() {
|
||||
HorizontalPanel panel = new HorizontalPanel();
|
||||
VerticalPanel leftPanel = new VerticalPanel();
|
||||
VerticalPanel tablesPanel = new VerticalPanel();
|
||||
CaptionPanel competitorsPanel = new CaptionPanel(stringMessages.competitor());
|
||||
leftPanel.add(importWidgetHolder);
|
||||
leftPanel.add(deviceIdTable);
|
||||
panel.add(leftPanel);
|
||||
panel.add(tablesPanel);
|
||||
tablesPanel.add(competitorsPanel);
|
||||
competitorsPanel.setContentWidget(competitorTable.asWidget());
|
||||
return panel;
|
||||
}
|
||||
|
||||
protected abstract String getSelectedImporterType();
|
||||
|
||||
@Override
|
||||
protected Collection<TypedDeviceMappingDTO> getResult() {
|
||||
List<TypedDeviceMappingDTO> result = new ArrayList<>();
|
||||
String dataType = getSelectedImporterType();
|
||||
for (TrackFileImportDeviceIdentifierDTO device : deviceIdTable.getMappings().keySet()) {
|
||||
DeviceIdentifierDTO deviceIdDto = new DeviceIdentifierDTO("FILE", device.uuidAsString);
|
||||
MappableToDevice mappedTo = deviceIdTable.getMappings().get(device);
|
||||
result.add(new TypedDeviceMappingDTO(deviceIdDto, device.from, device.to, mappedTo, null, dataType));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void setImportWidget(Widget importWidget) {
|
||||
importWidgetHolder.setWidget(importWidget);
|
||||
}
|
||||
}
|
||||
+5
-3
@@ -89,7 +89,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
|
||||
regattasDisplayers = new HashSet<>();
|
||||
leaderboardsDisplayers = new HashSet<>();
|
||||
leaderboardGroupsDisplayers = new HashSet<>();
|
||||
|
||||
|
||||
final EventManagementPanel eventManagementPanel = new EventManagementPanel(sailingService, this, this, getStringMessages(), panel);
|
||||
eventManagementPanel.ensureDebugId("EventManagement");
|
||||
panel.addToVerticalTabPanel(new DefaultRefreshableAdminConsolePanel<EventManagementPanel>(eventManagementPanel) {
|
||||
@@ -100,6 +100,8 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
|
||||
}
|
||||
}, getStringMessages().events(), Permission.MANAGE_EVENTS);
|
||||
leaderboardGroupsDisplayers.add(eventManagementPanel);
|
||||
|
||||
/* REGATTAS */
|
||||
|
||||
RegattaManagementPanel regattaManagementPanel = new RegattaManagementPanel(
|
||||
sailingService, this, getStringMessages(), this, eventManagementPanel);
|
||||
@@ -146,7 +148,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
|
||||
regattasDisplayers.add(leaderboardGroupConfigPanel);
|
||||
leaderboardGroupsDisplayers.add(leaderboardGroupConfigPanel);
|
||||
leaderboardsDisplayers.add(leaderboardGroupConfigPanel);
|
||||
|
||||
|
||||
/* RACES */
|
||||
|
||||
final HorizontalTabLayoutPanel racesTabPanel = panel.addVerticalTab(getStringMessages().trackedRaces(), "RacesPanel");
|
||||
@@ -208,7 +210,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
|
||||
panel.addToTabPanel(connectorsTabPanel, new DefaultRefreshableAdminConsolePanel<TracTracEventManagementPanel>(tractracEventManagementPanel),
|
||||
getStringMessages().tracTracEvents(), Permission.MANAGE_TRACKED_RACES);
|
||||
regattasDisplayers.add(tractracEventManagementPanel);
|
||||
|
||||
|
||||
SwissTimingReplayConnectorPanel swissTimingReplayConnectorPanel = new SwissTimingReplayConnectorPanel(
|
||||
sailingService, this, this, getStringMessages());
|
||||
panel.addToTabPanel(connectorsTabPanel, new DefaultRefreshableAdminConsolePanel<SwissTimingReplayConnectorPanel>(swissTimingReplayConnectorPanel),
|
||||
|
||||
+6
@@ -49,6 +49,12 @@ interface AdminConsoleResources extends ClientBundle {
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/clock.png")
|
||||
ImageResource clockIcon();
|
||||
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/pairinglist.png")
|
||||
ImageResource pairingList();
|
||||
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/print_pairinglist.png")
|
||||
ImageResource printPairingList();
|
||||
|
||||
// Smaller variant of RegattaRaceStatesFlagsResources.flagBlue to solve layouting issues
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/blue_small.png")
|
||||
ImageResource blueSmall();
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import com.google.gwt.user.client.ui.DialogBox;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.sap.sse.gwt.client.controls.busyindicator.SimpleBusyIndicator;
|
||||
|
||||
public class BusyDialog extends DialogBox {
|
||||
|
||||
private final FlowPanel mainPanel;
|
||||
private final SimpleBusyIndicator busyIndicator;
|
||||
|
||||
public BusyDialog() {
|
||||
this("");
|
||||
}
|
||||
|
||||
public BusyDialog(String title) {
|
||||
busyIndicator = new SimpleBusyIndicator(true, 1.5f);
|
||||
mainPanel = new FlowPanel();
|
||||
mainPanel.setWidth("100%");
|
||||
mainPanel.setPixelSize(50, 50);
|
||||
mainPanel.add(busyIndicator);
|
||||
center();
|
||||
setTitle(title);
|
||||
setModal(true);
|
||||
setGlassEnabled(true);
|
||||
setWidget(mainPanel);
|
||||
}
|
||||
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import com.google.gwt.event.dom.client.ChangeEvent;
|
||||
import com.google.gwt.event.dom.client.ChangeHandler;
|
||||
import com.google.gwt.event.logical.shared.ValueChangeEvent;
|
||||
import com.google.gwt.event.logical.shared.ValueChangeHandler;
|
||||
import com.google.gwt.user.client.ui.Grid;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.RadioButton;
|
||||
import com.google.gwt.user.client.ui.TextBox;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
|
||||
|
||||
public class ChooseNameDenoteEventDialog extends AbstractChooseNameDenoteEventDialog<String> {
|
||||
private final RadioButton defaultName;
|
||||
private final RadioButton ownPrefix;
|
||||
private final TextBox name;
|
||||
private final Label example;
|
||||
private final StrippedLeaderboardDTO strippedLeaderboardDTO;
|
||||
|
||||
public ChooseNameDenoteEventDialog(StringMessages stringMessages,StrippedLeaderboardDTO leaderboard,DialogCallback<String> callback){
|
||||
super(stringMessages.chooseAName(), stringMessages, null, callback);
|
||||
final String NAME_TYPE_RADIO_BUTTON_GROUP = "namegroup";
|
||||
this.strippedLeaderboardDTO=leaderboard;
|
||||
this.defaultName=createRadioButton(NAME_TYPE_RADIO_BUTTON_GROUP, stringMessages.defaultName());
|
||||
this.defaultName.setValue(true);
|
||||
this.ownPrefix=createRadioButton(NAME_TYPE_RADIO_BUTTON_GROUP, stringMessages.ownPrefix());
|
||||
this.name=createTextBox("R", 5);
|
||||
this.name.setEnabled(false);
|
||||
this.example=new Label();
|
||||
this.updateExample();
|
||||
this.ownPrefix.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
|
||||
@Override
|
||||
public void onValueChange(ValueChangeEvent<Boolean> event) {
|
||||
defaultName.setValue(false);
|
||||
name.setEnabled(true);
|
||||
updateExample();
|
||||
}
|
||||
});
|
||||
this.defaultName.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
|
||||
@Override
|
||||
public void onValueChange(ValueChangeEvent<Boolean> event) {
|
||||
name.setEnabled(false);
|
||||
ownPrefix.setValue(false);
|
||||
updateExample();
|
||||
}
|
||||
});
|
||||
this.name.addChangeHandler(new ChangeHandler() {
|
||||
@Override
|
||||
public void onChange(ChangeEvent event) {
|
||||
updateExample();
|
||||
}
|
||||
});
|
||||
this.getOkButton().setFocus(true);
|
||||
}
|
||||
|
||||
protected void updateExample() {
|
||||
if (this.defaultName.getValue()) {
|
||||
this.example.setText(stringMessages.exampleTextForName() + " " + strippedLeaderboardDTO.getName() + " "
|
||||
+ strippedLeaderboardDTO.getRaceList().get(0).getName() + " "
|
||||
+ strippedLeaderboardDTO.getRaceList().get(0).getFleets().get(0).getName());
|
||||
} else if (this.ownPrefix.getValue()) {
|
||||
this.example.setText(stringMessages.exampleTextForName() + " " + name.getValue() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Widget getAdditionalWidget(){
|
||||
final VerticalPanel panel = new VerticalPanel();
|
||||
Grid formGrid = new Grid(3,2);
|
||||
formGrid.setWidget(0, 0, defaultName);
|
||||
formGrid.setWidget(1, 0, ownPrefix);
|
||||
formGrid.setWidget(1, 1, name);
|
||||
formGrid.setWidget(2, 0, example);
|
||||
panel.add(formGrid);
|
||||
return panel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getResult() {
|
||||
final String result;
|
||||
if (this.ownPrefix.getValue()) {
|
||||
result = name.getValue();
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+275
@@ -0,0 +1,275 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.shared.DeviceMappingDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.EventDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.TrackFileImportDeviceIdentifierDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.TypedDeviceMappingDTO;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.Util.Triple;
|
||||
import com.sap.sse.gwt.client.ErrorReporter;
|
||||
import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback;
|
||||
|
||||
public class ExpeditionAllInOneAfterImportHandler {
|
||||
|
||||
private final SailingServiceAsync sailingService;
|
||||
private final ErrorReporter errorReporter;
|
||||
private final StringMessages stringMessages;
|
||||
private final RegattaNameAndRaceName regattaAndRaceIdentifier;
|
||||
private final String leaderboardGroupName;
|
||||
private final String raceColumnName;
|
||||
private final String fleetName;
|
||||
protected EventDTO event;
|
||||
private RegattaDTO regatta;
|
||||
private StrippedLeaderboardDTO leaderboard;
|
||||
private List<TrackFileImportDeviceIdentifierDTO> gpsFixesDeviceIDs;
|
||||
private List<TrackFileImportDeviceIdentifierDTO> sensorFixesDeviceIDs;
|
||||
private final String sensorImporterType;
|
||||
|
||||
public ExpeditionAllInOneAfterImportHandler(UUID eventId, String regattaName, String leaderboardName,
|
||||
String leaderboardGroupName, String raceName, String raceColumnName, String fleetName,
|
||||
List<String> gpsDeviceIds, List<String> sensorDeviceIds, String sensorImporterType,
|
||||
final SailingServiceAsync sailingService, final ErrorReporter errorReporter,
|
||||
final StringMessages stringMessages) {
|
||||
this.leaderboardGroupName = leaderboardGroupName;
|
||||
this.raceColumnName = raceColumnName;
|
||||
this.fleetName = fleetName;
|
||||
this.sensorImporterType = sensorImporterType;
|
||||
this.sailingService = sailingService;
|
||||
this.errorReporter = errorReporter;
|
||||
this.stringMessages = stringMessages;
|
||||
this.regattaAndRaceIdentifier = new RegattaNameAndRaceName(regattaName, raceName);
|
||||
|
||||
sailingService.getEventById(eventId, false, new DataLoadingCallback<EventDTO>() {
|
||||
@Override
|
||||
public void onSuccess(EventDTO result) {
|
||||
event = result;
|
||||
sailingService.getRegattaByName(regattaName, new DataLoadingCallback<RegattaDTO>() {
|
||||
@Override
|
||||
public void onSuccess(RegattaDTO result) {
|
||||
regatta = result;
|
||||
sailingService.getLeaderboard(leaderboardName,
|
||||
new DataLoadingCallback<StrippedLeaderboardDTO>() {
|
||||
@Override
|
||||
public void onSuccess(StrippedLeaderboardDTO result) {
|
||||
leaderboard = result;
|
||||
sailingService.getTrackFileImportDeviceIds(gpsDeviceIds,
|
||||
new DataLoadingCallback<List<TrackFileImportDeviceIdentifierDTO>>() {
|
||||
@Override
|
||||
public void onSuccess(List<TrackFileImportDeviceIdentifierDTO> result) {
|
||||
gpsFixesDeviceIDs = result;
|
||||
sailingService.getTrackFileImportDeviceIds(sensorDeviceIds,
|
||||
new DataLoadingCallback<List<TrackFileImportDeviceIdentifierDTO>>() {
|
||||
@Override
|
||||
public void onSuccess(List<TrackFileImportDeviceIdentifierDTO> result) {
|
||||
sensorFixesDeviceIDs = result;
|
||||
showCompetitorRegistration();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showCompetitorRegistration() {
|
||||
new RegattaLogCompetitorRegistrationDialog(regatta.boatClass == null ? null : regatta.boatClass.getName(),
|
||||
sailingService, stringMessages, errorReporter, true, leaderboard.getName(),
|
||||
new CancelImportDialogCallback<Set<CompetitorDTO>>() {
|
||||
@Override
|
||||
public void ok(final Set<CompetitorDTO> competitors) {
|
||||
if (competitors.isEmpty()) {
|
||||
Window.alert(stringMessages.importCanceledNoCompetitorAdded());
|
||||
} else {
|
||||
sailingService.setCompetitorRegistrationsInRegattaLog(leaderboard.getName(),
|
||||
competitors, new AsyncCallback<Void>() {
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
mapCompetitorsToGPSFixDeviceIds(competitors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError("Failed to register competitors!");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
|
||||
private void mapCompetitorsToGPSFixDeviceIds(final Set<CompetitorDTO> mappedCompetitors) {
|
||||
if (gpsFixesDeviceIDs.size() == 1 && mappedCompetitors.size() == 1) {
|
||||
// If there is exactly one device and one Competitor, the mapping is automatically added without user interaction
|
||||
final TrackFileImportDeviceIdentifierDTO deviceIdentifierDTO = gpsFixesDeviceIDs.iterator().next();
|
||||
final CompetitorDTO competitor = mappedCompetitors.iterator().next();
|
||||
saveCompetitorGPSMapping(mappedCompetitors, Collections.singleton(new DeviceMappingDTO(deviceIdentifierDTO, deviceIdentifierDTO.from, deviceIdentifierDTO.to, competitor, null)));
|
||||
} else {
|
||||
new RegattaLogFixesAddMappingsDialog(sailingService, errorReporter, stringMessages,
|
||||
leaderboard.getName(), gpsFixesDeviceIDs,
|
||||
new CancelImportDialogCallback<Collection<DeviceMappingDTO>>() {
|
||||
|
||||
@Override
|
||||
public void ok(Collection<DeviceMappingDTO> mappings) {
|
||||
saveCompetitorGPSMapping(mappedCompetitors, mappings);
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void saveCompetitorGPSMapping(final Set<CompetitorDTO> mappedCompetitors, final Collection<DeviceMappingDTO> mappings) {
|
||||
new AddDeviceMappingsToRegattaLog(leaderboard.getName(), mappings, () -> {
|
||||
mapCompetitorsToSensorFixDeviceIds(mappedCompetitors);
|
||||
});
|
||||
}
|
||||
|
||||
private final void mapCompetitorsToSensorFixDeviceIds(final Set<CompetitorDTO> mappedCompetitors) {
|
||||
if (sensorFixesDeviceIDs.size() == 1 && mappedCompetitors.size() == 1) {
|
||||
// If there is exactly one device and one Competitor, the mapping is automatically added without user interaction
|
||||
final TrackFileImportDeviceIdentifierDTO deviceIdentifierDTO = sensorFixesDeviceIDs.iterator().next();
|
||||
final CompetitorDTO competitor = mappedCompetitors.iterator().next();
|
||||
saveCompetitorSensorFixMapping(Collections.singleton(new TypedDeviceMappingDTO(deviceIdentifierDTO, deviceIdentifierDTO.from, deviceIdentifierDTO.to, competitor, null, sensorImporterType)));
|
||||
} else if (sensorFixesDeviceIDs.size() > 0) {
|
||||
new RegattaLogSensorDataAddMappingsDialog(sailingService, errorReporter, stringMessages, leaderboard.getName(),
|
||||
sensorFixesDeviceIDs, sensorImporterType,
|
||||
new CancelImportDialogCallback<Collection<TypedDeviceMappingDTO>>() {
|
||||
|
||||
@Override
|
||||
public void ok(Collection<TypedDeviceMappingDTO> mappings) {
|
||||
saveCompetitorSensorFixMapping(mappings);
|
||||
}
|
||||
}).show();
|
||||
} else {
|
||||
// there can be zero sensor fix devices -> skipping the mapping step
|
||||
continueWithMappedDevices();
|
||||
}
|
||||
}
|
||||
|
||||
private void saveCompetitorSensorFixMapping(final Collection<TypedDeviceMappingDTO> mappings) {
|
||||
new AddTypedDeviceMappingsToRegattaLog(leaderboard.getName(), mappings, () -> {
|
||||
continueWithMappedDevices();
|
||||
});
|
||||
}
|
||||
|
||||
private final void continueWithMappedDevices() {
|
||||
List<RegattaNameAndRaceName> racesToStopAndStartTrackingFor = new ArrayList<>();
|
||||
racesToStopAndStartTrackingFor.add(regattaAndRaceIdentifier);
|
||||
sailingService.removeAndUntrackRaces(racesToStopAndStartTrackingFor, new AsyncCallback<Void>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError("Failed to track race after import!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
final List<Triple<String, String, String>> leaderboardRaceColumnFleetNames = new ArrayList<>();
|
||||
leaderboardRaceColumnFleetNames.add(new Triple<>(leaderboard.name, raceColumnName, fleetName));
|
||||
sailingService.startRaceLogTracking(leaderboardRaceColumnFleetNames, /* trackWind */ true,
|
||||
/* TODO correctWindByDeclination */ true, new AsyncCallback<Void>() {
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
new ExpeditionAllInOneImportResultDialog(event.id, regatta.getName(),
|
||||
regattaAndRaceIdentifier.getRaceName(), leaderboard.getName(),
|
||||
leaderboardGroupName).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError(stringMessages.errorStartingTracking(
|
||||
Util.toStringOrNull(leaderboardRaceColumnFleetNames), caught.getMessage()));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private class AddTypedDeviceMappingsToRegattaLog {
|
||||
private int callCount = 0;
|
||||
private final Runnable callback;
|
||||
public AddTypedDeviceMappingsToRegattaLog(String leaderboardName, Collection<TypedDeviceMappingDTO> mappings, Runnable callback) {
|
||||
this.callback = callback;
|
||||
for (TypedDeviceMappingDTO mapping : mappings) {
|
||||
callCount++;
|
||||
sailingService.addTypedDeviceMappingToRegattaLog(leaderboardName, mapping, new AsyncCallback<Void>() {
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
callCount--;
|
||||
runCallbackIfNoCallIsRunning();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError("Failed to add device mappings!");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
private void runCallbackIfNoCallIsRunning() {
|
||||
if (callCount == 0) {
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class AddDeviceMappingsToRegattaLog {
|
||||
private int callCount = 0;
|
||||
private final Runnable callback;
|
||||
public AddDeviceMappingsToRegattaLog(String leaderboardName, Collection<DeviceMappingDTO> mappings, Runnable callback) {
|
||||
this.callback = callback;
|
||||
for (DeviceMappingDTO mapping : mappings) {
|
||||
callCount++;
|
||||
sailingService.addDeviceMappingToRegattaLog(leaderboardName, mapping, new AsyncCallback<Void>() {
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
callCount--;
|
||||
runCallbackIfNoCallIsRunning();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError("Failed to add device mappings!");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
private void runCallbackIfNoCallIsRunning() {
|
||||
if (callCount == 0) {
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private abstract class DataLoadingCallback<T> implements AsyncCallback<T> {
|
||||
|
||||
@Override
|
||||
public final void onFailure(Throwable caught) {
|
||||
errorReporter.reportError("Failed loading importer data from server!");
|
||||
}
|
||||
}
|
||||
|
||||
private abstract class CancelImportDialogCallback<T> implements DialogCallback<T> {
|
||||
|
||||
@Override
|
||||
public final void cancel() {
|
||||
Window.alert(stringMessages.importCanceledByUser());
|
||||
}
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gwt.user.client.ui.Anchor;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.settings.client.EntryPointWithSettingsLinkFactory;
|
||||
import com.sap.sailing.gwt.ui.client.EntryPointLinkFactory;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
|
||||
|
||||
public class ExpeditionAllInOneImportResultDialog extends DataEntryDialog<Void> {
|
||||
|
||||
private final VerticalPanel verticalPanel;
|
||||
|
||||
public ExpeditionAllInOneImportResultDialog(UUID eventId, String regattaName, String raceName,
|
||||
String leaderboardName, String leaderboardGroupName) {
|
||||
super(StringMessages.INSTANCE.importFinished(), StringMessages.INSTANCE.importFinishedMessage(),
|
||||
StringMessages.INSTANCE.ok(), StringMessages.INSTANCE.cancel(), /* validator */ null,
|
||||
new DialogCallback<Void>() {
|
||||
@Override
|
||||
public void ok(Void editedObject) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
}
|
||||
});
|
||||
|
||||
verticalPanel = new VerticalPanel();
|
||||
verticalPanel.setSpacing(20);
|
||||
Anchor raceboardAnchor = new Anchor(StringMessages.INSTANCE.importFinishedGotoRaceboard(),
|
||||
EntryPointWithSettingsLinkFactory.createRaceBoardLinkWithDefaultSettings(eventId, leaderboardName,
|
||||
leaderboardGroupName, regattaName, raceName));
|
||||
raceboardAnchor.setTarget("_blank");
|
||||
verticalPanel.add(raceboardAnchor);
|
||||
Anchor eventAnchor = new Anchor(StringMessages.INSTANCE.importFinishedGotoEvent(),
|
||||
EntryPointLinkFactory.createEventPlaceLink(eventId.toString(), Collections.emptyMap()));
|
||||
eventAnchor.setTarget("_blank");
|
||||
verticalPanel.add(eventAnchor);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Widget getAdditionalWidget() {
|
||||
return verticalPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void getResult() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+6
-2
@@ -1,6 +1,6 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.text.shared.SafeHtmlRenderer;
|
||||
@@ -17,6 +17,8 @@ public class LeaderboardConfigImagesBarCell extends ImagesBarCell {
|
||||
public static final String ACTION_EXPORT_XML = "ACTION_EXPORT_XML";
|
||||
public static final String ACTION_OPEN_COACH_DASHBOARD = "ACTION_OPEN_COACH_DASHBOARD";
|
||||
public static final String ACTION_SHOW_REGATTA_LOG = "ACTION_SHOW_REGATTA_LOG";
|
||||
public static final String ACTION_CREATE_PAIRINGLIST = "ACTION_CREATE_PAIRINGLIST";
|
||||
public static final String ACTION_PRINT_PAIRINGLIST = "ACTION_PRINT_PAIRINGLIST";
|
||||
private static AdminConsoleResources resources = GWT.create(AdminConsoleResources.class);
|
||||
private final StringMessages stringMessages;
|
||||
|
||||
@@ -40,6 +42,8 @@ public class LeaderboardConfigImagesBarCell extends ImagesBarCell {
|
||||
new ImageSpec(ACTION_REMOVE, stringMessages.actionRemove(), makeImagePrototype(IconResources.INSTANCE.removeIcon())),
|
||||
new ImageSpec(ACTION_EXPORT_XML, stringMessages.actionExportXML(), makeImagePrototype(resources.exportXMLIcon())),
|
||||
new ImageSpec(ACTION_OPEN_COACH_DASHBOARD, stringMessages.actionOpenDashboard(), makeImagePrototype(resources.openCoachDashboard())),
|
||||
new ImageSpec(ACTION_SHOW_REGATTA_LOG, stringMessages.regattaLog(), makeImagePrototype(resources.flagIcon())));
|
||||
new ImageSpec(ACTION_SHOW_REGATTA_LOG, stringMessages.regattaLog(), makeImagePrototype(resources.flagIcon())),
|
||||
new ImageSpec(ACTION_CREATE_PAIRINGLIST, stringMessages.pairingLists(), makeImagePrototype(resources.pairingList())),
|
||||
new ImageSpec(ACTION_PRINT_PAIRINGLIST, stringMessages.print() + " " + stringMessages.pairingList(), makeImagePrototype(resources.printPairingList())));
|
||||
}
|
||||
}
|
||||
Executable → Regular
+58
-1
@@ -1,6 +1,6 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
@@ -38,6 +38,7 @@ import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||
import com.sap.sailing.domain.common.dto.AbstractLeaderboardDTO;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.domain.common.dto.FleetDTO;
|
||||
import com.sap.sailing.domain.common.dto.PairingListTemplateDTO;
|
||||
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
|
||||
import com.sap.sailing.gwt.settings.client.EntryPointWithSettingsLinkFactory;
|
||||
import com.sap.sailing.gwt.settings.client.leaderboard.AbstractLeaderboardPerspectiveLifecycle;
|
||||
@@ -330,6 +331,10 @@ TrackedRaceChangedListener, LeaderboardsDisplayer {
|
||||
Window.open(EntryPointLinkFactory.createDashboardLink(dashboardURLParameters), "", null);
|
||||
} else if (LeaderboardConfigImagesBarCell.ACTION_SHOW_REGATTA_LOG.equals(value)) {
|
||||
showRegattaLog();
|
||||
} else if (LeaderboardConfigImagesBarCell.ACTION_CREATE_PAIRINGLIST.equals(value)) {
|
||||
createPairingListTemplate(leaderboardDTO);
|
||||
} else if (LeaderboardConfigImagesBarCell.ACTION_PRINT_PAIRINGLIST.equals(value)) {
|
||||
openPairingListEntryPoint(leaderboardDTO);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1015,4 +1020,56 @@ TrackedRaceChangedListener, LeaderboardsDisplayer {
|
||||
availableLeaderboardList.remove(leaderBoard);
|
||||
leaderboardSelectionModel.setSelected(leaderBoard, false);
|
||||
}
|
||||
|
||||
private void createPairingListTemplate(final StrippedLeaderboardDTO leaderboardDTO) {
|
||||
final PairingListCreationSetupDialog dialog = new PairingListCreationSetupDialog(leaderboardDTO, this.stringMessages,
|
||||
new DialogCallback<PairingListTemplateDTO>() {
|
||||
|
||||
@Override
|
||||
public void ok(PairingListTemplateDTO editedObject) {
|
||||
BusyDialog busyDialog = new BusyDialog();
|
||||
busyDialog.show();
|
||||
try {
|
||||
sailingService.calculatePairingListTemplate(editedObject.getFlightCount(), editedObject.getGroupCount(),
|
||||
editedObject.getCompetitorCount(), editedObject.getFlightMultiplier(),
|
||||
new AsyncCallback<PairingListTemplateDTO>() {
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
busyDialog.hide();
|
||||
System.out.println(caught);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(PairingListTemplateDTO result) {
|
||||
busyDialog.hide();
|
||||
result.setSelectedFlightNames(editedObject.getSelectedFlightNames());
|
||||
openPairingListCreationDialog(leaderboardDTO, result);
|
||||
}
|
||||
|
||||
});
|
||||
} catch (Exception exception) {
|
||||
// TODO show error somehow
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
|
||||
}
|
||||
});
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private void openPairingListCreationDialog(StrippedLeaderboardDTO leaderboardDTO, PairingListTemplateDTO template) {
|
||||
PairingListCreationDialog dialog = new PairingListCreationDialog(leaderboardDTO, stringMessages, template, sailingService);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private void openPairingListEntryPoint(StrippedLeaderboardDTO leaderboardDTO) {
|
||||
Map<String, String> result = new HashMap<>();
|
||||
result.put("leaderboardName", leaderboardDTO.getName());
|
||||
String link = EntryPointLinkFactory.createPairingListLink(result);
|
||||
Window.open(link, "", "");
|
||||
}
|
||||
}
|
||||
+256
@@ -0,0 +1,256 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.dom.client.Style.Unit;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.Anchor;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.CaptionPanel;
|
||||
import com.google.gwt.user.client.ui.Grid;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.Image;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.ScrollPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.domain.common.dto.PairingListDTO;
|
||||
import com.sap.sailing.domain.common.dto.PairingListTemplateDTO;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
|
||||
|
||||
public class PairingListCreationDialog extends DataEntryDialog<PairingListTemplateDTO> {
|
||||
|
||||
private final PairingListTemplateDTO template;
|
||||
private final SailingServiceAsync sailingService;
|
||||
private final StrippedLeaderboardDTO leaderboardDTO;
|
||||
private final StringMessages stringMessages;
|
||||
|
||||
private PairingListDTO pairingListDTO;
|
||||
|
||||
private final AdminConsoleResources resources = GWT.create(AdminConsoleResources.class);
|
||||
|
||||
private final Button applyToRacelogButton, printPreViewButton, refreshButton;
|
||||
private final Anchor cSVExportAnchor;
|
||||
|
||||
public PairingListCreationDialog(StrippedLeaderboardDTO leaderboardDTO, final StringMessages stringMessages,
|
||||
PairingListTemplateDTO template, SailingServiceAsync sailingService) {
|
||||
super(stringMessages.pairingList(), null, stringMessages.close(), null, null, null);
|
||||
this.stringMessages = stringMessages;
|
||||
this.template = template;
|
||||
this.sailingService = sailingService;
|
||||
this.leaderboardDTO = leaderboardDTO;
|
||||
this.ensureDebugId("PairingListCreationDialog");
|
||||
applyToRacelogButton = new Button(stringMessages.insertIntoRegatta());
|
||||
printPreViewButton = new Button(stringMessages.printView());
|
||||
refreshButton = new Button(stringMessages.recalculate());
|
||||
cSVExportAnchor = new Anchor(stringMessages.csvExport());
|
||||
cSVExportAnchor.ensureDebugId("CSVExportAnchor");
|
||||
cSVExportAnchor.getElement().setAttribute("href",
|
||||
"data:text/plain;charset=utf-8," + getCSVFromPairingListTemplate(getResult().getPairingListTemplate()));
|
||||
cSVExportAnchor.getElement().setAttribute("download", "pairingListTemplate.csv");
|
||||
if (template.getCompetitorCount() != leaderboardDTO.competitorsCount) {
|
||||
this.disableApplyToRacelogsAndPrintPreview();
|
||||
}
|
||||
|
||||
sailingService.getPairingListFromTemplate(this.leaderboardDTO.getName(), this.template.getFlightMultiplier(),
|
||||
this.template.getSelectedFlightNames(), this.template, new AsyncCallback<PairingListDTO>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
pairingListDTO = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(PairingListDTO result) {
|
||||
pairingListDTO = result;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Widget getAdditionalWidget() {
|
||||
HorizontalPanel panel = new HorizontalPanel();
|
||||
|
||||
/* DATA PANEL */
|
||||
|
||||
CaptionPanel dataPanel = new CaptionPanel();
|
||||
dataPanel.setCaptionText(stringMessages.parameters());
|
||||
Grid formGrid = new Grid(6, 2);
|
||||
dataPanel.add(formGrid);
|
||||
Label flights = new Label(String.valueOf(this.template.getFlightCount()));
|
||||
flights.ensureDebugId("FlightCountLabel");
|
||||
Label groups = new Label(String.valueOf(this.template.getGroupCount()));
|
||||
groups.ensureDebugId("GroupCountLabel");
|
||||
Label competitors = new Label(String.valueOf(this.template.getCompetitorCount()));
|
||||
competitors.ensureDebugId("CompetitorCountLabel");
|
||||
formGrid.setWidget(0, 0, new Label(stringMessages.numberOfFlights()));
|
||||
formGrid.setWidget(0, 1, flights);
|
||||
formGrid.setWidget(1, 0, new Label(stringMessages.numberOfFleets()));
|
||||
formGrid.setWidget(1, 1, groups);
|
||||
formGrid.setWidget(2, 0, new Label(stringMessages.numberOfRaces()));
|
||||
formGrid.setWidget(2, 1, new Label(String.valueOf((template.getFlightCount() * template.getGroupCount()))));
|
||||
formGrid.setWidget(3, 0, new Label(stringMessages.numberOfCompetitors()));
|
||||
formGrid.setWidget(3, 1, competitors);
|
||||
HorizontalPanel qualityPanel = new HorizontalPanel();
|
||||
qualityPanel.add(new Label(stringMessages.quality()));
|
||||
Image qualityHelpImage = new Image(resources.help());
|
||||
qualityPanel.add(qualityHelpImage);
|
||||
qualityHelpImage.getElement().getStyle().setMarginLeft(10, Unit.PX);
|
||||
qualityHelpImage.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
Window.open("https://wiki.sapsailing.com/wiki/howto/eventmanagers/Pairing-Lists#pairing-list_general_quality", "", "");
|
||||
}
|
||||
});
|
||||
formGrid.setWidget(4, 0, qualityPanel);
|
||||
formGrid.setWidget(4, 1, new Label(String.valueOf(Math.floor(this.template.getQuality() * 1000) / 1000)));
|
||||
if (this.template.getFlightMultiplier() > 1) {
|
||||
Label flightMultiplierLabel = new Label(String.valueOf(this.template.getFlightMultiplier()));
|
||||
formGrid.setWidget(5, 0, new Label(stringMessages.amountOfFlightRepeats()));
|
||||
formGrid.setWidget(5, 1, flightMultiplierLabel);
|
||||
flightMultiplierLabel.ensureDebugId("FlightMultiplierCountLabel");
|
||||
}
|
||||
formGrid.setCellSpacing(10);
|
||||
panel.add(dataPanel);
|
||||
|
||||
/* PAIRING LIST TEMPLATE PANEL */
|
||||
CaptionPanel pairingListTemplatePanel = new CaptionPanel();
|
||||
pairingListTemplatePanel.setCaptionText(stringMessages.pairingListTemplate());
|
||||
Grid pairingListGrid = new Grid(this.template.getPairingListTemplate().length,
|
||||
this.template.getPairingListTemplate()[0].length);
|
||||
pairingListGrid.setCellSpacing(5);
|
||||
ScrollPanel scrollPanel = new ScrollPanel(pairingListGrid);
|
||||
scrollPanel.setPixelSize((Window.getClientWidth() / 4), (Window.getClientHeight() / 3));
|
||||
pairingListTemplatePanel.add(scrollPanel);
|
||||
for (int groupIndex = 0; groupIndex < this.template.getPairingListTemplate().length; groupIndex++) {
|
||||
for (int boatIndex = 0; boatIndex < this.template.getPairingListTemplate()[0].length; boatIndex++) {
|
||||
pairingListGrid.setWidget(groupIndex, boatIndex,
|
||||
new Label(String.valueOf(this.template.getPairingListTemplate()[groupIndex][boatIndex] + 1)));
|
||||
pairingListGrid.getCellFormatter().setWidth(groupIndex, boatIndex, "50px");
|
||||
}
|
||||
}
|
||||
panel.add(pairingListTemplatePanel);
|
||||
configButtons();
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
protected PairingListTemplateDTO getResult() {
|
||||
return this.template;
|
||||
}
|
||||
|
||||
private void configButtons() {
|
||||
getRightButtonPannel().remove(getCancelButton());
|
||||
applyToRacelogButton.getElement().getStyle().setMargin(3, Unit.PX);
|
||||
applyToRacelogButton.ensureDebugId("ApplyToRacelogButton");
|
||||
printPreViewButton.getElement().getStyle().setMargin(3, Unit.PX);
|
||||
printPreViewButton.ensureDebugId("printViewButton");
|
||||
refreshButton.getElement().getStyle().setMargin(3, Unit.PX);
|
||||
refreshButton.ensureDebugId("printViewButton");
|
||||
getRightButtonPannel().add(applyToRacelogButton);
|
||||
getRightButtonPannel().add(printPreViewButton);
|
||||
getRightButtonPannel().add(refreshButton);
|
||||
getRightButtonPannel().add(cSVExportAnchor);
|
||||
if (!applyToRacelogButton.isEnabled()) {
|
||||
Label label = new Label(stringMessages.blockedApplyButton());
|
||||
label.getElement().getStyle().setColor("red");
|
||||
getRightButtonPannel().add(label);
|
||||
}
|
||||
applyToRacelogButton.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
sailingService.fillRaceLogsFromPairingListTemplate(leaderboardDTO.getName(),
|
||||
template.getFlightMultiplier(), template.getSelectedFlightNames(), pairingListDTO,
|
||||
new AsyncCallback<Void>() {
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
/* TODO: log successfull */
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
caught.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
printPreViewButton.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
sailingService.getRaceDisplayNamesFromLeaderboard(leaderboardDTO.getName(),
|
||||
Util.asList(template.getSelectedFlightNames()), new AsyncCallback<List<String>>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
try {
|
||||
throw caught;
|
||||
} catch (Throwable e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void onSuccess(List<String> result) {
|
||||
PairingListPreviewDialog dialog = new PairingListPreviewDialog(pairingListDTO, result, stringMessages,leaderboardDTO.getName());
|
||||
dialog.show();
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
refreshButton.addClickHandler(new ClickHandler() {
|
||||
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
getDialogBox().hide();
|
||||
BusyDialog busyDialog = new BusyDialog();
|
||||
busyDialog.show();
|
||||
try {
|
||||
sailingService.calculatePairingListTemplate(template.getFlightCount(), template.getGroupCount(),
|
||||
template.getCompetitorCount(), template.getFlightMultiplier(),
|
||||
new AsyncCallback<PairingListTemplateDTO>() {
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
busyDialog.hide();
|
||||
System.out.println(caught);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(PairingListTemplateDTO result) {
|
||||
busyDialog.hide();
|
||||
result.setSelectedFlightNames(template.getSelectedFlightNames());
|
||||
PairingListCreationDialog dialog = new PairingListCreationDialog(leaderboardDTO,
|
||||
stringMessages, result, sailingService);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
});
|
||||
} catch (Exception exception) {
|
||||
// TODO show error somehow
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private String getCSVFromPairingListTemplate(int[][] pairingListTemplate) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (int[] row : pairingListTemplate) {
|
||||
for (int column : row) {
|
||||
result.append((column + 1) + ",");
|
||||
}
|
||||
result.append("\n");
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private void disableApplyToRacelogsAndPrintPreview() {
|
||||
this.applyToRacelogButton.setEnabled(false);
|
||||
printPreViewButton.setEnabled(false);
|
||||
}
|
||||
|
||||
}
|
||||
+242
@@ -0,0 +1,242 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.event.logical.shared.ValueChangeEvent;
|
||||
import com.google.gwt.event.logical.shared.ValueChangeHandler;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.ui.CaptionPanel;
|
||||
import com.google.gwt.user.client.ui.CheckBox;
|
||||
import com.google.gwt.user.client.ui.Grid;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.ScrollPanel;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.domain.common.dto.PairingListTemplateDTO;
|
||||
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.gwt.client.controls.IntegerBox;
|
||||
|
||||
public class PairingListCreationSetupDialog extends AbstractPairingListCreationSetupDialog<PairingListTemplateDTO> {
|
||||
|
||||
private final IntegerBox competitorCountTextBox;
|
||||
private final IntegerBox flightMultiplierTextBox;
|
||||
private final CheckBox flightMultiplierCheckBox;
|
||||
private Iterable<CheckBox> selectedSeriesCheckboxes;
|
||||
|
||||
protected static class PairingListParameterValidator extends AbstractPairingListParameterValidator {
|
||||
public PairingListParameterValidator(StringMessages stringMessages) {
|
||||
super(stringMessages);
|
||||
}
|
||||
}
|
||||
|
||||
public PairingListCreationSetupDialog(StrippedLeaderboardDTO leaderboardDTO, StringMessages stringMessages,
|
||||
DialogCallback<PairingListTemplateDTO> callback) {
|
||||
|
||||
super(leaderboardDTO, stringMessages.pairingList(), stringMessages,
|
||||
new PairingListParameterValidator(stringMessages), callback);
|
||||
|
||||
this.competitorCountTextBox = createIntegerBox(leaderboardDTO.competitorsCount, 2);
|
||||
this.competitorCountTextBox.ensureDebugId("CompetitorCountBox");
|
||||
this.flightMultiplierTextBox = createIntegerBox(1, 2);
|
||||
this.flightMultiplierTextBox.setEnabled(false);
|
||||
this.flightMultiplierTextBox.ensureDebugId("FlightMultiplierIntegerBox");
|
||||
this.flightMultiplierCheckBox = createCheckbox(this.stringMessages.amountOfFlightRepeats());
|
||||
this.flightMultiplierCheckBox.setTitle(this.stringMessages.multiplierInfo());
|
||||
this.flightMultiplierCheckBox.ensureDebugId("FlightMultiplierCheckBox");
|
||||
this.ensureDebugId("PairingListCreationSetupDialog");
|
||||
|
||||
this.flightMultiplierCheckBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
|
||||
@Override
|
||||
public void onValueChange(ValueChangeEvent<Boolean> event) {
|
||||
flightMultiplierTextBox.setEnabled(event.getValue());
|
||||
if (event.getValue()) {
|
||||
if (Util.size(getCheckedSelectedCheckBoxes()) > 0) {
|
||||
enableOrDisableAllSelectedSeriesCheckBoxes(false, true);
|
||||
}
|
||||
} else {
|
||||
flightMultiplierTextBox.setText("1");
|
||||
enableOrDisableAllSelectedSeriesCheckBoxes(true, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
List<CheckBox> checkboxes = new ArrayList<CheckBox>();
|
||||
for (String seriesName : getSeriesNamesFromAllRaces(leaderboardDTO.getRaceList())) {
|
||||
CheckBox current = createCheckbox(seriesName);
|
||||
current.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
|
||||
@Override
|
||||
public void onValueChange(ValueChangeEvent<Boolean> event) {
|
||||
validateCheckboxes(event.getValue());
|
||||
}
|
||||
});
|
||||
current.ensureDebugId("SelectedFlightsCheckbox: " + seriesName);
|
||||
checkboxes.add(current);
|
||||
}
|
||||
selectedSeriesCheckboxes = checkboxes;
|
||||
Util.get(selectedSeriesCheckboxes, 0).setValue(true);
|
||||
validateCheckboxes(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Widget getAdditionalWidget() {
|
||||
final VerticalPanel panel = new VerticalPanel();
|
||||
CaptionPanel infoPanel = new CaptionPanel();
|
||||
infoPanel.setCaptionText("Info");
|
||||
panel.add(infoPanel);
|
||||
ScrollPanel infoScrollPanel = new ScrollPanel();
|
||||
infoScrollPanel.setPixelSize((Window.getClientWidth() / 3), 150);
|
||||
infoScrollPanel.add(new Label(stringMessages.pairingListCreationInfo()));
|
||||
infoPanel.add(infoScrollPanel);
|
||||
Grid formGrid = new Grid(Util.size(selectedSeriesCheckboxes) + 2, 2);
|
||||
panel.add(formGrid);
|
||||
formGrid.setWidget(0, 0, new Label(stringMessages.setCompetitors()));
|
||||
formGrid.setWidget(0, 1, this.competitorCountTextBox);
|
||||
formGrid.setWidget(1, 0, this.flightMultiplierCheckBox);
|
||||
formGrid.setWidget(1, 1, this.flightMultiplierTextBox);
|
||||
formGrid.setWidget(2, 0, new Label(stringMessages.seriesHint()));
|
||||
int count = 0;
|
||||
for (CheckBox current : selectedSeriesCheckboxes) {
|
||||
formGrid.setWidget(2 + count, 1, current);
|
||||
count++;
|
||||
}
|
||||
return panel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PairingListTemplateDTO getResult() {
|
||||
PairingListTemplateDTO dto = new PairingListTemplateDTO(this.competitorCountTextBox.getValue(),
|
||||
this.flightMultiplierTextBox.getValue());
|
||||
if (Util.size(this.getCheckedSelectedCheckBoxes()) > 0) {
|
||||
String seriesName = Util.get(this.getCheckedSelectedCheckBoxes(), 0).getText();
|
||||
dto.setGroupCount(
|
||||
this.getOneRaceFromSeriesName(seriesName, leaderboardDTO.getRaceList()).getFleets().size());
|
||||
} else {
|
||||
dto.setGroupCount(0);
|
||||
}
|
||||
if (this.flightMultiplierCheckBox.getValue()) {
|
||||
dto.setFlightMultiplier(this.flightMultiplierTextBox.getValue());
|
||||
} else {
|
||||
dto.setFlightMultiplier(1);
|
||||
}
|
||||
List<String> selectedFlightNames = new ArrayList<>();
|
||||
for (CheckBox box : getCheckedSelectedCheckBoxes()) {
|
||||
selectedFlightNames.addAll(getRaceColumnNamesFromSeriesName(box.getText(), leaderboardDTO.getRaceList()));
|
||||
}
|
||||
dto.setSelectedFlightNames(selectedFlightNames);
|
||||
dto.setFlightCount(selectedFlightNames.size());
|
||||
return dto;
|
||||
}
|
||||
|
||||
public void setDefaultCompetitorCount(final int competitorCount) {
|
||||
if (this.competitorCountTextBox.getValue() == 0) {
|
||||
this.competitorCountTextBox.setValue(competitorCount);
|
||||
this.validateAndUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
private void validateCheckboxes(boolean enabled) {
|
||||
if (enabled) {
|
||||
disableSelectedSeriesCheckBoxes(leaderboardDTO);
|
||||
if (flightMultiplierCheckBox.getValue()) {
|
||||
if (Util.size(getCheckedSelectedCheckBoxes()) > 0) {
|
||||
enableOrDisableAllSelectedSeriesCheckBoxes(false, true);
|
||||
}
|
||||
} else {
|
||||
if (Util.size(getCheckedSelectedCheckBoxes()) > 1) {
|
||||
flightMultiplierCheckBox.setEnabled(false);
|
||||
} else {
|
||||
flightMultiplierCheckBox.setEnabled(true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (Util.size(getCheckedSelectedCheckBoxes()) > 0) {
|
||||
|
||||
} else {
|
||||
enableOrDisableAllSelectedSeriesCheckBoxes(true, false);
|
||||
}
|
||||
if (Util.size(getCheckedSelectedCheckBoxes()) < 2) {
|
||||
flightMultiplierCheckBox.setEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Iterable<String> getSeriesNamesFromAllRaces(final Iterable<RaceColumnDTO> raceColumns) {
|
||||
List<String> result = new ArrayList<>();
|
||||
for (RaceColumnDTO raceColumn : raceColumns) {
|
||||
if (!raceColumn.isMedalRace()) {
|
||||
if (result.contains(raceColumn.getSeriesName())) {
|
||||
|
||||
} else {
|
||||
result.add(raceColumn.getSeriesName());
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private RaceColumnDTO getOneRaceFromSeriesName(final String seriesName, final Iterable<RaceColumnDTO> raceColumns) {
|
||||
for (RaceColumnDTO raceColumn : raceColumns) {
|
||||
if (!raceColumn.isMedalRace() && seriesName.equals(raceColumn.getSeriesName())) {
|
||||
return raceColumn;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<String> getRaceColumnNamesFromSeriesName(final String seriesName,
|
||||
final Iterable<RaceColumnDTO> raceColumns) {
|
||||
List<String> result = new ArrayList<>();
|
||||
for (RaceColumnDTO raceColumn : raceColumns) {
|
||||
if (!raceColumn.isMedalRace() && seriesName.equals(raceColumn.getSeriesName())) {
|
||||
result.add(raceColumn.getName());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Iterable<CheckBox> getCheckedSelectedCheckBoxes() {
|
||||
List<CheckBox> result = new ArrayList<>();
|
||||
for (CheckBox box : selectedSeriesCheckboxes) {
|
||||
if (box.getValue()) {
|
||||
result.add(box);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void disableSelectedSeriesCheckBoxes(final StrippedLeaderboardDTO leaderboardDTO) {
|
||||
Iterable<CheckBox> boxes = getCheckedSelectedCheckBoxes();
|
||||
if (Util.size(boxes) <= 1) {
|
||||
RaceColumnDTO race = getOneRaceFromSeriesName(Util.get(boxes, 0).getText(), leaderboardDTO.getRaceList());
|
||||
for (CheckBox box : selectedSeriesCheckboxes) {
|
||||
if (race.getFleets().size() == getOneRaceFromSeriesName(box.getText(), leaderboardDTO.getRaceList())
|
||||
.getFleets().size()) {
|
||||
} else {
|
||||
box.setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void enableOrDisableAllSelectedSeriesCheckBoxes(final boolean enabled, final boolean exclusiveSelected) {
|
||||
if (exclusiveSelected) {
|
||||
for (CheckBox box : selectedSeriesCheckboxes) {
|
||||
if (box.getValue()) {
|
||||
continue;
|
||||
}
|
||||
box.setEnabled(enabled);
|
||||
}
|
||||
} else {
|
||||
if (Util.size(getCheckedSelectedCheckBoxes()) > 0) {
|
||||
return;
|
||||
}
|
||||
for (CheckBox box : selectedSeriesCheckboxes) {
|
||||
box.setEnabled(enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+215
@@ -0,0 +1,215 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.dom.client.Style;
|
||||
import com.google.gwt.dom.client.Style.TextAlign;
|
||||
import com.google.gwt.dom.client.Style.Unit;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.Grid;
|
||||
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.ScrollPanel;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.domain.common.dto.BoatDTO;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTOImpl;
|
||||
import com.sap.sailing.domain.common.dto.PairingListDTO;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sse.common.Color;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
|
||||
|
||||
public class PairingListPreviewDialog extends DataEntryDialog<Void> {
|
||||
|
||||
private final StringMessages stringMessages;
|
||||
private final PairingListDTO pairingListDTO;
|
||||
private final List<String> fleetNames;
|
||||
private final Button print;
|
||||
private final String leaderboardName;
|
||||
|
||||
public PairingListPreviewDialog(PairingListDTO pairingListDTO, List<String> fleetNames, StringMessages stringMessages,String leaderboardName) {
|
||||
super(stringMessages.pairingList() + " " + stringMessages.printView(), "", stringMessages.ok(), stringMessages.cancel(), null, null);
|
||||
this.stringMessages = stringMessages;
|
||||
this.pairingListDTO = pairingListDTO;
|
||||
this.fleetNames = fleetNames;
|
||||
this.leaderboardName=leaderboardName;
|
||||
this.print= new Button(stringMessages.print());
|
||||
this.print.addClickHandler(new ClickHandler() {
|
||||
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
Widget pairingListPanel = getPairingListGrid();
|
||||
printPairingListGrid(
|
||||
"<div class='printHeader'><img src='images/home/logo-small@2x.png' </img>"
|
||||
+ "<b class='title'>"
|
||||
+ SafeHtmlUtils.fromString(leaderboardName)
|
||||
.asString()
|
||||
+ "</b></div>" + pairingListPanel.asWidget()
|
||||
.getElement().getInnerHTML());
|
||||
}
|
||||
});
|
||||
this.getRightButtonPannel().add(print);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void getResult() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Widget getAdditionalWidget() {
|
||||
ScrollPanel scrollPanel = new ScrollPanel(this.getPairingListGrid());
|
||||
scrollPanel.setHeight(((int) Window.getClientHeight() * 0.8) + "px");
|
||||
scrollPanel.getElement().getStyle().setPadding(15, Unit.PX);
|
||||
return scrollPanel;
|
||||
}
|
||||
|
||||
private Widget getPairingListGrid() {
|
||||
final List<BoatDTO> boats = pairingListDTO.getBoats();
|
||||
|
||||
final int flightCount = pairingListDTO.getPairingList().size();
|
||||
final int groupCount = pairingListDTO.getPairingList().get(0).size();
|
||||
final int boatCount = boats.size();
|
||||
|
||||
Grid pairingListGrid = new Grid(flightCount * groupCount + 1, (boatCount + 2));
|
||||
pairingListGrid.getElement().setId("grid");
|
||||
pairingListGrid.setCellPadding(15);
|
||||
pairingListGrid.getElement().setAttribute("style", "border-collapse: collapse");
|
||||
|
||||
int flightIndexInGrid = 1;
|
||||
int groupIndex = 1;
|
||||
int boatIndex = 0;
|
||||
|
||||
for (BoatDTO boat : boats) {
|
||||
pairingListGrid.setWidget(0, boatIndex + 2, new Label(boat.getName()));
|
||||
pairingListGrid.getCellFormatter().getElement(0, boatIndex + 2).getStyle().setTextAlign(TextAlign.CENTER);
|
||||
pairingListGrid.getCellFormatter().getElement(0, boatIndex + 2).getStyle().setPadding(10, Unit.PX);
|
||||
if (boat.getColor() != null) {
|
||||
pairingListGrid.getCellFormatter().getElement(0, boatIndex + 2).getStyle().setBackgroundColor(
|
||||
boat.getColor().getAsHtml());
|
||||
} else {
|
||||
pairingListGrid.getCellFormatter().getElement(0, boatIndex + 2).getStyle().setBackgroundColor(
|
||||
"#cecece");
|
||||
}
|
||||
boatIndex++;
|
||||
}
|
||||
String color = "";
|
||||
pairingListGrid.getCellFormatter().getElement(0, 0).getStyle().setBackgroundColor("#cecece");
|
||||
pairingListGrid.getCellFormatter().getElement(0, 1).getStyle().setBackgroundColor("#cecece");
|
||||
for (List<List<Pair<CompetitorDTO, BoatDTO>>> flight : pairingListDTO.getPairingList()) {
|
||||
color = (color.equals("none") ? "#cecece" : "none");
|
||||
// setting up race
|
||||
int currentRaceInGridCells = (((flightIndexInGrid - 1) * groupCount) + 1);
|
||||
pairingListGrid.setWidget(currentRaceInGridCells, 0,
|
||||
new Label(pairingListDTO.getRaceColumnNames().get(flightIndexInGrid - 1)));
|
||||
pairingListGrid.getCellFormatter().getElement(currentRaceInGridCells, 0).getStyle().setPadding(5, Unit.PX);
|
||||
pairingListGrid.getCellFormatter().getElement(currentRaceInGridCells, 0).getStyle()
|
||||
.setBackgroundColor(color);
|
||||
for (List<Pair<CompetitorDTO, BoatDTO>> group : flight) {
|
||||
// setting up fleet
|
||||
pairingListGrid.getCellFormatter().getElement(groupIndex, 0).getStyle().setPadding(3, Unit.PX);
|
||||
pairingListGrid.getCellFormatter().getElement(groupIndex, 0).getStyle().setBackgroundColor(color);
|
||||
//TODO add column for race 1-45 (default)
|
||||
pairingListGrid.setWidget(groupIndex, 1,
|
||||
new Label(fleetNames.get(groupIndex-1)));
|
||||
// setting up fleets style
|
||||
pairingListGrid.getCellFormatter().getElement(groupIndex, 1).getStyle().setPadding(3, Unit.PX);
|
||||
pairingListGrid.getCellFormatter().getElement(groupIndex, 1).getStyle().setBackgroundColor(color);
|
||||
|
||||
if (group.size() < boatCount) {
|
||||
List<BoatDTO> boatsToRemove = new ArrayList<>(boats);
|
||||
for (Pair<CompetitorDTO, BoatDTO> competitorAndBoatPair : group) {
|
||||
boatsToRemove.remove(competitorAndBoatPair.getB());
|
||||
}
|
||||
for (BoatDTO boat : boatsToRemove) {
|
||||
group.add(new Pair<CompetitorDTO, BoatDTO>(new CompetitorDTOImpl(), boat));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (Pair<CompetitorDTO, BoatDTO> competitorAndBoatPair : group) {
|
||||
int boatIndexInGrid = boats.indexOf(competitorAndBoatPair.getB()) + 2;
|
||||
if (competitorAndBoatPair.getA().getName() == null) {
|
||||
pairingListGrid.setWidget(groupIndex, boatIndexInGrid, new Label(stringMessages.empty()));
|
||||
pairingListGrid.getCellFormatter().getElement(groupIndex, boatIndexInGrid).getStyle()
|
||||
.setColor(Color.RED.toString());
|
||||
} else {
|
||||
// TODO change competitor name to competitor shorthand symbol
|
||||
pairingListGrid.setWidget(groupIndex, boatIndexInGrid,
|
||||
new Label(competitorAndBoatPair.getA().getSailID()));
|
||||
}
|
||||
pairingListGrid.getCellFormatter().getElement(groupIndex, boatIndexInGrid).getStyle()
|
||||
.setFontWeight(Style.FontWeight.BOLD);
|
||||
pairingListGrid.getCellFormatter().getElement(groupIndex, boatIndexInGrid).getStyle()
|
||||
.setTextAlign(TextAlign.CENTER);
|
||||
pairingListGrid.getCellFormatter().getElement(groupIndex, boatIndexInGrid).getStyle().setPadding(5,
|
||||
Unit.PX);
|
||||
pairingListGrid.getCellFormatter().getElement(groupIndex, boatIndexInGrid).getStyle()
|
||||
.setBackgroundColor(color);
|
||||
}
|
||||
|
||||
groupIndex++;
|
||||
}
|
||||
flightIndexInGrid++;
|
||||
}
|
||||
|
||||
VerticalPanel pairingListPanel = new VerticalPanel();
|
||||
pairingListPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
|
||||
pairingListPanel.add(pairingListGrid);
|
||||
pairingListPanel.setWidth("100%");
|
||||
pairingListPanel.ensureDebugId("PairingListPanel");
|
||||
|
||||
ScrollPanel result = new ScrollPanel();
|
||||
result.add(pairingListPanel);
|
||||
|
||||
return pairingListPanel;
|
||||
}
|
||||
|
||||
private native void printPairingListGrid(String pageHTMLContent) /*-{
|
||||
var frameID = '__gwt_historyFrame';
|
||||
var frame = $doc.getElementById(frameID);
|
||||
if (!frame) {
|
||||
$wnd.alert("Error: Can not find frame '" + frameID + "'");
|
||||
return;
|
||||
}
|
||||
frame = frame.contentWindow;
|
||||
var document = frame.document;
|
||||
document.open();
|
||||
document.write(pageHTMLContent);
|
||||
|
||||
//adding style to doc
|
||||
var css = "body { background: #fff; font-family: 'Open Sans', Arial, Verdana, sans-serif;"
|
||||
+ "line-height: 1; font-weight: 400; border: 0 }"
|
||||
+ ".title { font-size: 18px; text-align: center; float: right; color: #f6f9fc; margin-bottom: 0.466666666666667em; margin-right: 0.466666666666667em }"
|
||||
+ "img { max-height: 2em; float:left; margin-top: 0.466666666666667em; margin-left: 0.466666666666667em }"
|
||||
+ ".printHeader { font-size: 1rem; background: #333; border-bottom: 0.333333333333333em solid #f0ab00;"
|
||||
+ "height: 3.333333333333333em; line-height: 3em; width: 100%; overflow: hidden;}"
|
||||
+ "table { border-collapse: collapse; border: 1px solid black; margin: auto; width: 100%}"
|
||||
+ "td { font-size: 13px; }"
|
||||
head = document.head || document.getElementsByTagName('head')[0];
|
||||
style = document.createElement('style');
|
||||
style.type = 'text/css';
|
||||
if (style.styleSheet) {
|
||||
style.styleSheet.cssText = css;
|
||||
} else {
|
||||
style.appendChild(document.createTextNode(css));
|
||||
}
|
||||
head.appendChild(style);
|
||||
|
||||
document.close();
|
||||
|
||||
//Timeout for assets loading
|
||||
setTimeout(function() {
|
||||
frame.focus();
|
||||
frame.print();
|
||||
}, 100);
|
||||
}-*/;
|
||||
|
||||
}
|
||||
+1
-3
@@ -1,6 +1,6 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
@@ -364,6 +364,4 @@ public class RegattaListComposite extends Composite implements RegattasDisplayer
|
||||
public CellTable<RegattaDTO> getRegattaTable() {
|
||||
return regattaTable;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.shared.DeviceMappingDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.TrackFileImportDeviceIdentifierDTO;
|
||||
import com.sap.sse.gwt.client.ErrorReporter;
|
||||
|
||||
public class RegattaLogFixesAddMappingsDialog extends AbstractRegattaLogFixesAddMappingsDialog {
|
||||
TrackFileImportWidget importWidget;
|
||||
|
||||
public RegattaLogFixesAddMappingsDialog(SailingServiceAsync sailingService,
|
||||
final ErrorReporter errorReporter, final StringMessages stringMessages, String leaderboardName,
|
||||
Collection<TrackFileImportDeviceIdentifierDTO> importedDeviceIds,
|
||||
DialogCallback<Collection<DeviceMappingDTO>> callback) {
|
||||
super(sailingService, errorReporter, stringMessages, leaderboardName, callback);
|
||||
deviceIdTable.getDataProvider().getList().addAll(importedDeviceIds);
|
||||
}
|
||||
}
|
||||
+3
-199
@@ -1,216 +1,20 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.CaptionPanel;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.google.gwt.view.client.SelectionChangeEvent;
|
||||
import com.google.gwt.view.client.SingleSelectionModel;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.MappableToDevice;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.shared.DeviceIdentifierDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.DeviceMappingDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.MarkDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.TrackFileImportDeviceIdentifierDTO;
|
||||
import com.sap.sse.gwt.client.ErrorReporter;
|
||||
import com.sap.sse.gwt.client.celltable.RefreshableSingleSelectionModel;
|
||||
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
|
||||
|
||||
public class RegattaLogImportFixesAndAddMappingsDialog extends DataEntryDialog<Collection<DeviceMappingDTO>> {
|
||||
private String leaderboardName;
|
||||
public class RegattaLogImportFixesAndAddMappingsDialog extends AbstractRegattaLogFixesAddMappingsDialog {
|
||||
TrackFileImportWidget importWidget;
|
||||
private TrackFileImportDeviceIdentifierTableWrapper deviceIdTable;
|
||||
protected final CompetitorTableWrapper<RefreshableSingleSelectionModel<CompetitorDTO>> competitorTable;
|
||||
protected final MarkTableWrapper<RefreshableSingleSelectionModel<MarkDTO>> markTable;
|
||||
private final StringMessages stringMessages;
|
||||
|
||||
private final Map<TrackFileImportDeviceIdentifierDTO, MappableToDevice> mappings = new HashMap<>();
|
||||
|
||||
private TrackFileImportDeviceIdentifierDTO deviceToSelect;
|
||||
private CompetitorDTO compToSelect;
|
||||
private MarkDTO markToSelect;
|
||||
private boolean inInstableTransitionState = false;
|
||||
|
||||
public RegattaLogImportFixesAndAddMappingsDialog(SailingServiceAsync sailingService,
|
||||
final ErrorReporter errorReporter, final StringMessages stringMessages, String leaderboardName,
|
||||
DialogCallback<Collection<DeviceMappingDTO>> callback) {
|
||||
super(stringMessages.add(stringMessages.deviceMappings()), stringMessages.add(stringMessages.deviceMappings()),
|
||||
stringMessages.add(), stringMessages.cancel(),
|
||||
new DataEntryDialog.Validator<Collection<DeviceMappingDTO>>() {
|
||||
@Override
|
||||
public String getErrorMessage(Collection<DeviceMappingDTO> valueToValidate) {
|
||||
if (!valueToValidate.isEmpty()){
|
||||
return null;
|
||||
} else {
|
||||
return stringMessages.pleaseCreateAtLeastOneMappingBy();
|
||||
}
|
||||
}
|
||||
}, true, callback);
|
||||
this.stringMessages = stringMessages;
|
||||
deviceIdTable = new TrackFileImportDeviceIdentifierTableWrapper(sailingService, stringMessages, errorReporter);
|
||||
super(sailingService, errorReporter, stringMessages, leaderboardName, callback);
|
||||
importWidget = new TrackFileImportWidget(deviceIdTable, stringMessages, sailingService, errorReporter);
|
||||
deviceIdTable.getSelectionModel().addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
|
||||
@Override
|
||||
public void onSelectionChange(SelectionChangeEvent event) {
|
||||
deviceSelectionChanged(deviceIdTable.getSelectionModel().getSelectedObject());
|
||||
}
|
||||
});
|
||||
competitorTable = new CompetitorTableWrapper<>(sailingService, stringMessages, errorReporter, /* multiSelection */
|
||||
false, true);
|
||||
markTable = new MarkTableWrapper<RefreshableSingleSelectionModel<MarkDTO>>(
|
||||
/* multiSelection */false, sailingService, stringMessages, errorReporter);
|
||||
|
||||
competitorTable.getSelectionModel().addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
|
||||
@Override
|
||||
public void onSelectionChange(SelectionChangeEvent event) {
|
||||
mappedToSelectionChanged(competitorTable.getSelectionModel().getSelectedObject());
|
||||
}
|
||||
});
|
||||
markTable.getSelectionModel().addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
|
||||
@Override
|
||||
public void onSelectionChange(SelectionChangeEvent event) {
|
||||
mappedToSelectionChanged(markTable.getSelectionModel().getSelectedObject());
|
||||
}
|
||||
});
|
||||
|
||||
this.leaderboardName = leaderboardName;
|
||||
|
||||
getCompetitorRegistrations(sailingService, errorReporter);
|
||||
getMarks(sailingService, errorReporter);
|
||||
setImportWidget(importWidget);
|
||||
}
|
||||
|
||||
void getMarks(SailingServiceAsync sailingService, final ErrorReporter errorReporter) {
|
||||
sailingService.getMarksInRegattaLog(leaderboardName, new AsyncCallback<Iterable<MarkDTO>>() {
|
||||
@Override
|
||||
public void onSuccess(Iterable<MarkDTO> result) {
|
||||
markTable.refresh(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError("Could not load marks: " + caught.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void getCompetitorRegistrations(SailingServiceAsync sailingService, final ErrorReporter errorReporter) {
|
||||
sailingService.getCompetitorRegistrationsForLeaderboard(leaderboardName,
|
||||
new AsyncCallback<Collection<CompetitorDTO>>() {
|
||||
@Override
|
||||
public void onSuccess(Collection<CompetitorDTO> result) {
|
||||
competitorTable.refreshCompetitorList(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError("Could not load competitors: " + caught.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static <T> void selectOrClear(SingleSelectionModel<T> selectionModel, T object) {
|
||||
if (object == null) {
|
||||
selectionModel.clear();
|
||||
} else {
|
||||
selectionModel.setSelected(object, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid programmatic deselections that re-trigger the selection listeners and lead to a loop.
|
||||
*/
|
||||
private void select() {
|
||||
if (inInstableTransitionState) {
|
||||
if (deviceIdTable.getSelectionModel().getSelectedObject() == deviceToSelect
|
||||
&& competitorTable.getSelectionModel().getSelectedObject() == compToSelect
|
||||
&& markTable.getSelectionModel().getSelectedObject() == markToSelect) {
|
||||
inInstableTransitionState = false;
|
||||
}
|
||||
} else {
|
||||
inInstableTransitionState = true;
|
||||
selectOrClear(deviceIdTable.getSelectionModel(), deviceToSelect);
|
||||
selectOrClear(competitorTable.getSelectionModel(), compToSelect);
|
||||
selectOrClear(markTable.getSelectionModel(), markToSelect);
|
||||
}
|
||||
}
|
||||
|
||||
private void mappedToSelectionChanged(MappableToDevice mappedTo) {
|
||||
if (!inInstableTransitionState) {
|
||||
TrackFileImportDeviceIdentifierDTO device = deviceIdTable.getSelectionModel().getSelectedObject();
|
||||
if (device != null) {
|
||||
mappings.put(device, mappedTo);
|
||||
}
|
||||
|
||||
if (mappedTo instanceof CompetitorDTO) {
|
||||
markToSelect = null;
|
||||
compToSelect = (CompetitorDTO) mappedTo;
|
||||
} else {
|
||||
compToSelect = null;
|
||||
markToSelect = (MarkDTO) mappedTo;
|
||||
}
|
||||
}
|
||||
select();
|
||||
validateAndUpdate();
|
||||
}
|
||||
|
||||
private void deviceSelectionChanged(TrackFileImportDeviceIdentifierDTO deviceId) {
|
||||
if (!inInstableTransitionState) {
|
||||
deviceToSelect = deviceId;
|
||||
compToSelect = null;
|
||||
markToSelect = null;
|
||||
|
||||
if (deviceId != null) {
|
||||
MappableToDevice mappedTo = mappings.get(deviceId);
|
||||
if (mappedTo instanceof CompetitorDTO) {
|
||||
compToSelect = (CompetitorDTO) mappedTo;
|
||||
} else if (mappedTo instanceof MarkDTO) {
|
||||
markToSelect = (MarkDTO) mappedTo;
|
||||
}
|
||||
}
|
||||
}
|
||||
select();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Widget getAdditionalWidget() {
|
||||
HorizontalPanel panel = new HorizontalPanel();
|
||||
VerticalPanel leftPanel = new VerticalPanel();
|
||||
VerticalPanel tablesPanel = new VerticalPanel();
|
||||
CaptionPanel marksPanel = new CaptionPanel(stringMessages.mark());
|
||||
CaptionPanel competitorsPanel = new CaptionPanel(stringMessages.competitor());
|
||||
|
||||
leftPanel.add(importWidget);
|
||||
leftPanel.add(deviceIdTable);
|
||||
panel.add(leftPanel);
|
||||
panel.add(tablesPanel);
|
||||
tablesPanel.add(marksPanel);
|
||||
tablesPanel.add(competitorsPanel);
|
||||
|
||||
marksPanel.setContentWidget(markTable.asWidget());
|
||||
competitorsPanel.setContentWidget(competitorTable.asWidget());
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<DeviceMappingDTO> getResult() {
|
||||
List<DeviceMappingDTO> result = new ArrayList<>();
|
||||
for (TrackFileImportDeviceIdentifierDTO device : mappings.keySet()) {
|
||||
DeviceIdentifierDTO deviceIdDto = new DeviceIdentifierDTO("FILE", device.uuidAsString);
|
||||
MappableToDevice mappedTo = mappings.get(device);
|
||||
DeviceMappingDTO mapping = new DeviceMappingDTO(deviceIdDto, device.from, device.to, mappedTo, null);
|
||||
result.add(mapping);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-94
@@ -1,113 +1,26 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.CaptionPanel;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.google.gwt.view.client.SelectionChangeEvent;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.MappableToDevice;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.shared.DeviceIdentifierDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.TrackFileImportDeviceIdentifierDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.TypedDeviceMappingDTO;
|
||||
import com.sap.sse.gwt.client.ErrorReporter;
|
||||
import com.sap.sse.gwt.client.celltable.RefreshableSingleSelectionModel;
|
||||
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
|
||||
|
||||
public class RegattaLogImportSensorDataAndAddMappingsDialog extends DataEntryDialog<Collection<TypedDeviceMappingDTO>> {
|
||||
private final String leaderboardName;
|
||||
public class RegattaLogImportSensorDataAndAddMappingsDialog extends AbstractRegattaLogSensorDataAddMappingsDialog {
|
||||
private final SensorDataImportWidget importWidget;
|
||||
private final TrackFileImportDeviceIdentifierTableWrapper deviceIdTable;
|
||||
protected final CompetitorTableWrapper<RefreshableSingleSelectionModel<CompetitorDTO>> competitorTable;
|
||||
private final StringMessages stringMessages;
|
||||
|
||||
public RegattaLogImportSensorDataAndAddMappingsDialog(SailingServiceAsync sailingService,
|
||||
final ErrorReporter errorReporter, final StringMessages stringMessages, String leaderboardName,
|
||||
DialogCallback<Collection<TypedDeviceMappingDTO>> callback) {
|
||||
super(stringMessages.add(stringMessages.deviceMappings()), stringMessages.add(stringMessages.deviceMappings()),
|
||||
stringMessages.add(), stringMessages.cancel(),
|
||||
new DataEntryDialog.Validator<Collection<TypedDeviceMappingDTO>>() {
|
||||
@Override
|
||||
public String getErrorMessage(Collection<TypedDeviceMappingDTO> valueToValidate) {
|
||||
return valueToValidate.isEmpty() ? stringMessages.pleaseCreateAtLeastOneMappingForCompetitor() : null;
|
||||
}
|
||||
}, true, callback);
|
||||
this.stringMessages = stringMessages;
|
||||
deviceIdTable = new TrackFileImportDeviceIdentifierTableWrapper(sailingService, stringMessages, errorReporter);
|
||||
deviceIdTable.removeTrackNameColumn();
|
||||
|
||||
super(sailingService, errorReporter, stringMessages, leaderboardName, callback);
|
||||
|
||||
importWidget = new SensorDataImportWidget(deviceIdTable, stringMessages, sailingService, errorReporter);
|
||||
deviceIdTable.getSelectionModel().addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
|
||||
@Override
|
||||
public void onSelectionChange(SelectionChangeEvent event) {
|
||||
CompetitorDTO mappedComp = deviceIdTable.getMappedCompetitorForCurrentSelection();
|
||||
if (mappedComp != null) {
|
||||
competitorTable.getSelectionModel().setSelected(mappedComp, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
competitorTable = new CompetitorTableWrapper<>(sailingService, stringMessages, errorReporter,
|
||||
/* multiSelection */ false, /* enablePager */ true);
|
||||
competitorTable.getSelectionModel().addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
|
||||
@Override
|
||||
public void onSelectionChange(SelectionChangeEvent event) {
|
||||
deviceIdTable.didSelectCompetitorForMapping(competitorTable.getSelectionModel().getSelectedObject());
|
||||
validateAndUpdate();
|
||||
}
|
||||
});
|
||||
|
||||
this.leaderboardName = leaderboardName;
|
||||
|
||||
getCompetitorRegistrations(sailingService, errorReporter);
|
||||
setImportWidget(importWidget);
|
||||
}
|
||||
|
||||
void getCompetitorRegistrations(SailingServiceAsync sailingService, final ErrorReporter errorReporter) {
|
||||
sailingService.getCompetitorRegistrationsForLeaderboard(leaderboardName,
|
||||
new AsyncCallback<Collection<CompetitorDTO>>() {
|
||||
@Override
|
||||
public void onSuccess(Collection<CompetitorDTO> result) {
|
||||
competitorTable.refreshCompetitorList(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError("Could not load competitors: " + caught.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Widget getAdditionalWidget() {
|
||||
HorizontalPanel panel = new HorizontalPanel();
|
||||
VerticalPanel leftPanel = new VerticalPanel();
|
||||
VerticalPanel tablesPanel = new VerticalPanel();
|
||||
CaptionPanel competitorsPanel = new CaptionPanel(stringMessages.competitor());
|
||||
leftPanel.add(importWidget);
|
||||
leftPanel.add(deviceIdTable);
|
||||
panel.add(leftPanel);
|
||||
panel.add(tablesPanel);
|
||||
tablesPanel.add(competitorsPanel);
|
||||
competitorsPanel.setContentWidget(competitorTable.asWidget());
|
||||
return panel;
|
||||
protected String getSelectedImporterType() {
|
||||
return importWidget.getSelectedImporterType();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<TypedDeviceMappingDTO> getResult() {
|
||||
List<TypedDeviceMappingDTO> result = new ArrayList<>();
|
||||
String dataType = importWidget.getSelectedImporterType();
|
||||
for (TrackFileImportDeviceIdentifierDTO device : deviceIdTable.getMappings().keySet()) {
|
||||
DeviceIdentifierDTO deviceIdDto = new DeviceIdentifierDTO("FILE", device.uuidAsString);
|
||||
MappableToDevice mappedTo = deviceIdTable.getMappings().get(device);
|
||||
result.add(new TypedDeviceMappingDTO(deviceIdDto, device.from, device.to, mappedTo, null, dataType));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.shared.TrackFileImportDeviceIdentifierDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.TypedDeviceMappingDTO;
|
||||
import com.sap.sse.gwt.client.ErrorReporter;
|
||||
|
||||
public class RegattaLogSensorDataAddMappingsDialog extends AbstractRegattaLogSensorDataAddMappingsDialog {
|
||||
private final String importerType;
|
||||
|
||||
public RegattaLogSensorDataAddMappingsDialog(SailingServiceAsync sailingService,
|
||||
final ErrorReporter errorReporter, final StringMessages stringMessages, String leaderboardName,
|
||||
Collection<TrackFileImportDeviceIdentifierDTO> importedDeviceIds, String importerType,
|
||||
DialogCallback<Collection<TypedDeviceMappingDTO>> callback) {
|
||||
super(sailingService, errorReporter, stringMessages, leaderboardName, callback);
|
||||
this.importerType = importerType;
|
||||
|
||||
deviceIdTable.getDataProvider().getList().addAll(importedDeviceIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSelectedImporterType() {
|
||||
return importerType;
|
||||
}
|
||||
}
|
||||
+26
-12
@@ -573,19 +573,33 @@ public class SmartphoneTrackingEventManagementPanel extends AbstractLeaderboardC
|
||||
}
|
||||
|
||||
private void denoteForRaceLogTracking(final StrippedLeaderboardDTO leaderboard) {
|
||||
sailingService.denoteForRaceLogTracking(leaderboard.name, new AsyncCallback<Void>() {
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
loadAndRefreshLeaderboard(leaderboard.name);
|
||||
updateRegattaConfigDesignerModeToByMarks(leaderboard.regattaName);
|
||||
raceColumnTableSelectionModel.clear();
|
||||
}
|
||||
final ChooseNameDenoteEventDialog dialog = new ChooseNameDenoteEventDialog(stringMessages,leaderboard,
|
||||
new DialogCallback<String>() {
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError("Could not denote for RaceLog tracking: " + caught.getMessage());
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public void ok(String prefix) {
|
||||
sailingService.denoteForRaceLogTracking(leaderboard.name, prefix, new AsyncCallback<Void>() {
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
loadAndRefreshLeaderboard(leaderboard.name);
|
||||
updateRegattaConfigDesignerModeToByMarks(leaderboard.regattaName);
|
||||
raceColumnTableSelectionModel.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter
|
||||
.reportError("Could not denote for RaceLog tracking: " + caught.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
}
|
||||
});
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private void updateRegattaConfigDesignerModeToByMarks(final String regattaName) {
|
||||
|
||||
Executable → Regular
+71
@@ -44,6 +44,7 @@ import com.google.gwt.user.client.ui.Hidden;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.Panel;
|
||||
import com.google.gwt.user.client.ui.SuggestBox;
|
||||
import com.google.gwt.user.client.ui.TabPanel;
|
||||
import com.google.gwt.user.client.ui.TextBox;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
@@ -54,7 +55,10 @@ import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.common.dto.RaceDTO;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceImpl;
|
||||
import com.sap.sailing.gwt.common.client.suggestion.BoatClassMasterdataSuggestOracle;
|
||||
import com.sap.sailing.gwt.ui.adminconsole.WindImportResult.RaceEntry;
|
||||
import com.sap.sailing.gwt.ui.adminconsole.resulthandling.ExpeditionDataImportResponse;
|
||||
import com.sap.sailing.gwt.ui.adminconsole.resulthandling.ExpeditionDataImportResultsDialog;
|
||||
import com.sap.sailing.gwt.ui.client.RegattaRefresher;
|
||||
import com.sap.sailing.gwt.ui.client.RegattasDisplayer;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
@@ -70,6 +74,8 @@ import com.sap.sse.gwt.client.ErrorReporter;
|
||||
import com.sap.sse.gwt.client.async.AsyncActionsExecutor;
|
||||
import com.sap.sse.gwt.client.celltable.BaseCelltable;
|
||||
import com.sap.sse.gwt.client.celltable.RefreshableMultiSelectionModel;
|
||||
import com.sap.sse.gwt.client.controls.busyindicator.BusyIndicator;
|
||||
import com.sap.sse.gwt.client.controls.busyindicator.SimpleBusyIndicator;
|
||||
import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback;
|
||||
|
||||
/**
|
||||
@@ -85,7 +91,9 @@ public class WindPanel extends FormPanel implements RegattasDisplayer, WindShowe
|
||||
private static final String WIND_IMPORT_PARAMETER_RACES = "races";
|
||||
|
||||
private static final String EXPEDITON_IMPORT_PARAMETER_BOAT_ID = "boatId";
|
||||
private static final String EXPEDITON_IMPORT_PARAMETER_BOAT_CLASS = "boatClass";
|
||||
|
||||
private static final String URL_SAILINGSERVER_EXPEDITION_FULL_IMPORT = "/../../sailingserver/expedition/import";
|
||||
private static final String URL_SAILINGSERVER_EXPEDITION_IMPORT = "/../../sailingserver/expedition-import";
|
||||
private static final String URL_SAILINGSERVER_GRIB_IMPORT = "/../../sailingserver/grib-wind-import";
|
||||
private static final String URL_SAILINGSERVER_NMEA_IMPORT = "/../../sailingserver/nmea-wind-import";
|
||||
@@ -264,6 +272,7 @@ public class WindPanel extends FormPanel implements RegattasDisplayer, WindShowe
|
||||
mainPanel.add(createNmeaWindImportPanel());
|
||||
mainPanel.add(createBravoWindImportPanel());
|
||||
mainPanel.add(createIgtimiWindImportPanel(mainPanel));
|
||||
mainPanel.add(createExpeditionAllInOneImportPanel());
|
||||
}
|
||||
|
||||
private CaptionPanel createIgtimiWindImportPanel(VerticalPanel mainPanel) {
|
||||
@@ -439,6 +448,68 @@ public class WindPanel extends FormPanel implements RegattasDisplayer, WindShowe
|
||||
return new WindImportFileUploadForm(form, formContentPanel, fileUpload, submitButton);
|
||||
}
|
||||
|
||||
private CaptionPanel createExpeditionAllInOneImportPanel() {
|
||||
final CaptionPanel rootPanel = new CaptionPanel(stringMessages.importFullExpeditionData());
|
||||
final FormPanel formPanel = new FormPanel();
|
||||
final BusyIndicator busyIndicator = new SimpleBusyIndicator();
|
||||
final Button uploadButton = new Button(stringMessages.upload());
|
||||
uploadButton.addClickHandler(event -> {
|
||||
uploadButton.setEnabled(false);
|
||||
busyIndicator.setBusy(true);
|
||||
formPanel.submit();
|
||||
});
|
||||
formPanel.setMethod(FormPanel.METHOD_POST);
|
||||
formPanel.setEncoding(FormPanel.ENCODING_MULTIPART);
|
||||
formPanel.setAction(GWT.getHostPageBaseURL() + URL_SAILINGSERVER_EXPEDITION_FULL_IMPORT);
|
||||
formPanel.addSubmitCompleteHandler(event -> {
|
||||
uploadButton.setEnabled(true);
|
||||
busyIndicator.setBusy(false);
|
||||
final ExpeditionDataImportResponse response = ExpeditionDataImportResponse.parse(event.getResults());
|
||||
if (response.hasEventId()) {
|
||||
new ExpeditionAllInOneAfterImportHandler(response.getEventId(), response.getRegattaName(),
|
||||
response.getLeaderboardGroupName(), response.getLeaderboardName(), response.getRaceName(),
|
||||
response.getRaceColumnName(), response.getFleetName(), response.getGpsDeviceIds(),
|
||||
response.getSensorDeviceIds(), response.getSensorFixImporterType(), sailingService,
|
||||
errorReporter, stringMessages);
|
||||
} else {
|
||||
ExpeditionDataImportResultsDialog.showResults(response);
|
||||
}
|
||||
});
|
||||
rootPanel.add(formPanel);
|
||||
final VerticalPanel contentPanel = new VerticalPanel();
|
||||
formPanel.add(contentPanel);
|
||||
final FileUpload fileUpload = new FileUpload();
|
||||
fileUpload.setName("upload");
|
||||
contentPanel.add(fileUpload);
|
||||
final HorizontalPanel boatClassPanel = new HorizontalPanel();
|
||||
boatClassPanel.setSpacing(5);
|
||||
contentPanel.add(boatClassPanel);
|
||||
final Label boatClassLabel = new Label(stringMessages.boatClass() + ":");
|
||||
boatClassPanel.add(boatClassLabel);
|
||||
boatClassPanel.setCellVerticalAlignment(boatClassLabel, HasVerticalAlignment.ALIGN_MIDDLE);
|
||||
final SuggestBox boatClassInput = new SuggestBox(new BoatClassMasterdataSuggestOracle());
|
||||
boatClassInput.getValueBox().setName(EXPEDITON_IMPORT_PARAMETER_BOAT_CLASS);
|
||||
boatClassPanel.add(boatClassInput);
|
||||
boatClassPanel.setCellVerticalAlignment(boatClassInput, HasVerticalAlignment.ALIGN_MIDDLE);
|
||||
final HorizontalPanel controlPanel = new HorizontalPanel();
|
||||
controlPanel.setSpacing(5);
|
||||
controlPanel.add(uploadButton);
|
||||
controlPanel.add(busyIndicator);
|
||||
contentPanel.add(controlPanel);
|
||||
final Runnable validation = () -> {
|
||||
final String filename = fileUpload.getFilename(), boatClass = boatClassInput.getValue();
|
||||
final boolean fileValid = filename != null && !filename.trim().isEmpty();
|
||||
final boolean boatClassValid = boatClass != null && !boatClass.trim().isEmpty();
|
||||
uploadButton.setEnabled(fileValid && boatClassValid);
|
||||
};
|
||||
|
||||
fileUpload.addChangeHandler(event -> validation.run());
|
||||
boatClassInput.addSelectionHandler(event -> validation.run());
|
||||
boatClassInput.addKeyUpHandler(event -> validation.run());
|
||||
validation.run();
|
||||
return rootPanel;
|
||||
}
|
||||
|
||||
private CaptionPanel createExpeditionWindImportPanel() {
|
||||
/*
|
||||
* To style the "browse" button of the file upload widget
|
||||
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole.resulthandling;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.google.gwt.core.client.JavaScriptObject;
|
||||
import com.google.gwt.core.client.JsArray;
|
||||
import com.google.gwt.core.client.JsArrayString;
|
||||
import com.google.gwt.json.client.JSONParser;
|
||||
|
||||
/**
|
||||
* Abstract super-class for data import response overlay type providing convenience methods.
|
||||
*/
|
||||
class AbstractDataImportResponse extends JavaScriptObject {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AbstractDataImportResponse.class.getName());
|
||||
|
||||
/**
|
||||
* Extracts {@link ErrorMessage}s contained in this {@link JavaScriptObject JavaScript object}'s <i>errors</i>
|
||||
* field.
|
||||
*
|
||||
* @return the {@link List} of contained {@link ErrorMessage}s or an empty list if the <i>errors</i> field is
|
||||
* <code>undefined</code> or empty
|
||||
*
|
||||
* @see #getJsObjectList(String)
|
||||
*/
|
||||
public final List<ErrorMessage> getErrors() {
|
||||
return getJsObjectList("errors");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this {@link JavaScriptObject JavaScript object} contained errors.
|
||||
*
|
||||
* @return <code>true</code> if the {@link #getErrors() error list} is neither <code>null</code> nor empty,
|
||||
* <code>false</code> otherwise
|
||||
* @see #getErrors()
|
||||
*/
|
||||
public final boolean hasErrors() {
|
||||
final List<ErrorMessage> errors = getErrors();
|
||||
return errors != null && !errors.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JSONParser#parseStrict(String) Strictly parses} the provided {@link String} representation into JSON and
|
||||
* {@link JavaScriptObject#cast() casts} it to the desired type.
|
||||
*
|
||||
* @param json
|
||||
* {@link String} representation to parse into JSON
|
||||
* @param typeString
|
||||
* {@link String} name of the actually desired type
|
||||
* @return the parsed and casted object or <code>null</code> if any {@link Exception exception} occurs
|
||||
*/
|
||||
protected static final <T extends AbstractDataImportResponse> T parse(String json, String typeString) {
|
||||
try {
|
||||
return JSONParser.parseStrict(json).isObject().getJavaScriptObject().cast();
|
||||
} catch (Exception e) {
|
||||
logger.severe(() -> "Failed to parse import response to type " + typeString);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected AbstractDataImportResponse() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the field with the provided name representing a {@link JsArrayString JavaScript array of strings} from
|
||||
* this {@link JavaScriptObject JavaScript object} and maps the contained {@link String string} elements into a
|
||||
* {@link List list} by keeping their order.
|
||||
*
|
||||
* @param fieldName
|
||||
* the {@String name} of the field representing a {@link JsArrayString JavaScript array of strings}
|
||||
* @return the {@link List list} containing {@link String string} elements or an empty list if the field is
|
||||
* <code>undefined</code> or empty
|
||||
*/
|
||||
protected final List<String> getStringList(final String fieldName) {
|
||||
final JsArrayString array = arrayString(fieldName);
|
||||
if (array == null || array.length() == 0) {
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
final List<String> list = new ArrayList<>(array.length());
|
||||
for (int index = 0; index < array.length(); index++) {
|
||||
list.add(array.get(index));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the field with the provided name representing a {@link JsArray JavaScript array} containing any type of
|
||||
* {@link JavaScriptObject JavaScript object}s from this {@link JavaScriptObject JavaScript object} and maps the
|
||||
* contained elements into a {@link List list} of the same type by keeping their order.
|
||||
*
|
||||
* @param fieldName
|
||||
* the {@String name} of the field representing a {@link JsArray JavaScript array} containing any type of
|
||||
* {@link JavaScriptObject JavaScript object}s
|
||||
* @return the {@link List list} containing {@link String string} elements or an empty list if the field is
|
||||
* <code>undefined</code> or empty
|
||||
*/
|
||||
protected final <T extends JavaScriptObject> List<T> getJsObjectList(final String fieldName) {
|
||||
final JsArray<T> array = arrayJsObject(fieldName);
|
||||
if (array == null || array.length() == 0) {
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
final List<T> list = new ArrayList<>(array.length());
|
||||
for (int index = 0; index < array.length(); index++) {
|
||||
list.add(array.get(index));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
private final native <T extends JavaScriptObject> JsArray<T> arrayJsObject(String fieldName) /*-{
|
||||
return this[fieldName];
|
||||
}-*/;
|
||||
|
||||
private final native JsArrayString arrayString(String fieldName) /*-{
|
||||
return this[fieldName];
|
||||
}-*/;
|
||||
|
||||
/**
|
||||
* Extracts the field with the provided name representing a {@link String string} from this {@link JavaScriptObject
|
||||
* JavaScript object}.
|
||||
*
|
||||
* @param fieldName
|
||||
* the {@String name} of the field representing a {@link String string}
|
||||
* @return the {@link String string} or <code>null</code> if the field is <code>undefined</code>
|
||||
*/
|
||||
protected final native String getString(String fieldName) /*-{
|
||||
return this[fieldName];
|
||||
}-*/;
|
||||
|
||||
static class ErrorMessage extends JavaScriptObject {
|
||||
|
||||
protected ErrorMessage() {
|
||||
}
|
||||
|
||||
public final native String getExUUID() /*-{
|
||||
return this.exUUID;
|
||||
}-*/;
|
||||
|
||||
public final native String getFilename() /*-{
|
||||
return this.filename;
|
||||
}-*/;
|
||||
|
||||
public final native String getRequestedImporter() /*-{
|
||||
return this.requestedImporter;
|
||||
}-*/;
|
||||
|
||||
public final native String getClassName() /*-{
|
||||
return this.className;
|
||||
}-*/;
|
||||
|
||||
public final native String getMessage() /*-{
|
||||
return this.message;
|
||||
}-*/;
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole.resulthandling;
|
||||
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.DialogBox;
|
||||
import com.google.gwt.user.client.ui.HTML;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.sap.sailing.gwt.ui.adminconsole.resulthandling.AbstractDataImportResponse.ErrorMessage;
|
||||
|
||||
public class AbstractDataImportResultDialog {
|
||||
|
||||
protected static final String DIV_BOLD = "<div style='font-weight:bold;'>", DIV_END = "</div>";
|
||||
protected static final String DIV_MARGIN = "<div style='margin:40px;'>", UL = "<ul>", UL_END = "</ul>";
|
||||
protected static final String LI = "<li>", LI_END = "</liv>", P = "<p>", P_END = "</p>";
|
||||
|
||||
protected static void appendErrorMessagesIfPresent(SafeHtmlBuilder builder, AbstractDataImportResponse response) {
|
||||
if (response.hasErrors()) {
|
||||
appendParagraph(builder, "Error messages");
|
||||
response.getErrors().forEach(errorMessage -> appendErrorMessage(builder, errorMessage));
|
||||
}
|
||||
}
|
||||
|
||||
protected static void appendErrorMessage(SafeHtmlBuilder builder, ErrorMessage errorMessage) {
|
||||
builder.appendHtmlConstant(DIV_BOLD).appendEscaped(errorMessage.getMessage()).appendHtmlConstant(DIV_END);
|
||||
builder.appendHtmlConstant(UL);
|
||||
appendLineItemIfValueNotNull(builder, "ServerLog UUID", errorMessage.getExUUID());
|
||||
appendLineItemIfValueNotNull(builder, "Exception Classname", errorMessage.getClassName());
|
||||
appendLineItemIfValueNotNull(builder, "Filename", errorMessage.getFilename());
|
||||
appendLineItemIfValueNotNull(builder, "Requested Importer", errorMessage.getRequestedImporter());
|
||||
builder.appendHtmlConstant(UL_END);
|
||||
}
|
||||
|
||||
protected static void appendParagraph(SafeHtmlBuilder builder, String text) {
|
||||
builder.appendHtmlConstant(P).appendEscaped(text).appendHtmlConstant(P_END);
|
||||
}
|
||||
|
||||
protected static void appendLineItem(SafeHtmlBuilder builder, String text) {
|
||||
builder.appendHtmlConstant(LI).appendEscaped(text).appendHtmlConstant(LI_END);
|
||||
}
|
||||
|
||||
protected static void appendLineItemIfValueNotNull(SafeHtmlBuilder builder, String label, String value) {
|
||||
if (value != null && !value.isEmpty()) {
|
||||
builder.appendHtmlConstant(LI);
|
||||
builder.appendEscaped(label).appendEscaped(": ").appendEscaped(value);
|
||||
builder.appendHtmlConstant(LI_END);
|
||||
}
|
||||
}
|
||||
|
||||
protected static void show(SafeHtmlBuilder builder) {
|
||||
final DialogBox errorBox = new DialogBox(false, true);
|
||||
final VerticalPanel content = new VerticalPanel();
|
||||
content.add(new HTML(builder.toSafeHtml()));
|
||||
final Button close = new Button("Close", (ClickHandler) e -> errorBox.hide());
|
||||
content.add(close);
|
||||
content.setSpacing(10);
|
||||
errorBox.setGlassEnabled(true);
|
||||
errorBox.setWidget(content);
|
||||
errorBox.center();
|
||||
}
|
||||
|
||||
}
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole.resulthandling;
|
||||
|
||||
|
||||
import com.google.gwt.core.client.JavaScriptObject;
|
||||
|
||||
public class ErrorMessage extends JavaScriptObject {
|
||||
|
||||
protected ErrorMessage() {
|
||||
}
|
||||
|
||||
public final native String getExUUID() /*-{
|
||||
return this.exUUID;
|
||||
}-*/;
|
||||
public final native String getFilename() /*-{
|
||||
return this.filename;
|
||||
}-*/;
|
||||
public final native String getRequestedImporter() /*-{
|
||||
return this.requestedImporter;
|
||||
}-*/;
|
||||
|
||||
public final native String getClassName() /*-{
|
||||
return this.className;
|
||||
}-*/;
|
||||
|
||||
public final native String getMessage() /*-{
|
||||
return this.message;
|
||||
}-*/;
|
||||
|
||||
}
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole.resulthandling;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ExpeditionDataImportResponse extends AbstractDataImportResponse {
|
||||
|
||||
public static final ExpeditionDataImportResponse parse(String json) {
|
||||
return AbstractDataImportResponse.parse(json, "ExpeditionDataImportResponse");
|
||||
}
|
||||
|
||||
protected ExpeditionDataImportResponse() {
|
||||
}
|
||||
|
||||
public final UUID getEventId() {
|
||||
String eventId = getString("eventId");
|
||||
return eventId == null ? null : UUID.fromString(eventId);
|
||||
}
|
||||
|
||||
public final native String getLeaderboardGroupName() /*-{
|
||||
return this.leaderboardGroupName;
|
||||
}-*/;
|
||||
|
||||
public final native String getLeaderboardName() /*-{
|
||||
return this.leaderboardName;
|
||||
}-*/;
|
||||
|
||||
public final native String getRegattaName() /*-{
|
||||
return this.regattaName;
|
||||
}-*/;
|
||||
|
||||
public final native String getRaceName() /*-{
|
||||
return this.raceName;
|
||||
}-*/;
|
||||
|
||||
public final native String getRaceColumnName() /*-{
|
||||
return this.raceColumnName;
|
||||
}-*/;
|
||||
|
||||
public final native String getFleetName() /*-{
|
||||
return this.fleetName;
|
||||
}-*/;
|
||||
|
||||
public final List<String> getGpsDeviceIds() {
|
||||
return getStringList("gpsDeviceIds");
|
||||
}
|
||||
|
||||
public final List<String> getSensorDeviceIds() {
|
||||
return getStringList("sensorDeviceIds");
|
||||
}
|
||||
|
||||
public final native String getSensorFixImporterType() /*-{
|
||||
return this.sensorFixImporterType;
|
||||
}-*/;
|
||||
|
||||
public final boolean hasEventId() {
|
||||
final String stringValue = getString("eventId");
|
||||
return stringValue != null && !stringValue.isEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole.resulthandling;
|
||||
|
||||
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
|
||||
|
||||
public class ExpeditionDataImportResultsDialog extends AbstractDataImportResultDialog {
|
||||
|
||||
public static void showResults(ExpeditionDataImportResponse response) {
|
||||
if (response.hasErrors()) {
|
||||
final SafeHtmlBuilder builder = new SafeHtmlBuilder();
|
||||
builder.appendHtmlConstant(DIV_MARGIN);
|
||||
appendErrorMessagesIfPresent(builder, response);
|
||||
builder.appendHtmlConstant(DIV_END);
|
||||
show(builder);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+4
-48
@@ -1,67 +1,23 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole.resulthandling;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.google.gwt.core.client.JavaScriptObject;
|
||||
import com.google.gwt.core.client.JsArray;
|
||||
import com.google.gwt.json.client.JSONParser;
|
||||
|
||||
public class SensorDataImportResponse extends JavaScriptObject {
|
||||
private static final Logger logger = Logger.getLogger(SensorDataImportResponse.class.getName());
|
||||
public class SensorDataImportResponse extends AbstractDataImportResponse {
|
||||
|
||||
public static final SensorDataImportResponse parse(String json) {
|
||||
try {
|
||||
return (SensorDataImportResponse) JSONParser.parseStrict(json).isObject().getJavaScriptObject();
|
||||
} catch (Exception e) {
|
||||
logger.severe("failed to parse result");
|
||||
return null;
|
||||
}
|
||||
return AbstractDataImportResponse.parse(json, "SensorDataImportResponse");
|
||||
}
|
||||
|
||||
protected SensorDataImportResponse() {
|
||||
}
|
||||
|
||||
public final List<String> getUploads() {
|
||||
final String[] uploads = uploads();
|
||||
if (uploads == null || uploads.length == 0) {
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
return Arrays.asList(uploads);
|
||||
}
|
||||
return getStringList("uploads");
|
||||
}
|
||||
|
||||
public final List<ErrorMessage> getErrors() {
|
||||
final JsArray<ErrorMessage> errors = errors();
|
||||
if (errors == null || errors.length() == 0) {
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
final ArrayList<ErrorMessage> errorsAsList = new ArrayList<>(errors.length());
|
||||
for (int i = 0; i < errors.length(); i++) {
|
||||
errorsAsList.add(errors.get(i));
|
||||
}
|
||||
return errorsAsList;
|
||||
}
|
||||
}
|
||||
|
||||
private final native String[] uploads() /*-{
|
||||
return this.uploads;
|
||||
}-*/;
|
||||
|
||||
private final native JsArray<ErrorMessage> errors() /*-{
|
||||
return this.errors;
|
||||
}-*/;
|
||||
|
||||
public final boolean didSucceedImportingAnyFile() {
|
||||
return getUploads() != null && getUploads().size() > 0;
|
||||
return getUploads() != null && !getUploads().isEmpty();
|
||||
}
|
||||
|
||||
public final boolean hasErrors() {
|
||||
final JsArray<ErrorMessage> errors = errors();
|
||||
return errors != null && errors.length() > 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-59
@@ -1,70 +1,26 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole.resulthandling;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.DialogBox;
|
||||
import com.google.gwt.user.client.ui.HTML;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
|
||||
public class SensorDataImportResultsDialog {
|
||||
public class SensorDataImportResultsDialog extends AbstractDataImportResultDialog {
|
||||
|
||||
public static void showResults(SensorDataImportResponse response) {
|
||||
if (!response.hasErrors()) {
|
||||
return;
|
||||
}
|
||||
List<ErrorMessage> errorMessages = response.getErrors();
|
||||
SafeHtmlBuilder shb = new SafeHtmlBuilder();
|
||||
shb.appendHtmlConstant("<div style='margin:40px;'>");
|
||||
if (response.didSucceedImportingAnyFile()) {
|
||||
shb.appendHtmlConstant("<p>Succesful uploads</p>");
|
||||
shb.appendHtmlConstant("<ul>");
|
||||
for (String uuid : response.getUploads()) {
|
||||
shb.appendHtmlConstant(" <li >").appendEscaped(uuid).appendHtmlConstant("</li>");
|
||||
}
|
||||
shb.appendHtmlConstant("</ul>");
|
||||
} else {
|
||||
shb.appendHtmlConstant("<p>No succesful upload</p>");
|
||||
}
|
||||
if (response.hasErrors()) {
|
||||
shb.appendHtmlConstant("<p>Error messages</p>");
|
||||
for (ErrorMessage errorMsg : errorMessages) {
|
||||
shb.appendHtmlConstant("<div style='font-weight:bold;'>").appendEscaped(errorMsg.getMessage())
|
||||
.appendHtmlConstant("</div>");
|
||||
shb.appendHtmlConstant("<ul>");
|
||||
if (!isNullOrEmpty(errorMsg.getExUUID())) {
|
||||
shb.appendHtmlConstant(" <li>ServerLog UUID: ").appendEscaped(errorMsg.getExUUID())
|
||||
.appendHtmlConstant("</li>");
|
||||
}
|
||||
if (!isNullOrEmpty(errorMsg.getClassName())) {
|
||||
shb.appendHtmlConstant(" <li>Exception Classname: ").appendEscaped(errorMsg.getClassName())
|
||||
.appendHtmlConstant("</li>");
|
||||
}
|
||||
if (!isNullOrEmpty(errorMsg.getFilename())) {
|
||||
shb.appendHtmlConstant(" <li>Filename: ").appendEscaped(errorMsg.getFilename())
|
||||
.appendHtmlConstant("</li>");
|
||||
}
|
||||
if (!isNullOrEmpty(errorMsg.getRequestedImporter())) {
|
||||
shb.appendHtmlConstant(" <li>Requested Importer: ").appendEscaped(errorMsg.getRequestedImporter())
|
||||
.appendHtmlConstant("</li>");
|
||||
}
|
||||
shb.appendHtmlConstant("</ul>");
|
||||
final SafeHtmlBuilder builder = new SafeHtmlBuilder();
|
||||
builder.appendHtmlConstant(DIV_MARGIN);
|
||||
if (response.didSucceedImportingAnyFile()) {
|
||||
appendParagraph(builder, "Succesful uploads");
|
||||
builder.appendHtmlConstant(UL);
|
||||
response.getUploads().forEach(uuid -> appendLineItem(builder, uuid));
|
||||
builder.appendHtmlConstant(UL_END);
|
||||
} else {
|
||||
appendParagraph(builder, "No succesful upload!");
|
||||
}
|
||||
appendErrorMessagesIfPresent(builder, response);
|
||||
|
||||
builder.appendHtmlConstant(DIV_END);
|
||||
show(builder);
|
||||
}
|
||||
shb.appendHtmlConstant("</div>");
|
||||
final DialogBox errorBox = new DialogBox(false, true);
|
||||
VerticalPanel vp = new VerticalPanel();
|
||||
vp.add(new HTML(shb.toSafeHtml()));
|
||||
Button close = new Button("Close");
|
||||
close.addClickHandler(e -> errorBox.hide());
|
||||
vp.add(close);
|
||||
vp.setSpacing(10);
|
||||
errorBox.setGlassEnabled(true);
|
||||
errorBox.setWidget(vp);
|
||||
errorBox.center();
|
||||
}
|
||||
|
||||
private static boolean isNullOrEmpty(String text) {
|
||||
return text == null || text.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -38,4 +38,8 @@ public class EntryPointLinkFactory extends AbstractEntryPointLinkFactory {
|
||||
public static String createDashboardLink(Map<String, String> parameters) {
|
||||
return createEntryPointLink("/dashboards/RibDashboard.html", parameters);
|
||||
}
|
||||
|
||||
public static String createPairingListLink(Map<String, String> parameters) {
|
||||
return createEntryPointLink("/gwt/PairingList.html", parameters);
|
||||
}
|
||||
}
|
||||
|
||||
+19
-4
@@ -35,6 +35,8 @@ import com.sap.sailing.domain.common.dto.BoatDTO;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.domain.common.dto.FleetDTO;
|
||||
import com.sap.sailing.domain.common.dto.IncrementalOrFullLeaderboardDTO;
|
||||
import com.sap.sailing.domain.common.dto.PairingListDTO;
|
||||
import com.sap.sailing.domain.common.dto.PairingListTemplateDTO;
|
||||
import com.sap.sailing.domain.common.dto.PersonDTO;
|
||||
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
|
||||
import com.sap.sailing.domain.common.dto.RaceColumnInSeriesDTO;
|
||||
@@ -241,12 +243,8 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
|
||||
boolean firstRaceIsNonDiscardableCarryForward, boolean hasSplitFleetScore, Integer maximumNumberOfDiscards,
|
||||
List<FleetDTO> fleets);
|
||||
|
||||
RaceColumnInSeriesDTO addRaceColumnToSeries(RegattaIdentifier regattaIdentifier, String seriesName, String columnName);
|
||||
|
||||
void removeRaceColumnsFromSeries(RegattaIdentifier regattaIdentifier, String seriesName, List<String> columnNames);
|
||||
|
||||
void removeRaceColumnFromSeries(RegattaIdentifier regattaIdentifier, String seriesName, String columnName);
|
||||
|
||||
void moveRaceColumnInSeriesUp(RegattaIdentifier regattaIdentifier, String seriesName, String columnName);
|
||||
|
||||
void moveRaceColumnInSeriesDown(RegattaIdentifier regattaIdentifier, String seriesName, String columnName);
|
||||
@@ -482,6 +480,8 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
|
||||
|
||||
void denoteForRaceLogTracking(String leaderboardName) throws Exception;
|
||||
|
||||
void denoteForRaceLogTracking(String leaderboardName,String prefix) throws Exception;
|
||||
|
||||
/**
|
||||
* Performs all the necessary steps to start tracking the race.
|
||||
* The {@code RaceLog} needs to be denoted for racelog-tracking beforehand.
|
||||
@@ -694,4 +694,19 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
|
||||
void addOrReplaceExpeditionDeviceConfiguration(ExpeditionDeviceConfiguration expeditionDeviceConfiguration);
|
||||
|
||||
void removeExpeditionDeviceConfiguration(ExpeditionDeviceConfiguration expeditionDeviceConfiguration);
|
||||
|
||||
PairingListTemplateDTO calculatePairingListTemplate(final int flightCount, final int groupCount, final int competitorCount,
|
||||
final int flightMultiplier)
|
||||
throws NotFoundException, IllegalArgumentException;
|
||||
|
||||
PairingListDTO getPairingListFromTemplate(String leaderboardName, int flightMultiplier,
|
||||
Iterable<String> selectedFlightNames, PairingListTemplateDTO templateDTO) throws NotFoundException;
|
||||
|
||||
PairingListDTO getPairingListFromRaceLogs(String leaderboardName) throws NotFoundException;
|
||||
|
||||
void fillRaceLogsFromPairingListTemplate(String leaderboardName, int flightMultiplier,
|
||||
Iterable<String> selectedFlightNames, PairingListDTO pairingListDTO)
|
||||
throws NotFoundException, CompetitorRegistrationOnRaceLogDisabledException;
|
||||
|
||||
List<String> getRaceDisplayNamesFromLeaderboard(String leaderboardName, List<String> raceColumnNames) throws NotFoundException;
|
||||
}
|
||||
|
||||
+64
-7
@@ -15,6 +15,7 @@ import com.sap.sailing.domain.common.DetailType;
|
||||
import com.sap.sailing.domain.common.LeaderboardType;
|
||||
import com.sap.sailing.domain.common.LegIdentifier;
|
||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.NotFoundException;
|
||||
import com.sap.sailing.domain.common.PassingInstruction;
|
||||
import com.sap.sailing.domain.common.PolarSheetsXYDiagramData;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
@@ -30,6 +31,8 @@ import com.sap.sailing.domain.common.dto.BoatDTO;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.domain.common.dto.FleetDTO;
|
||||
import com.sap.sailing.domain.common.dto.IncrementalOrFullLeaderboardDTO;
|
||||
import com.sap.sailing.domain.common.dto.PairingListDTO;
|
||||
import com.sap.sailing.domain.common.dto.PairingListTemplateDTO;
|
||||
import com.sap.sailing.domain.common.dto.PersonDTO;
|
||||
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
|
||||
import com.sap.sailing.domain.common.dto.RaceColumnInSeriesDTO;
|
||||
@@ -100,6 +103,7 @@ import com.sap.sse.gwt.client.filestorage.FileStorageManagementGwtServiceAsync;
|
||||
import com.sap.sse.gwt.client.media.ImageDTO;
|
||||
import com.sap.sse.gwt.client.media.VideoDTO;
|
||||
import com.sap.sse.gwt.client.replication.RemoteReplicationServiceAsync;
|
||||
import com.sap.sse.pairinglist.PairingListTemplate;
|
||||
|
||||
/**
|
||||
* The async counterpart of {@link SailingService}
|
||||
@@ -436,12 +440,6 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan
|
||||
|
||||
void removeRegattas(Collection<RegattaIdentifier> regattas, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void addRaceColumnToSeries(RegattaIdentifier regattaIdentifier, String seriesName, String columnName,
|
||||
AsyncCallback<RaceColumnInSeriesDTO> callback);
|
||||
|
||||
void removeRaceColumnFromSeries(RegattaIdentifier regattaIdentifier, String seriesName, String columnName,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void moveRaceColumnInSeriesUp(RegattaIdentifier regattaIdentifier, String seriesName, String columnName,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
@@ -664,6 +662,8 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan
|
||||
AsyncCallback<Boolean> callback);
|
||||
|
||||
void denoteForRaceLogTracking(String leaderboardName, AsyncCallback<Void> callback);
|
||||
|
||||
void denoteForRaceLogTracking(String leaderboardName,String prefix, AsyncCallback<Void> callback);
|
||||
|
||||
void startRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName, boolean trackWind,
|
||||
boolean correctWindByDeclination, AsyncCallback<Void> callback);
|
||||
@@ -867,7 +867,64 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan
|
||||
|
||||
void getExpeditionDeviceConfigurations(AsyncCallback<List<ExpeditionDeviceConfiguration>> callback);
|
||||
|
||||
void removeExpeditionDeviceConfiguration(ExpeditionDeviceConfiguration expeditionDeviceConfiguration, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void addOrReplaceExpeditionDeviceConfiguration(ExpeditionDeviceConfiguration expeditionDeviceConfiguration, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void removeExpeditionDeviceConfiguration(ExpeditionDeviceConfiguration expeditionDeviceConfiguration, AsyncCallback<Void> asyncCallback);
|
||||
/**
|
||||
* Calculates a {@link PairingListTemplate} based on a competitor count, flight count and group count of the
|
||||
* leaderboard. Since the competitor count must not be the competitors that are registered on the leaderboard, it
|
||||
* can vary.
|
||||
*
|
||||
* @param leaderboardName
|
||||
* the name of the leaderboard
|
||||
* @param competitorCount
|
||||
* the count of competitors
|
||||
* @param flightMultiplier
|
||||
* specifies how often the flights will be cloned
|
||||
* @param callback
|
||||
* returns a {@link PairingListTemplateDTO}
|
||||
* @throws NotFoundException
|
||||
* is thrown if the leaderboard is not found by name
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
void calculatePairingListTemplate(final int flightCount, final int groupCount, final int competitorCount,
|
||||
final int flightMultiplier, AsyncCallback<PairingListTemplateDTO> callback)
|
||||
throws NotFoundException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Creates a {@link PairingListDTO} in which the competitors will be matched to a {@link PairingList} based on the
|
||||
* information that the {@link PairingListTemplate} contains.
|
||||
*
|
||||
* @param leaderboardName
|
||||
* @param flightMultiplier
|
||||
* specifies how often the flights will be cloned
|
||||
* @param callback
|
||||
*/
|
||||
void getPairingListFromTemplate(final String leaderboardName, final int flightMultiplier,
|
||||
final Iterable<String> selectedFlightNames,PairingListTemplateDTO templateDTO, AsyncCallback<PairingListDTO> callback);
|
||||
|
||||
/**
|
||||
* Creates a {@link PairingListDTO} that is based on the competitors in the race logs of a leaderboard.
|
||||
*
|
||||
* @param leaderboardName
|
||||
* the name of the leaderboard
|
||||
* @param callback
|
||||
* returns a {@link PairingListDTO}
|
||||
*/
|
||||
void getPairingListFromRaceLogs(final String leaderboardName, AsyncCallback<PairingListDTO> callback);
|
||||
|
||||
/**
|
||||
* Registers all competitors of a {@link PairingList} in the respective {@link RaceColumn}s and {@link Fleet}s.
|
||||
*
|
||||
* @param leaderboardName
|
||||
* the name of the leaderboard
|
||||
* @param flightMultiplier
|
||||
* specifies how often the flights will be cloned
|
||||
* @param callback
|
||||
*/
|
||||
void fillRaceLogsFromPairingListTemplate(final String leaderboardName, final int flightMultiplier,
|
||||
final Iterable<String> selectedFlightNames,PairingListDTO pairingListDTO, AsyncCallback<Void> callback);
|
||||
|
||||
void getRaceDisplayNamesFromLeaderboard(final String leaderboardName,List<String> raceColumnNames, AsyncCallback<List<String>> callback);
|
||||
}
|
||||
|
||||
+38
@@ -232,6 +232,31 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
|
||||
String noSelection();
|
||||
String raceIsKnownToStartUpwind();
|
||||
String events();
|
||||
String pairingList();
|
||||
String pairingLists();
|
||||
String pairingListCreationInfo();
|
||||
String setCompetitors();
|
||||
String seriesHint();
|
||||
String amountOfFlightRepeats();
|
||||
String insertIntoRegatta();
|
||||
String recalculate();
|
||||
String csvExport();
|
||||
String printView();
|
||||
String print();
|
||||
String invalidCompetitorCount();
|
||||
String invalidFlightMultiplier();
|
||||
String invalidSeriesSelection();
|
||||
String flightsMustBeAMultipleOfMultiplier();
|
||||
String parameters();
|
||||
String numberOfFlights();
|
||||
String numberOfFleets();
|
||||
String numberOfCompetitors();
|
||||
String quality();
|
||||
String pairingListTemplate();
|
||||
String printHint();
|
||||
String blockedApplyButton();
|
||||
String multiplierInfo();
|
||||
String noPairingListAvailable();
|
||||
String settingsForComponent(String localizedComponentName);
|
||||
String noEventsFound();
|
||||
String noEventSelected();
|
||||
@@ -342,6 +367,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
|
||||
String showWindSpeedSeries();
|
||||
String showWindDirectionSeries();
|
||||
String fleet();
|
||||
String boat();
|
||||
String boatClass();
|
||||
String setDelayToLive();
|
||||
String pleaseEnterNonEmptyVenue();
|
||||
@@ -1497,6 +1523,10 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
|
||||
String copyCourse();
|
||||
String copyCompetitors();
|
||||
String smartphoneTracking();
|
||||
String titelOfChooseNameDialog();
|
||||
String ownPrefix();
|
||||
String defaultName();
|
||||
String exampleTextForName();
|
||||
String flightsCount(@PluralCount(DefaultRule_1_0n.class) int count);
|
||||
String viewQueryDefinition();
|
||||
String queryDefinitionViewer();
|
||||
@@ -1989,4 +2019,12 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
|
||||
String threeSixtyVideoHint();
|
||||
String processingMP4();
|
||||
String resetStartTimeToDefault();
|
||||
String importFullExpeditionData();
|
||||
String importCanceledNoCompetitorAdded();
|
||||
String importCanceledByUser();
|
||||
String importFinished();
|
||||
String importFinishedMessage();
|
||||
String importFinishedGotoRaceboard();
|
||||
String importFinishedGotoEvent();
|
||||
String chooseAName();
|
||||
}
|
||||
|
||||
+42
-1
@@ -233,6 +233,34 @@ hoverOverAPoint=Hover over a point for details
|
||||
noSelection=No selection
|
||||
raceIsKnownToStartUpwind=Race starts with upwind leg
|
||||
events=Events
|
||||
pairingList=Pairing list
|
||||
pairingLists=Pairing lists
|
||||
pairingListCreationInfo=First of all a template will be calculated that contains only the competitor numbers and can be applied to other leaderboards. If the competitor count is not divisible by the boat count without remainder, empty placeholders will be entered into the pairing list. \
|
||||
\ In addition if the competitor count is unequal to the registered competitor count in the actual leaderboard, the pairing list cannot be applied to Race logs. \
|
||||
\ The count of the flights, that is used to generate a pairing list, is set by all flights of the leaderboard that are not medal races.
|
||||
setCompetitors=Please set the competitors count:
|
||||
seriesHint=Please select one or more series that should be in a PairingList:
|
||||
amountOfFlightRepeats=Number of flight repeats
|
||||
insertIntoRegatta=Insert into regatta
|
||||
recalculate=Recalculate
|
||||
csvExport=Export as CSV
|
||||
printView=Print preview
|
||||
print=Print
|
||||
invalidCompetitorCount=Invalid competitor count
|
||||
invalidFlightMultiplier=Invalid flight repeats
|
||||
invalidSeriesSelection=Invalid series selection
|
||||
flightsMustBeAMultipleOfMultiplier=Flights has to be a multiple of flight multiplier
|
||||
parameters=Parameters
|
||||
numberOfFlights=Number of flights
|
||||
numberOfFleets=Number of races per flight
|
||||
numberOfCompetitors=Number of competiors
|
||||
numberOfRaces=Number of races
|
||||
quality=Quality
|
||||
pairingListTemplate=Pairing list template
|
||||
printHint=Prints the applied version
|
||||
blockedApplyButton=Registered Competitors are unequal to Competitors from Pairinglist!
|
||||
multiplierInfo=Multipes flights and create them next to each other so that a competition with less boatchanges is possible
|
||||
noPairingListAvailable=The print function is only available when a pairing list has already been applied to the selected leaderboards race logs.
|
||||
settingsForComponent=Settings for {0}
|
||||
noEventsFound=No events were found
|
||||
noEventSelected=No event selected
|
||||
@@ -353,6 +381,7 @@ replicatingFromMaster=Replicating from master {0}:{2}, messaging port {3}:{1}, e
|
||||
showWindSpeedSeries=Show wind speed data
|
||||
showWindDirectionSeries=Show wind directions data
|
||||
fleet=Fleet
|
||||
boat=Boat
|
||||
boatClass=Boat Class
|
||||
setDelayToLive=Set delay to live
|
||||
pleaseEnterNonEmptyVenue=Please enter a venue.
|
||||
@@ -1465,6 +1494,10 @@ doYouWantToCreateADefaultRegattaLeaderboard=Do you want to create a default Rega
|
||||
copyCourse=Copy Course
|
||||
copyCompetitors=Copy Competitors
|
||||
smartphoneTracking=Smartphone Tracking
|
||||
titelOfChooseNameDialog=Choose a name
|
||||
ownPrefix=Own Prefix
|
||||
defaultName=Default
|
||||
exampleTextForName=Your name looks like:
|
||||
flightsCount={0,number} flights
|
||||
flightsCount[one]={0,number} flight
|
||||
viewQueryDefinition=View Query Definition
|
||||
@@ -1973,4 +2006,12 @@ totalDurationFoiledInSecondsTooltip=Total time foiled, across the entire leaderb
|
||||
totalDistanceFoiledInMetersTooltip=Total distance foiled, across the entire leaderboard
|
||||
threeSixtyVideoHint=This is a 360° video, the camera can be turned
|
||||
processingMP4=Mp4 is analyzed (this will take a few Seconds)
|
||||
resetStartTimeToDefault=Set to default
|
||||
resetStartTimeToDefault=Set to default
|
||||
importFullExpeditionData=Import full expedition data
|
||||
importCanceledNoCompetitorAdded=No competitor was added! Import will be canceled.
|
||||
importCanceledByUser=Import canceled!
|
||||
importFinished=Finished importing data
|
||||
importFinishedMessage=Successfully imported expedition data.
|
||||
importFinishedGotoRaceboard=Open raceboard
|
||||
importFinishedGotoEvent=Open event
|
||||
chooseAName=Choose a name
|
||||
+42
-1
@@ -235,6 +235,34 @@ hoverOverAPoint=Für Details Maus über dem Graph positionieren
|
||||
noSelection=Keine Selektion
|
||||
raceIsKnownToStartUpwind=Rennen beginnt mit Kreuz
|
||||
events=Veranstaltungen
|
||||
pairingList=Gegner Paarungsliste
|
||||
pairingLists=Gegner Paarungslisten
|
||||
pairingListCreationInfo=Es wird zunächst ein Template berechnet, das nur aus Zahlen besteht. Wenn die Teilnehmer Anzahl nicht durch die Anzahl der Boote dividiert werden kann, entstehen leere Plätze in der Pairing List. \
|
||||
\ Wenn außerdem die Anzahl der Teilnehmer nicht der auf der Rangliste registrierten Teilnehmer Anzahl entspricht, kann die Pairing List nicht in die Race Logs eingetragen werden. \
|
||||
\ Es wird eine Vereinigungsmenge aus allen Rennen, die keine Medallien Rennen sind, als Rennenanzahl für die Pairing List gebildet.
|
||||
setCompetitors=Anzahl der Teilnehmer:
|
||||
seriesHint=Bitte wählen Sie eine oder mehr Serien für die eine Paarungsliste aus:
|
||||
amountOfFlightRepeats=Anzahl der Flight Wiederholungen
|
||||
insertIntoRegatta=In Regatta einfügen
|
||||
recalculate=Neu berechnen
|
||||
csvExport=Export als CSV
|
||||
printView=Druckvorschau
|
||||
print=Drucken
|
||||
invalidCompetitorCount=Ungültige Teilnehmeranzahl
|
||||
invalidFlightMultiplier=Ungültige Flight Wiederholungen
|
||||
invalidSeriesSelection=Ungültige Serienauswahl
|
||||
flightsMustBeAMultipleOfMultiplier=Anzahl der Wettfahren muss ein Vielfaches vom Wiederholungsfaktor sein
|
||||
parameters=Parameter
|
||||
numberOfFlights=Anzahl der Flights
|
||||
numberOfFleets=Anzahl der Wettfahrten pro Flight
|
||||
numberOfCompetitors=Anzahl der Teilnehmer
|
||||
numberOfRaces=Anzahl der Wettfahrten
|
||||
quality=Qualität
|
||||
pairingListTemplate=Paarungsliste
|
||||
printHint=Druckt die aktuell angewendete Version!
|
||||
blockedApplyButton=Die Anzahl der Teilnehmer der Paarungliste ist ungleich den registrierten Teilnehmern!
|
||||
multiplierInfo=Vervielfacht die WEttfahrten und schreibt gleiche hintereinader um möglichst wenig Bootswechsel zu ermöglichen
|
||||
noPairingListAvailable=Die Druckfunktion ist erst möglich, wenn bereits eine Gegner Paarungsliste auf die Race Logs des ausgewählten Leaderbaord angewendet wurde.
|
||||
settingsForComponent=Einstellungen für {0}
|
||||
noEventsFound=Es wurden keine Rennen gefunden
|
||||
noEventSelected=Kein Rennen ausgewählt
|
||||
@@ -354,6 +382,7 @@ replicatingFromMaster=Repliziert von master {0}:{2}, Messaging Port {3}:{1}, Exc
|
||||
showWindSpeedSeries=Daten für Windgeschwindigkeit zeigen
|
||||
showWindDirectionSeries=Daten für Windrichtung zeigen
|
||||
fleet=Flotte
|
||||
boat=Boot
|
||||
boatClass=Bootsklasse
|
||||
setDelayToLive=Verzögerung zu ''Live'' setzen
|
||||
pleaseEnterNonEmptyVenue=Bitte geben sie einen Veranstaltungsort ein.
|
||||
@@ -1447,6 +1476,10 @@ doYouWantToCreateADefaultRegattaLeaderboard=Möchten Sie eine Standardrangliste
|
||||
copyCourse=Kurs kopieren
|
||||
copyCompetitors=Teilnehmer kopieren
|
||||
smartphoneTracking=Smartphone Tracking
|
||||
titelOfChooseNameDialog= Wählen sie einen Namen
|
||||
ownPrefix=Eigener Bezeichner
|
||||
defaultName=Standard
|
||||
exampleTextForName=Namen werden in dieser Form erstellt:
|
||||
flightsCount={0,number} Läufe
|
||||
flightsCount[one]={0,number} Lauf
|
||||
viewQueryDefinition=Query Definition anzeigen
|
||||
@@ -1967,4 +2000,12 @@ totalDurationFoiledInSecondsTooltip=Insgesamt gefoilte Zeit, über die gesamte
|
||||
totalDistanceFoiledInMetersTooltip=Insgesamt gefoilte Strecke, über die gesamte Ergebnisliste kumuliert
|
||||
threeSixtyVideoHint=Dies ist ein 360° Video, die Kamera ist drehbar
|
||||
processingMP4=Mp4 wird analysiert (dies Dauert einige Sekunden)
|
||||
resetStartTimeToDefault=Auf Standard zurücksetzten
|
||||
resetStartTimeToDefault=Auf Standard zurücksetzten
|
||||
importFullExpeditionData=Alle Expeditionsdaten importieren
|
||||
importCanceledNoCompetitorAdded=Es wurde kein Teilnehmer hinzugefügt! Der Import wird abgebrochen.
|
||||
importCanceledByUser=Import abgebrochen!
|
||||
importFinished=Importvorgang abgeschlossen
|
||||
importFinishedMessage=Erfolgreich Expeditionsdaten eingelesen
|
||||
importFinishedGotoRaceboard=Raceboard öffnen
|
||||
importFinishedGotoEvent=Event öffnen
|
||||
chooseAName=Namen auswählen
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.sap.sailing.gwt.ui.pairinglist;
|
||||
|
||||
import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings;
|
||||
import com.sap.sse.common.settings.generic.StringSetting;
|
||||
|
||||
public class PairingListContextDefinition extends AbstractGenericSerializableSettings {
|
||||
|
||||
private static final long serialVersionUID = 6206953942932913058L;
|
||||
|
||||
private transient StringSetting leaderboardName;
|
||||
|
||||
public PairingListContextDefinition() { }
|
||||
|
||||
public PairingListContextDefinition(String leaderboardName) {
|
||||
this.leaderboardName.setValue(leaderboardName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addChildSettings() {
|
||||
this.leaderboardName = new StringSetting("leaderboardName", this);
|
||||
}
|
||||
|
||||
public String getLeaderboardName() {
|
||||
return this.leaderboardName.getValue();
|
||||
}
|
||||
}
|
||||
+266
@@ -0,0 +1,266 @@
|
||||
package com.sap.sailing.gwt.ui.pairinglist;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.dom.client.Style;
|
||||
import com.google.gwt.dom.client.Style.TextAlign;
|
||||
import com.google.gwt.dom.client.Style.Unit;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.DockLayoutPanel;
|
||||
import com.google.gwt.user.client.ui.Grid;
|
||||
import com.google.gwt.user.client.ui.HTML;
|
||||
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.RootLayoutPanel;
|
||||
import com.google.gwt.user.client.ui.ScrollPanel;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.sap.sailing.domain.common.dto.BoatDTO;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTOImpl;
|
||||
import com.sap.sailing.domain.common.dto.PairingListDTO;
|
||||
import com.sap.sailing.gwt.common.authentication.FixedSailingAuthentication;
|
||||
import com.sap.sailing.gwt.common.authentication.SAPSailingHeaderWithAuthentication;
|
||||
import com.sap.sailing.gwt.ui.client.AbstractSailingEntryPoint;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
|
||||
import com.sap.sse.common.Color;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.gwt.settings.SettingsToUrlSerializer;
|
||||
|
||||
public class PairingListEntryPoint extends AbstractSailingEntryPoint {
|
||||
|
||||
private PairingListContextDefinition pairingListContextDefinition;
|
||||
|
||||
private StringMessages stringmessages = StringMessages.INSTANCE;
|
||||
private StrippedLeaderboardDTO strippedLeaderboardDTO;
|
||||
|
||||
@Override
|
||||
protected void doOnModuleLoad() {
|
||||
super.doOnModuleLoad();
|
||||
pairingListContextDefinition = new SettingsToUrlSerializer()
|
||||
.deserializeFromCurrentLocation(new PairingListContextDefinition());
|
||||
this.sailingService.getLeaderboard(pairingListContextDefinition.getLeaderboardName(),
|
||||
new AsyncCallback<StrippedLeaderboardDTO>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
strippedLeaderboardDTO = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(StrippedLeaderboardDTO result) {
|
||||
strippedLeaderboardDTO = result;
|
||||
createUI();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void createUI() {
|
||||
DockLayoutPanel mainPanel = new DockLayoutPanel(Unit.PX);
|
||||
ScrollPanel scrollPanel = new ScrollPanel();
|
||||
RootLayoutPanel.get().add(mainPanel);
|
||||
mainPanel.setWidth("100%");
|
||||
mainPanel.setHeight("100%");
|
||||
SAPSailingHeaderWithAuthentication header = new SAPSailingHeaderWithAuthentication(
|
||||
pairingListContextDefinition.getLeaderboardName());
|
||||
new FixedSailingAuthentication(getUserService(), header.getAuthenticationMenuView());
|
||||
mainPanel.addNorth(header, 75);
|
||||
|
||||
VerticalPanel contentPanel = new VerticalPanel();
|
||||
contentPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
|
||||
contentPanel.setWidth("100%");
|
||||
contentPanel.getElement().getStyle().setProperty("marginTop", "15px");
|
||||
contentPanel.getElement().getStyle().setProperty("marginBottom", "15px");
|
||||
scrollPanel.add(contentPanel);
|
||||
sailingService.getPairingListFromRaceLogs(pairingListContextDefinition.getLeaderboardName(),
|
||||
new AsyncCallback<PairingListDTO>() {
|
||||
|
||||
@Override
|
||||
public void onSuccess(PairingListDTO result) {
|
||||
if (strippedLeaderboardDTO != null) {
|
||||
sailingService.getRaceDisplayNamesFromLeaderboard(strippedLeaderboardDTO.getName(),
|
||||
result.getRaceColumnNames(), new AsyncCallback<List<String>>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
HTML lbl = new HTML(
|
||||
"<h2>" + stringmessages.noPairingListAvailable() + "</h2>");
|
||||
lbl.getElement().getStyle().setColor(Color.BLACK.toString());
|
||||
contentPanel.add(lbl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(List<String> names) {
|
||||
Button btn = new Button(getStringMessages().print());
|
||||
contentPanel.add(btn);
|
||||
VerticalPanel pairingListPanel = createPairingListPanel(result, names);
|
||||
contentPanel.add(pairingListPanel);
|
||||
btn.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
printPairingListGrid(
|
||||
"<div class='printHeader'><img src='images/home/logo-small@2x.png' </img>"
|
||||
+ "<b class='title'>"
|
||||
+ SafeHtmlUtils.fromString(pairingListContextDefinition.getLeaderboardName())
|
||||
.asString()
|
||||
+ "</b></div>" + pairingListPanel.asWidget().getElement().getInnerHTML());
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
try {
|
||||
throw caught;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
mainPanel.add(scrollPanel);
|
||||
}
|
||||
|
||||
private VerticalPanel createPairingListPanel(PairingListDTO pairingListDTO, final List<String> fleetnames) {
|
||||
final List<BoatDTO> boats = pairingListDTO.getBoats();
|
||||
|
||||
final int flightCount = pairingListDTO.getPairingList().size();
|
||||
final int groupCount = pairingListDTO.getPairingList().get(0).size();
|
||||
final int boatCount = boats.size();
|
||||
|
||||
Grid pairingListGrid = new Grid(flightCount * groupCount + 1, (boatCount + 2));
|
||||
pairingListGrid.getElement().setId("grid");
|
||||
pairingListGrid.setCellPadding(15);
|
||||
|
||||
int flightIndexInGrid = 1;
|
||||
int groupIndex = 1;
|
||||
int boatIndex = 0;
|
||||
|
||||
for (BoatDTO boat : boats) {
|
||||
pairingListGrid.setWidget(0, boatIndex + 2, new Label(boat.getName()));
|
||||
pairingListGrid.getCellFormatter().getElement(0, boatIndex + 2).getStyle().setTextAlign(TextAlign.CENTER);
|
||||
pairingListGrid.getCellFormatter().getElement(0, boatIndex + 2).getStyle().setPadding(10, Unit.PX);
|
||||
if (boat.getColor() != null) {
|
||||
pairingListGrid.getCellFormatter().getElement(0, boatIndex + 2).getStyle()
|
||||
.setBackgroundColor(boat.getColor().getAsHtml());
|
||||
} else {
|
||||
pairingListGrid.getCellFormatter().getElement(0, boatIndex + 2).getStyle()
|
||||
.setBackgroundColor("#cecece");
|
||||
}
|
||||
boatIndex++;
|
||||
}
|
||||
String color = "";
|
||||
pairingListGrid.getCellFormatter().getElement(0, 0).getStyle().setBackgroundColor("#cecece");
|
||||
pairingListGrid.getCellFormatter().getElement(0, 1).getStyle().setBackgroundColor("#cecece");
|
||||
for (List<List<Pair<CompetitorDTO, BoatDTO>>> flight : pairingListDTO.getPairingList()) {
|
||||
color = (color.equals("none") ? "#cecece" : "none");
|
||||
// setting up race
|
||||
int currentRaceInGridCells = (((flightIndexInGrid - 1) * groupCount) + 1);
|
||||
pairingListGrid.setWidget(currentRaceInGridCells, 0,
|
||||
new Label(pairingListDTO.getRaceColumnNames().get(flightIndexInGrid - 1)));
|
||||
pairingListGrid.getCellFormatter().getElement(currentRaceInGridCells, 0).getStyle().setPadding(5, Unit.PX);
|
||||
pairingListGrid.getCellFormatter().getElement(currentRaceInGridCells, 0).getStyle()
|
||||
.setBackgroundColor(color);
|
||||
for (List<Pair<CompetitorDTO, BoatDTO>> group : flight) {
|
||||
// setting up fleet
|
||||
pairingListGrid.getCellFormatter().getElement(groupIndex, 0).getStyle().setPadding(3, Unit.PX);
|
||||
pairingListGrid.getCellFormatter().getElement(groupIndex, 0).getStyle().setBackgroundColor(color);
|
||||
pairingListGrid.setWidget(groupIndex, 1, new Label(fleetnames.get(groupIndex - 1)));
|
||||
// setting up fleets style
|
||||
pairingListGrid.getCellFormatter().getElement(groupIndex, 1).getStyle().setPadding(3, Unit.PX);
|
||||
pairingListGrid.getCellFormatter().getElement(groupIndex, 1).getStyle().setBackgroundColor(color);
|
||||
|
||||
if (group.size() < boatCount) {
|
||||
List<BoatDTO> boatsToRemove = new ArrayList<>(boats);
|
||||
for (Pair<CompetitorDTO, BoatDTO> competitorAndBoatPair : group) {
|
||||
boatsToRemove.remove(competitorAndBoatPair.getB());
|
||||
}
|
||||
for (BoatDTO boat : boatsToRemove) {
|
||||
group.add(new Pair<CompetitorDTO, BoatDTO>(new CompetitorDTOImpl(), boat));
|
||||
}
|
||||
}
|
||||
for (Pair<CompetitorDTO, BoatDTO> competitorAndBoatPair : group) {
|
||||
int boatIndexInGrid = boats.indexOf(competitorAndBoatPair.getB()) + 2;
|
||||
if (competitorAndBoatPair.getA().getName() == null) {
|
||||
pairingListGrid.setWidget(groupIndex, boatIndexInGrid, new Label(getStringMessages().empty()));
|
||||
pairingListGrid.getCellFormatter().getElement(groupIndex, boatIndexInGrid).getStyle()
|
||||
.setColor(Color.RED.toString());
|
||||
} else {
|
||||
// TODO change competitor name to competitor shorthand symbol ( bug2822 )
|
||||
pairingListGrid.setWidget(groupIndex, boatIndexInGrid,
|
||||
new Label(competitorAndBoatPair.getA().getSailID()));
|
||||
}
|
||||
pairingListGrid.getCellFormatter().getElement(groupIndex, boatIndexInGrid).getStyle()
|
||||
.setFontWeight(Style.FontWeight.BOLD);
|
||||
pairingListGrid.getCellFormatter().getElement(groupIndex, boatIndexInGrid).getStyle()
|
||||
.setTextAlign(TextAlign.CENTER);
|
||||
pairingListGrid.getCellFormatter().getElement(groupIndex, boatIndexInGrid).getStyle().setPadding(5,
|
||||
Unit.PX);
|
||||
pairingListGrid.getCellFormatter().getElement(groupIndex, boatIndexInGrid).getStyle()
|
||||
.setBackgroundColor(color);
|
||||
}
|
||||
|
||||
groupIndex++;
|
||||
}
|
||||
flightIndexInGrid++;
|
||||
}
|
||||
|
||||
VerticalPanel pairingListPanel = new VerticalPanel();
|
||||
pairingListPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
|
||||
pairingListPanel.add(pairingListGrid);
|
||||
pairingListPanel.setWidth("100%");
|
||||
pairingListPanel.ensureDebugId("PairingListPanel");
|
||||
pairingListPanel.getElement().getStyle().setProperty("marginTop", "15px");
|
||||
|
||||
return pairingListPanel;
|
||||
}
|
||||
|
||||
private native void printPairingListGrid(String pageHTMLContent) /*-{
|
||||
var frameID = '__gwt_historyFrame';
|
||||
var frame = $doc.getElementById(frameID);
|
||||
if (!frame) {
|
||||
$wnd.alert("Error: Can not find frame '" + frameID + "'");
|
||||
return;
|
||||
}
|
||||
frame = frame.contentWindow;
|
||||
var document = frame.document;
|
||||
document.open();
|
||||
document.write(pageHTMLContent);
|
||||
|
||||
//adding style to doc
|
||||
var css = "body { background: #fff; font-family: 'Open Sans', Arial, Verdana, sans-serif;"
|
||||
+ "line-height: 1; font-weight: 400; border: 0 }"
|
||||
+ ".title { font-size: 18px; text-align: center; float: right; color: #f6f9fc; margin-bottom: 0.466666666666667em; margin-right: 0.466666666666667em }"
|
||||
+ "img { max-height: 2em; float:left; margin-top: 0.466666666666667em; margin-left: 0.466666666666667em }"
|
||||
+ ".printHeader { font-size: 1rem; background: #333; border-bottom: 0.333333333333333em solid #f0ab00;"
|
||||
+ "height: 3.333333333333333em; line-height: 3em; width: 100%; overflow: hidden;}"
|
||||
+ "table { border-collapse: collapse; border: 1px solid black; margin: auto; width: 100%}"
|
||||
+ "td { font-size: 13px; }"
|
||||
head = document.head || document.getElementsByTagName('head')[0];
|
||||
style = document.createElement('style');
|
||||
style.type = 'text/css';
|
||||
if (style.styleSheet) {
|
||||
style.styleSheet.cssText = css;
|
||||
} else {
|
||||
style.appendChild(document.createTextNode(css));
|
||||
}
|
||||
head.appendChild(style);
|
||||
|
||||
document.close();
|
||||
|
||||
//Timeout for assets loading
|
||||
setTimeout(function() {
|
||||
frame.focus();
|
||||
frame.print();
|
||||
}, 100);
|
||||
}-*/;
|
||||
|
||||
}
|
||||
Regular → Executable
+190
-30
@@ -57,7 +57,6 @@ import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.InvalidSyntaxException;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
import org.osgi.util.tracker.ServiceTracker;
|
||||
|
||||
import com.sap.sailing.competitorimport.CompetitorProvider;
|
||||
import com.sap.sailing.domain.abstractlog.AbstractLog;
|
||||
import com.sap.sailing.domain.abstractlog.AbstractLogEvent;
|
||||
@@ -85,6 +84,7 @@ import com.sap.sailing.domain.abstractlog.race.state.impl.ReadonlyRaceStateImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.FlagPoleState;
|
||||
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.gate.ReadonlyGateStartRacingProcedure;
|
||||
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.line.ConfigurableStartModeFlagRacingProcedure;
|
||||
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDenoteForTrackingEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogTrackingStateAnalyzer;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
|
||||
@@ -114,6 +114,7 @@ import com.sap.sailing.domain.base.LeaderboardGroupBase;
|
||||
import com.sap.sailing.domain.base.Leg;
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.base.Nationality;
|
||||
import com.sap.sailing.domain.base.PairingListLeaderboardAdapter;
|
||||
import com.sap.sailing.domain.base.RaceColumn;
|
||||
import com.sap.sailing.domain.base.RaceColumnInSeries;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
@@ -194,11 +195,14 @@ import com.sap.sailing.domain.common.abstractlog.TimePointSpecificationFoundInLo
|
||||
import com.sap.sailing.domain.common.dto.BoatClassDTO;
|
||||
import com.sap.sailing.domain.common.dto.BoatDTO;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTOImpl;
|
||||
import com.sap.sailing.domain.common.dto.FleetDTO;
|
||||
import com.sap.sailing.domain.common.dto.FullLeaderboardDTO;
|
||||
import com.sap.sailing.domain.common.dto.IncrementalLeaderboardDTO;
|
||||
import com.sap.sailing.domain.common.dto.IncrementalOrFullLeaderboardDTO;
|
||||
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
|
||||
import com.sap.sailing.domain.common.dto.PairingListDTO;
|
||||
import com.sap.sailing.domain.common.dto.PairingListTemplateDTO;
|
||||
import com.sap.sailing.domain.common.dto.PersonDTO;
|
||||
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
|
||||
import com.sap.sailing.domain.common.dto.RaceColumnDTOFactory;
|
||||
@@ -267,6 +271,7 @@ import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapterFactory;
|
||||
import com.sap.sailing.domain.racelogtracking.impl.DeviceMappingImpl;
|
||||
import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo;
|
||||
import com.sap.sailing.domain.regattalike.HasRegattaLike;
|
||||
import com.sap.sailing.domain.regattalike.IsRegattaLike;
|
||||
import com.sap.sailing.domain.regattalike.LeaderboardThatHasRegattaLike;
|
||||
import com.sap.sailing.domain.regattalog.RegattaLogStore;
|
||||
import com.sap.sailing.domain.swisstimingadapter.StartList;
|
||||
@@ -492,6 +497,9 @@ import com.sap.sse.gwt.shared.replication.ReplicaDTO;
|
||||
import com.sap.sse.gwt.shared.replication.ReplicationMasterDTO;
|
||||
import com.sap.sse.gwt.shared.replication.ReplicationStateDTO;
|
||||
import com.sap.sse.i18n.ResourceBundleStringMessages;
|
||||
import com.sap.sse.pairinglist.PairingList;
|
||||
import com.sap.sse.pairinglist.PairingListTemplate;
|
||||
import com.sap.sse.pairinglist.impl.PairingListTemplateImpl;
|
||||
import com.sap.sse.replication.OperationWithResult;
|
||||
import com.sap.sse.replication.Replicable;
|
||||
import com.sap.sse.replication.ReplicationFactory;
|
||||
@@ -1770,7 +1778,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
competitorDTOsMap.put(competitorDTO.getIdAsString(), competitorDTO);
|
||||
}
|
||||
for (Competitor competitor : race.getCompetitors()) {
|
||||
Boat boatOfCompetitor = race.getBoatOfCompetitorById(competitor.getId());
|
||||
Boat boatOfCompetitor = race.getBoatOfCompetitor(competitor);
|
||||
if (boatOfCompetitor != null) {
|
||||
BoatDTO boatDTO = new BoatDTO(boatOfCompetitor.getName(), boatOfCompetitor.getSailID(),
|
||||
boatOfCompetitor.getColor());
|
||||
@@ -4114,20 +4122,6 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
maximumNumberOfDiscards, fleets));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceColumnInSeriesDTO addRaceColumnToSeries(RegattaIdentifier regattaIdentifier, String seriesName, String columnName) {
|
||||
Regatta regatta = getService().getRegatta(regattaIdentifier);
|
||||
if (regatta != null) {
|
||||
SecurityUtils.getSubject().checkPermission(Permission.REGATTA.getStringPermissionForObjects(Mode.UPDATE, regatta.getName()));
|
||||
}
|
||||
RaceColumnInSeriesDTO result = null;
|
||||
RaceColumnInSeries raceColumnInSeries = getService().apply(new AddColumnToSeries(regattaIdentifier, seriesName, columnName));
|
||||
if(raceColumnInSeries != null) {
|
||||
result = convertToRaceColumnInSeriesDTO(raceColumnInSeries);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRaceColumnsFromSeries(RegattaIdentifier regattaIdentifier, String seriesName, List<String> columnNames) {
|
||||
Regatta regatta = getService().getRegatta(regattaIdentifier);
|
||||
@@ -4139,15 +4133,6 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRaceColumnFromSeries(RegattaIdentifier regattaIdentifier, String seriesName, String columnName) {
|
||||
Regatta regatta = getService().getRegatta(regattaIdentifier);
|
||||
if (regatta != null) {
|
||||
SecurityUtils.getSubject().checkPermission(Permission.REGATTA.getStringPermissionForObjects(Mode.UPDATE, regatta.getName()));
|
||||
}
|
||||
getService().apply(new RemoveColumnFromSeries(regattaIdentifier, seriesName, columnName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveRaceColumnInSeriesUp(RegattaIdentifier regattaIdentifier, String seriesName, String columnName) {
|
||||
Regatta regatta = getService().getRegatta(regattaIdentifier);
|
||||
@@ -5418,14 +5403,18 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
|
||||
@Override
|
||||
public void denoteForRaceLogTracking(String leaderboardName) throws Exception {
|
||||
denoteForRaceLogTracking(leaderboardName, /* race name prefix */ null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void denoteForRaceLogTracking(String leaderboardName, String prefix) throws Exception {
|
||||
Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName);
|
||||
getRaceLogTrackingAdapter().denoteAllRacesForRaceLogTracking(getService(), leaderboard);
|
||||
getRaceLogTrackingAdapter().denoteAllRacesForRaceLogTracking(getService(), leaderboard, prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param triple leaderboard and racecolumn and fleet names
|
||||
* @return
|
||||
* @throws NotFoundException
|
||||
* @param triple
|
||||
* leaderboard and racecolumn and fleet names
|
||||
*/
|
||||
private RaceLog getRaceLog(com.sap.sse.common.Util.Triple<String, String, String> triple) throws NotFoundException {
|
||||
return getRaceLog(triple.getA(), triple.getB(), triple.getC());
|
||||
@@ -6758,7 +6747,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
}
|
||||
return availableDetailsTypes;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<ExpeditionDeviceConfiguration> getExpeditionDeviceConfigurations() {
|
||||
final List<ExpeditionDeviceConfiguration> result = new ArrayList<>();
|
||||
@@ -6786,4 +6775,175 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
expeditionConnector.removeDeviceConfiguration(deviceConfiguration);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PairingListTemplateDTO calculatePairingListTemplate(final int flightCount, final int groupCount,
|
||||
final int competitorCount, final int flightMultiplier) {
|
||||
PairingListTemplate template = getService().createPairingListTemplate(flightCount, groupCount, competitorCount,
|
||||
flightMultiplier);
|
||||
return new PairingListTemplateDTO(flightCount, groupCount, competitorCount, flightMultiplier,
|
||||
template.getPairingListTemplate(), template.getQuality());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PairingListDTO getPairingListFromTemplate(final String leaderboardName, final int flightMultiplier,
|
||||
final Iterable<String> selectedRaceColumnNames, PairingListTemplateDTO templateDTO)
|
||||
throws NotFoundException {
|
||||
Leaderboard leaderboard = getLeaderboardByName(leaderboardName);
|
||||
List<RaceColumn> selectedRaces = new ArrayList<RaceColumn>();
|
||||
for (String raceColumnName : selectedRaceColumnNames) {
|
||||
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
||||
if (raceColumnName.equalsIgnoreCase(raceColumn.getName())) {
|
||||
selectedRaces.add(raceColumn);
|
||||
}
|
||||
}
|
||||
}
|
||||
PairingListTemplate pairingListTemplate = new PairingListTemplateImpl(templateDTO.getPairingListTemplate(),
|
||||
templateDTO.getCompetitorCount(), templateDTO.getFlightMultiplier());
|
||||
PairingList<RaceColumn, Fleet, Competitor, Boat> pairingList = getService()
|
||||
.getPairingListFromTemplate(pairingListTemplate, leaderboardName, selectedRaces);
|
||||
List<List<List<Pair<CompetitorDTO, BoatDTO>>>> result = new ArrayList<>();
|
||||
for (RaceColumn raceColumn : selectedRaces) {
|
||||
List<List<Pair<CompetitorDTO, BoatDTO>>> raceColumnList = new ArrayList<>();
|
||||
for (Fleet fleet : raceColumn.getFleets()) {
|
||||
List<Pair<CompetitorDTO, BoatDTO>> fleetList = new ArrayList<>();
|
||||
for (Pair<Competitor, Boat> competitorAndBoatPair : pairingList.getCompetitors(raceColumn, fleet)) {
|
||||
if (competitorAndBoatPair.getA() != null) {
|
||||
fleetList.add(new Pair<CompetitorDTO, BoatDTO>(
|
||||
baseDomainFactory.convertToCompetitorDTO(competitorAndBoatPair.getA()),
|
||||
new BoatDTO(competitorAndBoatPair.getB().getName(),
|
||||
competitorAndBoatPair.getB().getSailID(),
|
||||
competitorAndBoatPair.getB().getColor())));
|
||||
} else {
|
||||
fleetList.add(new Pair<CompetitorDTO, BoatDTO>(new CompetitorDTOImpl(),
|
||||
new BoatDTO(competitorAndBoatPair.getB().getName(),
|
||||
competitorAndBoatPair.getB().getSailID(),
|
||||
competitorAndBoatPair.getB().getColor())));
|
||||
}
|
||||
}
|
||||
raceColumnList.add(fleetList);
|
||||
}
|
||||
result.add(raceColumnList);
|
||||
}
|
||||
return new PairingListDTO(result, Util.asList(selectedRaceColumnNames));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PairingListDTO getPairingListFromRaceLogs(final String leaderboardName) throws NotFoundException {
|
||||
Leaderboard leaderboard = getLeaderboardByName(leaderboardName);
|
||||
|
||||
List<List<List<Pair<CompetitorDTO, BoatDTO>>>> result = new ArrayList<>();
|
||||
List<String> raceColumnNames = new ArrayList<>();
|
||||
PairingListLeaderboardAdapter adapter = new PairingListLeaderboardAdapter();
|
||||
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
||||
if (!raceColumn.isMedalRace()) {
|
||||
List<List<Pair<CompetitorDTO, BoatDTO>>> raceColumnList = new ArrayList<>();
|
||||
for (Fleet fleet : raceColumn.getFleets()) {
|
||||
List<Pair<CompetitorDTO, BoatDTO>> fleetList = new ArrayList<>();
|
||||
for (Pair<Competitor, Boat> competitorAndBoatPair : adapter.getCompetitors(raceColumn, fleet)) {
|
||||
fleetList.add(new Pair<CompetitorDTO, BoatDTO>(baseDomainFactory.convertToCompetitorDTO(competitorAndBoatPair.getA()),
|
||||
new BoatDTO(competitorAndBoatPair.getB().getName(), competitorAndBoatPair.getB().getSailID(),
|
||||
competitorAndBoatPair.getB().getColor())));
|
||||
}
|
||||
if (fleetList.size() > 0) {
|
||||
raceColumnList.add(fleetList);
|
||||
}
|
||||
}
|
||||
if (raceColumnList.size() > 0) {
|
||||
result.add(raceColumnList);
|
||||
|
||||
if (!raceColumnNames.contains(raceColumn.getName())) {
|
||||
raceColumnNames.add(raceColumn.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new PairingListDTO(result, raceColumnNames);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillRaceLogsFromPairingListTemplate(final String leaderboardName, final int flightMultiplier,
|
||||
final Iterable<String> selectedFlightNames, final PairingListDTO pairingListDTO)
|
||||
throws NotFoundException, CompetitorRegistrationOnRaceLogDisabledException {
|
||||
Leaderboard leaderboard = getLeaderboardByName(leaderboardName);
|
||||
int flightCount = 0;
|
||||
int groupCount = 0;
|
||||
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
||||
if (Util.contains(selectedFlightNames, raceColumn.getName())) {
|
||||
groupCount = 0;
|
||||
for (Fleet fleet : raceColumn.getFleets()) {
|
||||
raceColumn.enableCompetitorRegistrationOnRaceLog(fleet);
|
||||
Set<CompetitorDTO> competitors = new HashSet<>();
|
||||
List<Pair<CompetitorDTO, BoatDTO>> competitorsFromPairingList = pairingListDTO.getPairingList()
|
||||
.get(flightCount).get(groupCount);
|
||||
for (Pair<CompetitorDTO, BoatDTO> competitorAndBoatPair : competitorsFromPairingList) {
|
||||
if (competitorAndBoatPair.getA() != null && competitorAndBoatPair.getA().getName() != null) {
|
||||
competitors.add(competitorAndBoatPair.getA());
|
||||
}
|
||||
}
|
||||
// TODO set boat and competitors in race logs (bug4403)
|
||||
// TODO add Javadoc to setCompetitorRegistrationsInRacelog
|
||||
this.setCompetitorRegistrationsInRaceLog(leaderboard.getName(), raceColumn.getName(),
|
||||
fleet.getName(), competitors);
|
||||
groupCount++;
|
||||
}
|
||||
flightCount++;
|
||||
} else {
|
||||
for (Fleet fleet : raceColumn.getFleets()) {
|
||||
this.setCompetitorRegistrationsInRaceLog(leaderboard.getName(), raceColumn.getName(),
|
||||
fleet.getName(), new HashSet<CompetitorDTO>());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (leaderboard instanceof LeaderboardThatHasRegattaLike && flightMultiplier > 1) {
|
||||
final IsRegattaLike regattaLike = ((LeaderboardThatHasRegattaLike) leaderboard).getRegattaLike();
|
||||
logger.info("Updating regatta "+regattaLike.getRegattaLikeIdentifier().getName()+
|
||||
", setting flag that fleets can run in parallel because a pairing list with flight multiplier "+
|
||||
flightMultiplier+" has been used.");
|
||||
regattaLike.setFleetsCanRunInParallelToTrue();
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getRaceDisplayNamesFromLeaderboard(String leaderboardName,List<String> raceColumnNames) throws NotFoundException{
|
||||
Leaderboard leaderboard=this.getLeaderboardByName(leaderboardName);
|
||||
List<String> result=new ArrayList<>();
|
||||
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
||||
if(raceColumn.hasTrackedRaces()){
|
||||
if (raceColumnNames.contains(raceColumn.getName())) {
|
||||
for (Fleet fleet : raceColumn.getFleets()) {
|
||||
if(raceColumn.getTrackedRace(fleet) != null && raceColumn.getTrackedRace(fleet).getRaceIdentifier()!=null){
|
||||
result.add(raceColumn.getTrackedRace(fleet).getRaceIdentifier().getRaceName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(result.size()==raceColumnNames.size()*Util.size(leaderboard.getRaceColumnByName(raceColumnNames.get(0)).getFleets())){
|
||||
return result;
|
||||
}
|
||||
result.clear();
|
||||
for (RaceColumn raceColumn : leaderboard.getRaceColumns()){
|
||||
for(Fleet fleet: raceColumn.getFleets()){
|
||||
NavigableSet<RaceLogEvent> set=raceColumn.getRaceLog(fleet).getUnrevokedEvents();
|
||||
for (RaceLogEvent raceLogEvent : set) {
|
||||
if(raceLogEvent instanceof RaceLogDenoteForTrackingEvent){
|
||||
RaceLogDenoteForTrackingEvent denoteEvent = (RaceLogDenoteForTrackingEvent) raceLogEvent;
|
||||
result.add(denoteEvent.getRaceName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(result.size()==raceColumnNames.size()*Util.size(leaderboard.getRaceColumnByName(raceColumnNames.get(0)).getFleets())){
|
||||
return result;
|
||||
}
|
||||
result.clear();
|
||||
for(int count=1;count<=raceColumnNames.size()*Util.size(leaderboard.getRaceColumnByName(raceColumnNames.get(0)).getFleets());count++){
|
||||
result.add("Race "+count);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Could not determine the version of your GWT SDK; using the module DTD
|
||||
from GWT 1.6.4. You may want to change this. -->
|
||||
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.7.0//EN" "http://gwtproject.org/doctype/2.7.0/gwt-module.dtd">
|
||||
<module>
|
||||
<inherits name='com.sap.sailing.gwt.ui.CommonConfigs' />
|
||||
|
||||
<!-- Highcharts API -->
|
||||
<inherits name="com.sap.sse.gwt.Highcharts_Autoinject" />
|
||||
|
||||
<!-- Google Maps API -->
|
||||
<inherits name='com.google.gwt.ajaxloader.AjaxLoader' />
|
||||
<inherits name='com.google.gwt.maps.Maps' />
|
||||
|
||||
<!-- Other module inherits -->
|
||||
<inherits name="com.sap.sse.gwt.SSESharedGWT" />
|
||||
<inherits name="com.sap.sse.SSECommon" />
|
||||
<inherits name="com.sap.sailing.domain.SailingDomain" />
|
||||
<inherits name="com.sap.sse.gwt.AdminConsole" />
|
||||
<inherits name="com.sap.sse.security.ui.LoginPanel" />
|
||||
|
||||
<!-- Specify the app entry point class. -->
|
||||
<entry-point class='com.sap.sailing.gwt.ui.pairinglist.PairingListEntryPoint' />
|
||||
|
||||
<!-- module containing locale configuration -->
|
||||
<inherits name='com.sap.sailing.gwt.common.SailingLocalesAllPermutations' />
|
||||
|
||||
<inherits name='com.sap.sailing.gwt.ui.SourceLeaderboard' />
|
||||
<inherits name='com.sap.sailing.gwt.ui.SourceCommon' />
|
||||
<inherits name='com.sap.sailing.gwt.ui.SourceClient' />
|
||||
<inherits name='com.sap.sailing.gwt.ui.SourceShared' />
|
||||
<inherits name="com.sap.sailing.gwt.ui.SourceLeaderboard" />
|
||||
<inherits name="com.sap.sailing.gwt.ui.SourceAdminConsole" />
|
||||
<inherits name="com.sap.sailing.gwt.ui.SourcePairingList" />
|
||||
<inherits name='com.sap.sailing.gwt.settings.Settings'/>
|
||||
|
||||
<inherits name='com.sap.sse.gwt.CommonControlCSS_Autoinject'/>
|
||||
<inherits name='com.sap.sailing.gwt.common.AuthenticationCommon'/>
|
||||
</module>
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 228 B |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 233 B |
+2
-1
@@ -57,7 +57,8 @@ public class RaceLogConnectivityParamsLoadAndStoreTest extends AbstractConnectiv
|
||||
theSeries.addRaceColumn("R2", racingEventService);
|
||||
theSeries.addRaceColumn("R3", racingEventService);
|
||||
final RegattaLeaderboard leaderboard = racingEventService.addRegattaLeaderboard(regatta.getRegattaIdentifier(), /* leaderboardDisplayName */ null, new int[] { 5, 9 });
|
||||
RaceLogTrackingAdapterFactory.INSTANCE.getAdapter(domainObjectFactory.getBaseDomainFactory()).denoteAllRacesForRaceLogTracking(racingEventService, leaderboard);
|
||||
RaceLogTrackingAdapterFactory.INSTANCE.getAdapter(domainObjectFactory.getBaseDomainFactory()).denoteAllRacesForRaceLogTracking(racingEventService, leaderboard,
|
||||
/* race name prefix */ null);
|
||||
final RaceLogConnectivityParams rlParams = new RaceLogConnectivityParams(
|
||||
racingEventService, regatta, leaderboard.getRaceColumnByName("R2"), fleet, leaderboard,
|
||||
delayToLiveInMillis, domainObjectFactory.getBaseDomainFactory(), trackWind,
|
||||
|
||||
+6
@@ -15,11 +15,13 @@ import com.sap.sailing.selenium.pages.adminconsole.regatta.RegattaListCompositeP
|
||||
import com.sap.sailing.selenium.pages.gwt.CellTablePO;
|
||||
import com.sap.sailing.selenium.pages.gwt.DataEntryPO;
|
||||
import com.sap.sailing.selenium.pages.gwt.GenericCellTablePO;
|
||||
import com.sap.sailing.selenium.pages.leaderboard.PairingListCreationSetupDialogPO;
|
||||
|
||||
public class LeaderboardConfigurationPanelPO extends PageArea {
|
||||
public static class LeaderboardEntryPO extends DataEntryPO {
|
||||
|
||||
private static final String ACTION_NAME_CONFIGURE_URL = "ACTION_CONFIGURE_URL";
|
||||
private static final String ACTION_NAME_CALC_PAIRINGLIST = "ACTION_CREATE_PAIRINGLIST";
|
||||
|
||||
public LeaderboardEntryPO(CellTablePO<?> table, WebElement element) {
|
||||
super(table, element);
|
||||
@@ -47,6 +49,10 @@ public class LeaderboardConfigurationPanelPO extends PageArea {
|
||||
clickActionImage(ACTION_NAME_CONFIGURE_URL);
|
||||
return waitForPO(LeaderboardUrlConfigurationDialogPO::new, "LeaderboardPageUrlConfigurationDialog", 60);
|
||||
}
|
||||
public PairingListCreationSetupDialogPO getLeaderboardPairingListCreationSetupDialog(){
|
||||
clickActionImage(ACTION_NAME_CALC_PAIRINGLIST);
|
||||
return waitForPO(PairingListCreationSetupDialogPO::new, "PairingListCreationSetupDialog", 60);
|
||||
}
|
||||
}
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "CreateFlexibleLeaderboardButton")
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package com.sap.sailing.selenium.pages.leaderboard;
|
||||
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
||||
import com.sap.sailing.selenium.core.BySeleniumId;
|
||||
import com.sap.sailing.selenium.core.FindBy;
|
||||
import com.sap.sailing.selenium.pages.PageArea;
|
||||
|
||||
public class PairinfListCreationDialogPO extends PageArea {
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "OkButton")
|
||||
private WebElement closeButton;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "FlightCountLabel")
|
||||
private WebElement flightsLabel;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "GroupCountLabel")
|
||||
private WebElement groupsLabel;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "CompetitorCountLabel")
|
||||
private WebElement competitorsLabel;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "FlightMultiplierCountLabel")
|
||||
private WebElement multiplierLabel;
|
||||
|
||||
protected PairinfListCreationDialogPO(WebDriver driver, WebElement element) {
|
||||
super(driver, element);
|
||||
}
|
||||
|
||||
public void pressClose(){
|
||||
closeButton.click();
|
||||
}
|
||||
|
||||
public String getValueOfFlightsLabel(){
|
||||
return flightsLabel.getText();
|
||||
}
|
||||
public String getValueOfGroupsLabel(){
|
||||
return groupsLabel.getText();
|
||||
}
|
||||
public String getValueOfCompetitorsLabel(){
|
||||
return competitorsLabel.getText();
|
||||
}
|
||||
public String getValueOfMultiplerLabel(){
|
||||
return multiplierLabel.getText();
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package com.sap.sailing.selenium.pages.leaderboard;
|
||||
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
||||
import com.sap.sailing.selenium.core.BySeleniumId;
|
||||
import com.sap.sailing.selenium.core.FindBy;
|
||||
import com.sap.sailing.selenium.pages.PageArea;
|
||||
import com.sap.sailing.selenium.pages.gwt.CheckBoxPO;
|
||||
|
||||
public class PairingListCreationSetupDialogPO extends PageArea {
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "OkButton")
|
||||
private WebElement okButton;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "CompetitorCountBox")
|
||||
private WebElement competitorsIntegerBox;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "FlightMultiplierIntegerBox")
|
||||
private WebElement multiplierIntegerBox;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "FlightMultiplierCheckBox")
|
||||
private WebElement multiplierCheckBox;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "SelectedFlightsCheckbox: Quali")
|
||||
private WebElement flightsCheckbox;
|
||||
|
||||
private PairingListCreationSetupDialogPO pairingListCreationSetupDialogPO;
|
||||
|
||||
public PairingListCreationSetupDialogPO(WebDriver webDriver, WebElement webElement){
|
||||
super(webDriver,webElement);
|
||||
}
|
||||
public PairingListCreationSetupDialogPO getPairingListCreationDialogPO() {
|
||||
return this.pairingListCreationSetupDialogPO;
|
||||
}
|
||||
public void setCompetitorsCount(String count){
|
||||
competitorsIntegerBox.clear();
|
||||
competitorsIntegerBox.sendKeys(count);
|
||||
}
|
||||
public PairinfListCreationDialogPO pressOk(){
|
||||
okButton.click();
|
||||
return waitForPO(PairinfListCreationDialogPO::new, "PairingListCreationDialog", 60);
|
||||
}
|
||||
public boolean isOkButtonEnabled(){
|
||||
return okButton.isEnabled();
|
||||
}
|
||||
public boolean isFlightMultiplierBoxEnabled(){
|
||||
return multiplierIntegerBox.isEnabled();
|
||||
}
|
||||
public void setFlightMultiplier(String count){
|
||||
multiplierIntegerBox.clear();
|
||||
multiplierIntegerBox.sendKeys(count);
|
||||
}
|
||||
public void clickFlightMultiplierCheckBox() {
|
||||
CheckBoxPO.create(driver, multiplierCheckBox).setSelected(!this.getValueOfFlightMultiplierCheckBox());
|
||||
}
|
||||
public void clickFlightCheckBox() {
|
||||
CheckBoxPO.create(driver, flightsCheckbox).setSelected(!this.getValueOfFlightCheckBox());
|
||||
}
|
||||
public boolean getValueOfFlightCheckBox(){
|
||||
return CheckBoxPO.create(driver, flightsCheckbox).isSelected();
|
||||
}
|
||||
public boolean getValueOfFlightMultiplierCheckBox(){
|
||||
return CheckBoxPO.create(driver, multiplierCheckBox).isSelected();
|
||||
}
|
||||
}
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
package com.sap.sailing.selenium.test.pairinglist;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.selenium.pages.adminconsole.AdminConsolePage;
|
||||
import com.sap.sailing.selenium.pages.adminconsole.event.EventConfigurationPanelPO;
|
||||
import com.sap.sailing.selenium.pages.adminconsole.leaderboard.LeaderboardConfigurationPanelPO;
|
||||
import com.sap.sailing.selenium.pages.adminconsole.leaderboard.LeaderboardConfigurationPanelPO.LeaderboardEntryPO;
|
||||
import com.sap.sailing.selenium.pages.adminconsole.regatta.RegattaDetailsCompositePO;
|
||||
import com.sap.sailing.selenium.pages.adminconsole.regatta.RegattaEditDialogPO;
|
||||
import com.sap.sailing.selenium.pages.adminconsole.regatta.RegattaListCompositePO.RegattaDescriptor;
|
||||
import com.sap.sailing.selenium.pages.adminconsole.regatta.RegattaStructureManagementPanelPO;
|
||||
import com.sap.sailing.selenium.pages.adminconsole.regatta.SeriesEditDialogPO;
|
||||
import com.sap.sailing.selenium.pages.leaderboard.PairinfListCreationDialogPO;
|
||||
import com.sap.sailing.selenium.pages.leaderboard.PairingListCreationSetupDialogPO;
|
||||
import com.sap.sailing.selenium.test.AbstractSeleniumTest;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
public class PairinglistTest extends AbstractSeleniumTest {
|
||||
private static final String EVENT = "TestEvent";
|
||||
private static final String EVENT_DESC = "TestEvent";
|
||||
private static final String VENUE = "Walldorf";
|
||||
private static final String BOAT_CLASS_49ER = "49er";
|
||||
private static final String REGATTA_49ER = "KW 2015 Olympic - 49er"; //$NON-NLS-1$
|
||||
private static final String REGATTA_49ER_WITH_SUFFIX = REGATTA_49ER + " ("+BOAT_CLASS_49ER+")"; //$NON-NLS-1$
|
||||
private static final Date EVENT_START_TIME = DatatypeConverter.parseDateTime("2015-06-20T08:00:00-00:00")
|
||||
.getTime();
|
||||
private static final Date EVENT_END_TIME = DatatypeConverter.parseDateTime("2015-06-28T20:00:00-00:00")
|
||||
.getTime();
|
||||
private static final String SERIES_QUALIFICATION = "Quali";
|
||||
private static final String SERIES_MEDALS = "Medals";
|
||||
private static final String SERIES_DEFAULT = "Default";
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() {
|
||||
clearState(getContextRoot());
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createEventAndTestPOForCalculation() throws InterruptedException {
|
||||
final RegattaDescriptor regattaDescriptor = new RegattaDescriptor(REGATTA_49ER, BOAT_CLASS_49ER);
|
||||
{
|
||||
AdminConsolePage adminConsolePage = AdminConsolePage.goToPage(getWebDriver(), getContextRoot());
|
||||
EventConfigurationPanelPO events = adminConsolePage.goToEvents();
|
||||
events.createEventWithDefaultLeaderboardGroupRegattaAndDefaultLeaderboard(EVENT, EVENT_DESC, VENUE,
|
||||
EVENT_START_TIME, EVENT_END_TIME, true, REGATTA_49ER_WITH_SUFFIX, BOAT_CLASS_49ER, EVENT_START_TIME,
|
||||
EVENT_END_TIME, false);
|
||||
final RegattaStructureManagementPanelPO regattaStructurePanel = adminConsolePage.goToRegattaStructure();
|
||||
final RegattaDetailsCompositePO regattaDetails = regattaStructurePanel.getRegattaDetails(regattaDescriptor);
|
||||
regattaDetails.deleteSeries(SERIES_DEFAULT);
|
||||
RegattaEditDialogPO editRegatta = regattaStructurePanel.getRegattaList().editRegatta(regattaDescriptor);
|
||||
editRegatta.addSeries(SERIES_QUALIFICATION);
|
||||
editRegatta.addSeries(SERIES_MEDALS);
|
||||
editRegatta.pressOk();
|
||||
|
||||
final SeriesEditDialogPO editSeriesQualification = regattaDetails.editSeries(SERIES_QUALIFICATION);
|
||||
editSeriesQualification.addRaces(1, 12, "Q");
|
||||
editSeriesQualification.pressOk();
|
||||
|
||||
final SeriesEditDialogPO editSeriesMedals = regattaDetails.editSeries(SERIES_MEDALS);
|
||||
editSeriesMedals.setMedalSeries(true);
|
||||
editSeriesMedals.addSingleRace("M");
|
||||
editSeriesMedals.pressOk();
|
||||
LeaderboardConfigurationPanelPO leaderboardConfigurationPanelPO = adminConsolePage
|
||||
.goToLeaderboardConfiguration();
|
||||
LeaderboardEntryPO leaderboardEntryPO = leaderboardConfigurationPanelPO.getLeaderboardTable()
|
||||
.getEntry(REGATTA_49ER_WITH_SUFFIX);
|
||||
PairingListCreationSetupDialogPO dialog = leaderboardEntryPO.getLeaderboardPairingListCreationSetupDialog();
|
||||
Assert.assertTrue(!dialog.isOkButtonEnabled());
|
||||
dialog.setCompetitorsCount("1");
|
||||
Assert.assertTrue(dialog.isOkButtonEnabled());
|
||||
dialog.setCompetitorsCount("-1");
|
||||
Assert.assertTrue(!dialog.isOkButtonEnabled());
|
||||
dialog.setCompetitorsCount("17");
|
||||
Assert.assertTrue(dialog.isOkButtonEnabled());
|
||||
dialog.setCompetitorsCount("18");
|
||||
Assert.assertTrue(dialog.isOkButtonEnabled());
|
||||
PairinfListCreationDialogPO dialog2 = dialog.pressOk();
|
||||
Assert.assertEquals("12", dialog2.getValueOfFlightsLabel());
|
||||
Assert.assertEquals("1", dialog2.getValueOfGroupsLabel());
|
||||
Assert.assertEquals("18", dialog2.getValueOfCompetitorsLabel());
|
||||
dialog2.pressClose();
|
||||
}
|
||||
{
|
||||
AdminConsolePage adminConsolePage = AdminConsolePage.goToPage(getWebDriver(), getContextRoot());
|
||||
LeaderboardConfigurationPanelPO leaderboardConfigurationPanelPO = adminConsolePage
|
||||
.goToLeaderboardConfiguration();
|
||||
LeaderboardEntryPO leaderboardEntryPO = leaderboardConfigurationPanelPO.getLeaderboardTable()
|
||||
.getEntry(REGATTA_49ER_WITH_SUFFIX);
|
||||
PairingListCreationSetupDialogPO dialog = leaderboardEntryPO.getLeaderboardPairingListCreationSetupDialog();
|
||||
dialog.setCompetitorsCount("18");
|
||||
Assert.assertTrue(!dialog.isFlightMultiplierBoxEnabled());
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
dialog.clickFlightMultiplierCheckBox();
|
||||
if (dialog.getValueOfFlightMultiplierCheckBox()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Assert.assertTrue(dialog.isFlightMultiplierBoxEnabled());
|
||||
Thread.sleep(5000);
|
||||
dialog.setFlightMultiplier("0");
|
||||
Assert.assertTrue(!dialog.isOkButtonEnabled());
|
||||
dialog.setFlightMultiplier("2");
|
||||
Assert.assertTrue(dialog.isOkButtonEnabled());
|
||||
PairinfListCreationDialogPO dialog2 = dialog.pressOk();
|
||||
Assert.assertEquals("12", dialog2.getValueOfFlightsLabel());
|
||||
Assert.assertEquals("1", dialog2.getValueOfGroupsLabel());
|
||||
Assert.assertEquals("18", dialog2.getValueOfCompetitorsLabel());
|
||||
Assert.assertEquals("2", dialog2.getValueOfMultiplerLabel());
|
||||
dialog2.pressClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -26,9 +26,9 @@ public class CompetitorWithChangingBoatJsonSerializer extends CompetitorJsonSeri
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Color getColor(Competitor competitor ) {
|
||||
protected Color getColor(Competitor competitor) {
|
||||
if (race != null) {
|
||||
Boat boatOfCompetitor = race.getBoatOfCompetitorById(competitor.getId());
|
||||
Boat boatOfCompetitor = race.getBoatOfCompetitor(competitor);
|
||||
if (boatOfCompetitor != null) {
|
||||
return boatOfCompetitor.getColor();
|
||||
}
|
||||
@@ -37,9 +37,9 @@ public class CompetitorWithChangingBoatJsonSerializer extends CompetitorJsonSeri
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boat getBoat(Competitor competitor ) {
|
||||
protected Boat getBoat(Competitor competitor) {
|
||||
if (race != null) {
|
||||
Boat boatOfCompetitor = race.getBoatOfCompetitorById(competitor.getId());
|
||||
Boat boatOfCompetitor = race.getBoatOfCompetitor(competitor);
|
||||
if (boatOfCompetitor != null) {
|
||||
return boatOfCompetitor;
|
||||
}
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
package com.sap.sailing.server.gateway.trackfiles.impl;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ExpeditionImportFilenameUtilsTest {
|
||||
|
||||
@Test
|
||||
public void testTruncateFilenameExtentions_CSV() {
|
||||
testCase("2017Nov08_2.csv", "2017Nov08_2");
|
||||
testCase("2017Nov04VeryShort.CSV", "2017Nov04VeryShort");
|
||||
testCase("2017Nov04.1s_clean.csv", "2017Nov04.1s_clean");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTruncateFilenameExtentions_TXT() {
|
||||
testCase("Expedition_28Oct17_0820.txt", "Expedition_28Oct17_0820");
|
||||
testCase("VarLog1Hz_20171104_100149_843.Txt", "VarLog1Hz_20171104_100149_843");
|
||||
testCase("VarLog1Hz_20171105_091128_062.TXT", "VarLog1Hz_20171105_091128_062");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTruncateFilenameExtentions_LOG() {
|
||||
testCase("file1.log", "file1");
|
||||
testCase("file2.LOG", "file2");
|
||||
testCase("file3.Log", "file3");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTruncateFilenameExtentions_GZ() {
|
||||
testCase("archive1.gz", "archive1");
|
||||
testCase("archive2.GZ", "archive2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTruncateFilenameExtentions_ZIP() {
|
||||
testCase("archive1.zip", "archive1");
|
||||
testCase("archive2.ZIP", "archive2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTruncateFilenameExtentions_CSV_GZ() {
|
||||
testCase("2017Nov08.csv.gz", "2017Nov08");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTruncateFilenameExtentions_CSV_ZIP() {
|
||||
testCase("2017Nov08.csv.zip", "2017Nov08");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTruncateFilenameExtentions_TXT_GZ() {
|
||||
testCase("VarLog1Hz_20171105_091128_062.Txt.gz", "VarLog1Hz_20171105_091128_062");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTruncateFilenameExtentions_TXT_ZIP() {
|
||||
testCase("VarLog1Hz_20171105_091128_062.Txt.zip", "VarLog1Hz_20171105_091128_062");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTruncateFilenameExtentions_LOG_GZ() {
|
||||
testCase("log-archive.log.gz", "log-archive");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTruncateFilenameExtentions_LOG_ZIP() {
|
||||
testCase("log-archive.log.zip", "log-archive");
|
||||
}
|
||||
|
||||
private void testCase(String actualFilename, String expectedResult) {
|
||||
Assert.assertEquals(expectedResult, ExpeditionImportFilenameUtils.truncateFilenameExtentions(actualFilename));
|
||||
}
|
||||
|
||||
}
|
||||
+11
-6
@@ -19,7 +19,9 @@ import org.apache.commons.fileupload.FileItem;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
|
||||
import com.sap.sailing.domain.trackimport.GPSFixImporter;
|
||||
import com.sap.sailing.server.trackfiles.RouteConverterGPSFixImporterFactory;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
@@ -68,15 +70,18 @@ public class GPSFixImportTest {
|
||||
|
||||
@Test
|
||||
public void testReusingImportStream() throws IOException {
|
||||
TrackFilesImportServlet servlet = new TrackFilesImportServlet() {
|
||||
private static final long serialVersionUID = -7636477441858728847L;
|
||||
|
||||
TrackFilesImporter importer = new TrackFilesImporter(null, null, null) {
|
||||
@Override
|
||||
public Collection<GPSFixImporter> getGPSFixImporters(String type) {
|
||||
return Arrays.asList((GPSFixImporter) RouteConverterGPSFixImporterFactory.INSTANCE
|
||||
.createRouteConverterGPSFixImporter());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void additionalDataExtractor(ImportResultDTO jsonResult, TrackFileImportDeviceIdentifier device)
|
||||
throws TransformationException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storeFix(GPSFix fix, DeviceIdentifier deviceIdentifier) {
|
||||
}
|
||||
@@ -156,7 +161,7 @@ public class GPSFixImportTest {
|
||||
}
|
||||
};
|
||||
AtomicBoolean failed = new AtomicBoolean(false);
|
||||
JsonHolder holder = new JsonHolder(Logger.getLogger(GPSFixImportTest.class.getName())){
|
||||
ImportResultDTO holder = new ImportResultDTO(Logger.getLogger(GPSFixImportTest.class.getName())){
|
||||
|
||||
@Override
|
||||
public void add(Exception exception) {
|
||||
@@ -165,7 +170,7 @@ public class GPSFixImportTest {
|
||||
}
|
||||
};
|
||||
//The preferred importer will fail, however the default importer should succeed after
|
||||
servlet.importFiles(Arrays.asList(new Pair<>("test.gpx", fi)), holder, new AlwaysFailingGPSFixImporter(-1));
|
||||
importer.importFilesWithPreferredImporter(Arrays.asList(new Pair<>("test.gpx", fi)), holder, new AlwaysFailingGPSFixImporter(-1));
|
||||
assertFalse(failed.get());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,6 +190,14 @@
|
||||
<servlet-name>SensorDataImportServlet</servlet-name>
|
||||
<url-pattern>/sensordata/import</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet>
|
||||
<servlet-name>ExpeditionAllInOneImportServlet</servlet-name>
|
||||
<servlet-class>com.sap.sailing.server.gateway.trackfiles.impl.ExpeditionAllInOneImportServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>ExpeditionAllInOneImportServlet</servlet-name>
|
||||
<url-pattern>/expedition/import</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet>
|
||||
<servlet-name>FileUploadServlet</servlet-name>
|
||||
<servlet-class>com.sap.sailing.server.gateway.impl.FileUploadServlet</servlet-class>
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.sap.sailing.server.gateway.trackfiles.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.server.gateway.trackfiles.impl.ImportResultDTO.ErrorImportDTO;
|
||||
|
||||
public class AllinOneImportException extends Exception {
|
||||
private static final long serialVersionUID = 1L;
|
||||
List<ErrorImportDTO> additionalErrors = new ArrayList<>();
|
||||
|
||||
public AllinOneImportException(String message, Throwable cause, List<ErrorImportDTO> additionalErrors) {
|
||||
super(message, cause);
|
||||
this.additionalErrors.addAll(additionalErrors);
|
||||
}
|
||||
|
||||
public AllinOneImportException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public AllinOneImportException(String message, List<ErrorImportDTO> additionalErrors) {
|
||||
super(message);
|
||||
this.additionalErrors.addAll(additionalErrors);
|
||||
}
|
||||
|
||||
public AllinOneImportException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public AllinOneImportException(Throwable cause, List<ErrorImportDTO> additionalErrors) {
|
||||
super(cause);
|
||||
this.additionalErrors.addAll(additionalErrors);
|
||||
}
|
||||
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
package com.sap.sailing.server.gateway.trackfiles.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.fileupload.FileItem;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.osgi.util.tracker.ServiceTracker;
|
||||
|
||||
import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapterFactory;
|
||||
import com.sap.sailing.server.gateway.impl.AbstractFileUploadServlet;
|
||||
import com.sap.sailing.server.gateway.trackfiles.impl.ExpeditionAllInOneImporter.ImporterResult;
|
||||
import com.sap.sse.util.ServiceTrackerFactory;
|
||||
|
||||
/**
|
||||
* Import servlet for sensor data files. Importers are located through the OSGi service registry and matched against the
|
||||
* name provided by the upload form.
|
||||
*/
|
||||
public class ExpeditionAllInOneImportServlet extends AbstractFileUploadServlet {
|
||||
private static final long serialVersionUID = 1120226743039934620L;
|
||||
private static final Logger logger = Logger.getLogger(ExpeditionAllInOneImportServlet.class.getName());
|
||||
|
||||
private static final String REQUEST_PARAMETER_BOAT_CLASS = "boatClass";
|
||||
private static final String ERROR_MESSAGE_IMPORT_FILE_MISSING = "No file to import found!";
|
||||
private static final String ERROR_MESSAGE_BOAT_CLASS_MISSING = "No boat class name found!";
|
||||
|
||||
private ServiceTracker<RaceLogTrackingAdapterFactory, RaceLogTrackingAdapterFactory> raceLogTrackingAdapterTracker;
|
||||
|
||||
@Override
|
||||
public void init(ServletConfig config) throws ServletException {
|
||||
super.init(config);
|
||||
raceLogTrackingAdapterTracker = ServiceTrackerFactory.createAndOpen(getContext(),
|
||||
RaceLogTrackingAdapterFactory.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the uploaded file items.
|
||||
*/
|
||||
@Override
|
||||
protected void process(List<FileItem> fileItems, HttpServletRequest req, HttpServletResponse resp)
|
||||
throws IOException {
|
||||
resp.setContentType("text/html;charset=UTF-8");
|
||||
ImporterResult importerResult = null;
|
||||
try {
|
||||
String fileName = null;
|
||||
FileItem fileItem = null;
|
||||
String boatClassName = null;
|
||||
for (FileItem fi : fileItems) {
|
||||
if (!fi.isFormField()) {
|
||||
fileName = fi.getName();
|
||||
fileItem = fi;
|
||||
} else if (fi.getFieldName() != null) {
|
||||
if (REQUEST_PARAMETER_BOAT_CLASS.equals(fi.getFieldName())) {
|
||||
boatClassName = fi.getString();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fileItem == null) {
|
||||
throw new AllinOneImportException(ERROR_MESSAGE_IMPORT_FILE_MISSING);
|
||||
}
|
||||
if (boatClassName == null || boatClassName.isEmpty()) {
|
||||
throw new AllinOneImportException(ERROR_MESSAGE_BOAT_CLASS_MISSING);
|
||||
}
|
||||
importerResult = new ExpeditionAllInOneImporter(getService(),
|
||||
raceLogTrackingAdapterTracker.getService().getAdapter(getService().getBaseDomainFactory()),
|
||||
getServiceFinderFactory(), getContext()).importFiles(fileName, fileItem, boatClassName);
|
||||
} catch (AllinOneImportException e) {
|
||||
importerResult = new ImporterResult(e, e.additionalErrors);
|
||||
logger.log(Level.SEVERE, e.getMessage());
|
||||
} catch (Throwable t) {
|
||||
importerResult = new ImporterResult(t, Collections.emptyList());
|
||||
logger.log(Level.SEVERE, t.getMessage());
|
||||
} finally {
|
||||
this.toJSON(importerResult).writeJSONString(resp.getWriter());
|
||||
}
|
||||
}
|
||||
|
||||
private JSONObject toJSON(ImporterResult importerResult) {
|
||||
final JSONObject json = new JSONObject();
|
||||
json.put("eventId", importerResult.eventId == null ? null : importerResult.eventId.toString());
|
||||
json.put("leaderboardName", importerResult.leaderboardName);
|
||||
json.put("leaderboardGroupName", importerResult.leaderboardGroupName);
|
||||
json.put("regattaName", importerResult.regattaName);
|
||||
json.put("raceName", importerResult.raceName);
|
||||
json.put("raceColumnName", importerResult.raceColumnName);
|
||||
json.put("fleetName", importerResult.fleetName);
|
||||
json.put("errors", ImportResultSerializer.serializeErrorList(importerResult.errorList));
|
||||
json.put("gpsDeviceIds", ImportResultSerializer.serializeTrackList(importerResult.importGpsFixData));
|
||||
json.put("sensorDeviceIds", ImportResultSerializer.serializeTrackList(importerResult.importSensorFixData));
|
||||
json.put("sensorFixImporterType", importerResult.sensorFixImporterType);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
+284
@@ -0,0 +1,284 @@
|
||||
package com.sap.sailing.server.gateway.trackfiles.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.text.MessageFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apache.commons.fileupload.FileItem;
|
||||
import org.osgi.framework.BundleContext;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogEndOfTrackingEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartOfTrackingEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogDenoteForTrackingEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogStartTrackingEventImpl;
|
||||
import com.sap.sailing.domain.base.Event;
|
||||
import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.base.RaceColumn;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.Series;
|
||||
import com.sap.sailing.domain.base.impl.FleetImpl;
|
||||
import com.sap.sailing.domain.base.impl.SeriesImpl;
|
||||
import com.sap.sailing.domain.common.LeaderboardNameConstants;
|
||||
import com.sap.sailing.domain.common.RankingMetrics;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaName;
|
||||
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||
import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceWithAdditionalID;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapter;
|
||||
import com.sap.sailing.domain.ranking.RankingMetricConstructor;
|
||||
import com.sap.sailing.domain.ranking.RankingMetricsFactory;
|
||||
import com.sap.sailing.domain.trackimport.DoubleVectorFixImporter;
|
||||
import com.sap.sailing.domain.trackimport.GPSFixImporter;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.RaceHandle;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sailing.server.gateway.trackfiles.impl.ImportResultDTO.ErrorImportDTO;
|
||||
import com.sap.sailing.server.gateway.trackfiles.impl.ImportResultDTO.TrackImportDTO;
|
||||
import com.sap.sailing.server.gateway.windimport.AbstractWindImporter;
|
||||
import com.sap.sailing.server.gateway.windimport.AbstractWindImporter.WindImportResult;
|
||||
import com.sap.sailing.server.gateway.windimport.expedition.WindImporter;
|
||||
import com.sap.sailing.server.operationaltransformation.AddColumnToSeries;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.TypeBasedServiceFinderFactory;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
public class ExpeditionAllInOneImporter {
|
||||
private static final Logger logger = Logger.getLogger(ExpeditionAllInOneImporter.class.getName());
|
||||
|
||||
private static final String ERROR_MESSAGE_GPS_DATA_IMPORT_FAILED = "Failed to import GPS data!";
|
||||
private static final String ERROR_MESSAGE_SENSOR_DATA_IMPORT_FAILED = "Failed to import sensor data!";
|
||||
private static final String ERROR_MESSAGE_BOAT_CLASS_DETERMINATION_FAILED = "Failed to determine boat class!";
|
||||
|
||||
private final RacingEventService service;
|
||||
private final RaceLogTrackingAdapter adapter;
|
||||
private final TypeBasedServiceFinderFactory serviceFinderFactory;
|
||||
private final BundleContext context;
|
||||
|
||||
public static class ImporterResult {
|
||||
final UUID eventId;
|
||||
final String leaderboardName, leaderboardGroupName, regattaName, raceName, raceColumnName, fleetName;
|
||||
final List<TrackImportDTO> importGpsFixData, importSensorFixData;
|
||||
final String sensorFixImporterType;
|
||||
final List<ErrorImportDTO> errorList = new ArrayList<>();
|
||||
|
||||
public ImporterResult(Throwable exception, List<ErrorImportDTO> additionalErrors) {
|
||||
this(null, "", "", new RegattaNameAndRaceName("", ""), "", "", Collections.emptyList(),
|
||||
Collections.emptyList(), "", additionalErrors);
|
||||
this.errorList.add(new ErrorImportDTO(exception.getClass().getName(), exception.getMessage()));
|
||||
}
|
||||
|
||||
private ImporterResult(final UUID eventId, final String leaderboardName, String leaderboardGroupName,
|
||||
final RegattaAndRaceIdentifier regattaAndRaceIdentifier, final String raceColumnName,
|
||||
final String fleetName, final List<TrackImportDTO> importGpsFixData,
|
||||
final List<TrackImportDTO> importSensorFixData, final String sensorFixImporterType,
|
||||
List<ErrorImportDTO> errors) {
|
||||
this.eventId = eventId;
|
||||
this.leaderboardName = leaderboardName;
|
||||
this.leaderboardGroupName = leaderboardGroupName;
|
||||
this.regattaName = regattaAndRaceIdentifier.getRegattaName();
|
||||
this.raceName = regattaAndRaceIdentifier.getRaceName();
|
||||
this.raceColumnName = raceColumnName;
|
||||
this.fleetName = fleetName;
|
||||
this.importGpsFixData = importGpsFixData;
|
||||
this.importSensorFixData = importSensorFixData;
|
||||
this.sensorFixImporterType = sensorFixImporterType;
|
||||
this.errorList.addAll(errors);
|
||||
}
|
||||
}
|
||||
|
||||
public ExpeditionAllInOneImporter(final RacingEventService service, RaceLogTrackingAdapter adapter,
|
||||
final TypeBasedServiceFinderFactory serviceFinderFactory, final BundleContext context) {
|
||||
this.service = service;
|
||||
this.adapter = adapter;
|
||||
this.serviceFinderFactory = serviceFinderFactory;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public ImporterResult importFiles(final String filenameWithSuffix, final FileItem fileItem,
|
||||
final String boatClassName) throws AllinOneImportException {
|
||||
final List<ErrorImportDTO> errors = new ArrayList<>();
|
||||
final String importTimeString = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now(ZoneOffset.UTC));
|
||||
|
||||
final String filename = ExpeditionImportFilenameUtils.truncateFilenameExtentions(filenameWithSuffix);
|
||||
final String filenameWithDateTimeSuffix = filename + "_" + importTimeString;
|
||||
final String eventName = filenameWithDateTimeSuffix;
|
||||
final String description = MessageFormat.format("Event imported from expedition file ''{0}'' on {1}",
|
||||
filenameWithSuffix, importTimeString);
|
||||
final String leaderboardGroupName = filenameWithDateTimeSuffix;
|
||||
final String regattaNameAndleaderboardName = filenameWithDateTimeSuffix;
|
||||
final RegattaIdentifier regattaIdentifier = new RegattaName(filenameWithDateTimeSuffix);
|
||||
final String raceColumnName = filename;
|
||||
final String trackedRaceName = filenameWithDateTimeSuffix;
|
||||
final String courseAreaName = "Default";
|
||||
final UUID courseAreaId = UUID.randomUUID();
|
||||
// This is just the default used in the UI
|
||||
final Double buoyZoneRadiusInHullLengths = 3.0;
|
||||
// TODO is this a proper id for the WindSource used here?
|
||||
final String windSourceId = filenameWithDateTimeSuffix;
|
||||
|
||||
// TODO guess venue based on the reverse geocoder?
|
||||
final String venueName = filename;
|
||||
|
||||
final String fleetName = LeaderboardNameConstants.DEFAULT_FLEET_NAME;
|
||||
final String seriesName = Series.DEFAULT_NAME;
|
||||
|
||||
// TODO wild guess...
|
||||
final ScoringSchemeType scoringSchemeType = ScoringSchemeType.HIGH_POINT;
|
||||
final RankingMetrics rankingMetric = RankingMetrics.ONE_DESIGN;
|
||||
final int[] discardThresholds = new int[0];
|
||||
|
||||
// TODO These are the defaults also used by the UI
|
||||
final String raceLogEventAuthorName = "Shore";
|
||||
final int raceLogEventPriority = 4;
|
||||
final boolean correctWindDirectionByMagneticDeclination = true;
|
||||
|
||||
final ImportResultDTO jsonHolderForGpsFixImport = new ImportResultDTO(logger);
|
||||
final List<Pair<String, FileItem>> filesForGpsFixImport = Arrays.asList(new Pair<>(filenameWithSuffix, fileItem));
|
||||
try {
|
||||
new TrackFilesImporter(service, serviceFinderFactory, context).importFixes(jsonHolderForGpsFixImport,
|
||||
GPSFixImporter.EXPEDITION_TYPE, filesForGpsFixImport);
|
||||
this.ensureSuccessfulImport(jsonHolderForGpsFixImport, ERROR_MESSAGE_GPS_DATA_IMPORT_FAILED);
|
||||
} catch (IOException e1) {
|
||||
errors.addAll(jsonHolderForGpsFixImport.getErrorList());
|
||||
throw new AllinOneImportException(e1, errors);
|
||||
}
|
||||
errors.addAll(jsonHolderForGpsFixImport.getErrorList());
|
||||
|
||||
final ImportResultDTO jsonHolderForSensorFixImport = new ImportResultDTO(logger);
|
||||
final String sensorFixImporterType = DoubleVectorFixImporter.EXPEDITION_EXTENDED_TYPE;
|
||||
final Iterable<Pair<String, FileItem>> importerNamesAndFilesForSensorFixImport = Arrays
|
||||
.asList(new Pair<>(sensorFixImporterType, fileItem));
|
||||
try {
|
||||
new SensorDataImporter(service, context).importFiles(false, jsonHolderForSensorFixImport,
|
||||
importerNamesAndFilesForSensorFixImport);
|
||||
this.ensureSuccessfulImport(jsonHolderForSensorFixImport, ERROR_MESSAGE_SENSOR_DATA_IMPORT_FAILED);
|
||||
} catch (IOException e1) {
|
||||
errors.addAll(jsonHolderForSensorFixImport.getErrorList());
|
||||
throw new AllinOneImportException(e1, errors);
|
||||
}
|
||||
errors.addAll(jsonHolderForSensorFixImport.getErrorList());
|
||||
|
||||
TimePoint firstFixAt = null;
|
||||
TimePoint lastFixAt = null;
|
||||
final ArrayList<TrackImportDTO> allData = new ArrayList<>();
|
||||
allData.addAll(jsonHolderForGpsFixImport.getImportResult());
|
||||
allData.addAll(jsonHolderForSensorFixImport.getImportResult());
|
||||
|
||||
for (TrackImportDTO result : allData) {
|
||||
final TimePoint deviceTrackStart = result.getRange().from();
|
||||
final TimePoint deviceTrackEnd = result.getRange().to();
|
||||
if (firstFixAt == null || deviceTrackStart.before(firstFixAt)) {
|
||||
firstFixAt = deviceTrackStart;
|
||||
}
|
||||
if (lastFixAt == null || deviceTrackEnd.after(lastFixAt)) {
|
||||
lastFixAt = deviceTrackEnd;
|
||||
}
|
||||
}
|
||||
|
||||
final TimePoint eventStartDate = firstFixAt;
|
||||
final TimePoint eventEndDate = lastFixAt;
|
||||
|
||||
final Event event = service.addEvent(eventName, description, eventStartDate, eventEndDate, venueName, true,
|
||||
UUID.randomUUID());
|
||||
service.addCourseAreas(event.getId(), new String[] { courseAreaName }, new UUID[] { courseAreaId });
|
||||
|
||||
final Series series = new SeriesImpl(seriesName, /* isMedal */ false, /* isFleetsCanRunInParallel */ false,
|
||||
Collections.singleton(new FleetImpl(fleetName)), Collections.emptySet(),
|
||||
/* trackedRegattaRegistry */ service);
|
||||
final ScoringScheme scoringScheme = service.getBaseDomainFactory().createScoringScheme(scoringSchemeType);
|
||||
final RankingMetricConstructor rankingMetricConstructor = RankingMetricsFactory
|
||||
.getRankingMetricConstructor(rankingMetric);
|
||||
final Regatta regatta = service.createRegatta(regattaNameAndleaderboardName, boatClassName, null, null, UUID.randomUUID(),
|
||||
Collections.singleton(series), true, scoringScheme, courseAreaId, buoyZoneRadiusInHullLengths, true,
|
||||
false, rankingMetricConstructor);
|
||||
this.ensureBoatClassDetermination(regatta);
|
||||
service.apply(new AddColumnToSeries(regattaIdentifier, seriesName, raceColumnName));
|
||||
final RegattaLeaderboard regattaLeaderboard = service.addRegattaLeaderboard(regattaIdentifier, null,
|
||||
discardThresholds);
|
||||
|
||||
final LeaderboardGroup leaderboardGroup = service.addLeaderboardGroup(UUID.randomUUID(), leaderboardGroupName,
|
||||
description, null, false, Collections.singletonList(regattaNameAndleaderboardName), null, null);
|
||||
service.updateEvent(event.getId(), event.getName(), event.getDescription(), event.getStartDate(),
|
||||
event.getEndDate(), event.getVenue().getName(), event.isPublic(),
|
||||
Collections.singleton(leaderboardGroup.getId()), event.getOfficialWebsiteURL(), event.getBaseURL(),
|
||||
event.getSailorsInfoWebsiteURLs(), event.getImages(), event.getVideos());
|
||||
|
||||
final RaceColumn raceColumn = regattaLeaderboard.getRaceColumns().iterator().next();
|
||||
final Fleet fleet = raceColumn.getFleets().iterator().next();
|
||||
|
||||
final RaceLog raceLog = raceColumn.getRaceLog(fleet);
|
||||
final LogEventAuthorImpl author = new LogEventAuthorImpl(raceLogEventAuthorName, raceLogEventPriority);
|
||||
|
||||
final TimePoint startOfTracking = firstFixAt;
|
||||
final TimePoint endOfTracking = lastFixAt;
|
||||
raceLog.add(new RaceLogStartOfTrackingEventImpl(startOfTracking, author, raceLog.getCurrentPassId()));
|
||||
raceLog.add(new RaceLogEndOfTrackingEventImpl(endOfTracking, author, raceLog.getCurrentPassId()));
|
||||
// TODO explicitly set startOfRace?
|
||||
|
||||
try {
|
||||
TimePoint startTrackingTimePoint = MillisecondsTimePoint.now();
|
||||
// this ensures that the events consistently have different timepoints to ensure a consistent result of the state analysis
|
||||
// that's why we can't jus call adapter.denoteRaceForRaceLogTracking
|
||||
final TimePoint denotationTimePoint = startTrackingTimePoint.minus(1);
|
||||
raceLog.add(new RaceLogDenoteForTrackingEventImpl(denotationTimePoint,
|
||||
service.getServerAuthor(), raceLog.getCurrentPassId(), trackedRaceName, regatta.getBoatClass(), UUID.randomUUID()));
|
||||
|
||||
raceLog.add(new RaceLogStartTrackingEventImpl(startTrackingTimePoint, author, raceLog.getCurrentPassId()));
|
||||
|
||||
final RaceHandle raceHandle = adapter.startTracking(service, regattaLeaderboard, raceColumn, fleet, true,
|
||||
correctWindDirectionByMagneticDeclination);
|
||||
|
||||
// TODO do we need to wait or is the TrackedRace guaranteed to be reachable after calling startTracking?
|
||||
raceHandle.getRace();
|
||||
|
||||
final DynamicTrackedRace trackedRace = (DynamicTrackedRace) raceColumn.getTrackedRace(fleet);
|
||||
|
||||
final WindImportResult windImportResult = new AbstractWindImporter.WindImportResult();
|
||||
final WindSourceWithAdditionalID windSource = new WindSourceWithAdditionalID(WindSourceType.EXPEDITION,
|
||||
windSourceId);
|
||||
final Map<InputStream, String> streamsWithFilenames = new HashMap<>();
|
||||
streamsWithFilenames.put(fileItem.getInputStream(), filenameWithSuffix);
|
||||
new WindImporter().importWindToWindSourceAndTrackedRaces(service, windImportResult, windSource,
|
||||
Arrays.asList(trackedRace), streamsWithFilenames);
|
||||
|
||||
return new ImporterResult(event.getId(), regattaNameAndleaderboardName, leaderboardGroupName,
|
||||
trackedRace.getRaceIdentifier(), raceColumnName, fleetName,
|
||||
jsonHolderForGpsFixImport.getImportResult(), jsonHolderForSensorFixImport.getImportResult(),
|
||||
sensorFixImporterType, errors);
|
||||
} catch (Exception e) {
|
||||
throw new AllinOneImportException(e, errors);
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureSuccessfulImport(ImportResultDTO result, String errorMessage) throws AllinOneImportException {
|
||||
if (!result.getErrorList().isEmpty()) {
|
||||
throw new AllinOneImportException(errorMessage, result.getErrorList());
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureBoatClassDetermination(Regatta regatta) throws AllinOneImportException {
|
||||
if (regatta.getBoatClass() == null) {
|
||||
throw new AllinOneImportException(ERROR_MESSAGE_BOAT_CLASS_DETERMINATION_FAILED);
|
||||
}
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.sap.sailing.server.gateway.trackfiles.impl;
|
||||
|
||||
import static com.sap.sailing.server.trackfiles.impl.ExpeditionImportFileHandler.supportedExpeditionArchiveFileExtensions;
|
||||
import static com.sap.sailing.server.trackfiles.impl.ExpeditionImportFileHandler.supportedExpeditionLogFileExtensions;
|
||||
|
||||
class ExpeditionImportFilenameUtils {
|
||||
|
||||
static String truncateFilenameExtentions(String filenameWithExtensions) {
|
||||
return removeTailIfExists(removeTailIfExists(filenameWithExtensions, supportedExpeditionArchiveFileExtensions),
|
||||
supportedExpeditionLogFileExtensions);
|
||||
}
|
||||
|
||||
private static String removeTailIfExists(String source, Iterable<String> extensionsToRemove) {
|
||||
for (String toRemove : extensionsToRemove) {
|
||||
final String tailToRemove = "." + toRemove;
|
||||
if (source.toLowerCase().endsWith(tailToRemove)) {
|
||||
return source.substring(0, source.length() - tailToRemove.length());
|
||||
}
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
package com.sap.sailing.server.gateway.trackfiles.impl;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sse.common.TimeRange;
|
||||
|
||||
/**
|
||||
* Convenience class that wraps the json objects used to render json result objects
|
||||
*/
|
||||
class ImportResultDTO {
|
||||
|
||||
private final List<ErrorImportDTO> errorList = new CopyOnWriteArrayList<>();
|
||||
private final List<TrackImportDTO> importResult = new CopyOnWriteArrayList<>();
|
||||
private final Logger logger;
|
||||
|
||||
static class TrackImportDTO {
|
||||
|
||||
private final TimeRange range;
|
||||
private final long amount;
|
||||
private final UUID device;
|
||||
|
||||
TrackImportDTO(UUID device, TimeRange range, long amount) {
|
||||
this.device = device;
|
||||
this.range = range;
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
TimeRange getRange() {
|
||||
return range;
|
||||
}
|
||||
|
||||
UUID getDevice() {
|
||||
return device;
|
||||
}
|
||||
|
||||
long getAmount() {
|
||||
return amount;
|
||||
}
|
||||
}
|
||||
|
||||
static class ErrorImportDTO {
|
||||
|
||||
private final String exUUID;
|
||||
private final String name;
|
||||
private final String message;
|
||||
private final String filename;
|
||||
private final String requestedImporter;
|
||||
|
||||
ErrorImportDTO(String name, String message) {
|
||||
this(null, name, message, null, null);
|
||||
}
|
||||
|
||||
ErrorImportDTO(String exUUID, String name, String message, String filename, String requestedImporter) {
|
||||
this.exUUID = exUUID;
|
||||
this.name = name;
|
||||
this.message = message;
|
||||
this.filename = filename;
|
||||
this.requestedImporter = requestedImporter;
|
||||
}
|
||||
|
||||
String getExUUID() {
|
||||
return exUUID;
|
||||
}
|
||||
|
||||
String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
String getRequestedImporter() {
|
||||
return requestedImporter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ImportResultDTO(Logger logger) {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
void add(String requestedImporterName, String filename, Exception exception) {
|
||||
logger.log(Level.SEVERE, "Sensordata import importer: " + requestedImporterName);
|
||||
logger.log(Level.SEVERE, "Sensordata import filename: " + filename);
|
||||
logException(exception, filename, requestedImporterName);
|
||||
}
|
||||
|
||||
void add(Exception exception) {
|
||||
logException(exception, "", "");
|
||||
}
|
||||
|
||||
private void logException(Exception exception, String filename, String requestedImporterName) {
|
||||
final String exUUID = UUID.randomUUID().toString(), exClass = exception.getClass().getName();
|
||||
logger.log(Level.SEVERE, "Sensordata import ExUUID: " + exUUID, exception);
|
||||
errorList.add(new ErrorImportDTO(exUUID, exClass, exception.getMessage(), filename, requestedImporterName));
|
||||
}
|
||||
|
||||
void noImporterSucceeded(String filename) {
|
||||
errorList.add(new ErrorImportDTO(null, null, "No importer succeeded to process file", filename, null));
|
||||
}
|
||||
|
||||
void addTrackData(TrackImportDTO trackImportDTO) {
|
||||
importResult.add(trackImportDTO);
|
||||
}
|
||||
|
||||
List<ErrorImportDTO> getErrorList() {
|
||||
return errorList;
|
||||
}
|
||||
|
||||
List<TrackImportDTO> getImportResult() {
|
||||
return importResult;
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package com.sap.sailing.server.gateway.trackfiles.impl;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.sap.sailing.server.gateway.trackfiles.impl.ImportResultDTO.ErrorImportDTO;
|
||||
import com.sap.sailing.server.gateway.trackfiles.impl.ImportResultDTO.TrackImportDTO;
|
||||
|
||||
/**
|
||||
* Utility class providing convenience methods to serialize import result objects into JSON objects.
|
||||
*/
|
||||
class ImportResultSerializer {
|
||||
|
||||
static JSONObject serializeImportResult(ImportResultDTO result) {
|
||||
final JSONObject json = new JSONObject();
|
||||
json.put("errors", serializeErrorList(result.getErrorList()));
|
||||
json.put("uploads", serializeTrackList(result.getImportResult()));
|
||||
return json;
|
||||
}
|
||||
|
||||
static <R> JSONArray serializeList(List<? extends R> list, Function<? super R, ?> mapping) {
|
||||
final JSONArray json = new JSONArray();
|
||||
list.stream().map(mapping).forEach(json::add);
|
||||
return json;
|
||||
}
|
||||
|
||||
static JSONArray serializeTrackList(List<TrackImportDTO> trackList) {
|
||||
return serializeList(trackList, track -> track.getDevice().toString());
|
||||
}
|
||||
|
||||
static JSONArray serializeErrorList(List<ErrorImportDTO> errorList) {
|
||||
return serializeList(errorList, ImportResultSerializer::serializeError);
|
||||
}
|
||||
|
||||
private static JSONObject serializeError(ErrorImportDTO error) {
|
||||
final JSONObject json = new JSONObject();
|
||||
json.put("filename", error.getFilename());
|
||||
json.put("requestedImporter", error.getRequestedImporter());
|
||||
json.put("exUUID", error.getExUUID());
|
||||
json.put("className", error.getName());
|
||||
json.put("message", error.getMessage());
|
||||
return json;
|
||||
}
|
||||
}
|
||||
-79
@@ -1,79 +0,0 @@
|
||||
package com.sap.sailing.server.gateway.trackfiles.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
|
||||
|
||||
/**
|
||||
* Convenience class that wraps the json objects used to render json result objects
|
||||
*/
|
||||
public class JsonHolder {
|
||||
private final Set<UUID> knownMapings = new HashSet<>();
|
||||
private final JSONObject jsonResponseObj = new JSONObject();
|
||||
private final JSONArray jsonErrorObj = new JSONArray();
|
||||
private final JSONArray jsonUuidObj = new JSONArray();
|
||||
private final Logger logger;
|
||||
|
||||
public JsonHolder(Logger logger) {
|
||||
this.logger = logger;
|
||||
jsonResponseObj.put("errors", jsonErrorObj);
|
||||
jsonResponseObj.put("uploads", jsonUuidObj);
|
||||
}
|
||||
|
||||
public void add(String requestedImporterName, String filename, Exception exception) {
|
||||
logger.log(Level.SEVERE, "Sensordata import importer: " + requestedImporterName);
|
||||
logger.log(Level.SEVERE, "Sensordata import filename: " + filename);
|
||||
JSONObject jsonExceptionObj = logException(exception);
|
||||
jsonExceptionObj.put("filename", filename);
|
||||
jsonExceptionObj.put("requestedImporter", requestedImporterName);
|
||||
}
|
||||
|
||||
public void add(Exception exception) {
|
||||
logException(exception);
|
||||
}
|
||||
|
||||
private JSONObject logException(Exception e) {
|
||||
final String exUUID = UUID.randomUUID().toString();
|
||||
logger.log(Level.SEVERE, "Sensordata import ExUUID: " + exUUID, e);
|
||||
JSONObject jsonExceptionObj = new JSONObject();
|
||||
jsonErrorObj.add(jsonExceptionObj);
|
||||
jsonExceptionObj.put("exUUID", exUUID);
|
||||
jsonExceptionObj.put("className", e.getClass().getName());
|
||||
jsonExceptionObj.put("message", e.getMessage());
|
||||
return jsonExceptionObj;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param deviceIdentifier
|
||||
*/
|
||||
public void addDeviceIndentifier(TrackFileImportDeviceIdentifier deviceIdentifier) {
|
||||
if (!knownMapings.contains(deviceIdentifier.getId())) {
|
||||
knownMapings.add(deviceIdentifier.getId());
|
||||
String stringRep = deviceIdentifier.getId().toString();
|
||||
jsonUuidObj.add(stringRep);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeJSONString(HttpServletResponse resp) throws IOException {
|
||||
resp.setContentType("text/html");
|
||||
jsonResponseObj.writeJSONString(resp.getWriter());
|
||||
}
|
||||
|
||||
public void noImporterSucceeded(String filename) {
|
||||
JSONObject jsonExceptionObj = new JSONObject();
|
||||
jsonErrorObj.add(jsonExceptionObj);
|
||||
jsonExceptionObj.put("filename", filename);
|
||||
jsonExceptionObj.put("message", "No importer succeeded to process file");
|
||||
}
|
||||
}
|
||||
+5
-92
@@ -1,28 +1,16 @@
|
||||
package com.sap.sailing.server.gateway.trackfiles.impl;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.fileupload.FileItem;
|
||||
import org.osgi.framework.InvalidSyntaxException;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
|
||||
import com.sap.sailing.domain.trackimport.DoubleVectorFixImporter;
|
||||
import com.sap.sailing.domain.trackimport.FormatNotSupportedException;
|
||||
import com.sap.sailing.server.gateway.impl.AbstractFileUploadServlet;
|
||||
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
|
||||
/**
|
||||
@@ -33,70 +21,13 @@ public class SensorDataImportServlet extends AbstractFileUploadServlet {
|
||||
private static final long serialVersionUID = 1120226743039934620L;
|
||||
private static final Logger logger = Logger.getLogger(SensorDataImportServlet.class.getName());
|
||||
|
||||
public void storeFixes(Iterable<DoubleVectorFix> fixes, DeviceIdentifier deviceIdentifier) {
|
||||
try {
|
||||
getService().getSensorFixStore().storeFixes(deviceIdentifier, fixes);
|
||||
} catch (NoCorrespondingServiceRegisteredException e) {
|
||||
logger.log(Level.WARNING, "Could not store fix for " + deviceIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the requested importer in the importers provided by the OSGi registry and imports the priovided sensor
|
||||
* data file.
|
||||
*
|
||||
* @param files
|
||||
* the file items together with the names of the importer to use for importing the respective file's
|
||||
* contents; the importer names are matched against {@link DoubleVectorFixImporter#getType()} for all
|
||||
* importers found registered in the OSGi registry. The first matching importer is used for the file. The
|
||||
* importer is selected on a per-file basis.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private void importFiles(boolean enableDownsampler, JsonHolder jsonResult, Iterable<Pair<String, FileItem>> files)
|
||||
throws IOException {
|
||||
final Collection<DoubleVectorFixImporter> availableImporters = new LinkedHashSet<>();
|
||||
availableImporters.addAll(getOSGiRegisteredImporters());
|
||||
for (Pair<String, FileItem> file : files) {
|
||||
final String requestedImporterName = file.getA();
|
||||
final FileItem fi = file.getB();
|
||||
DoubleVectorFixImporter importerToUse = null;
|
||||
for (DoubleVectorFixImporter candidate : availableImporters) {
|
||||
if (candidate.getType().equals(requestedImporterName)) {
|
||||
importerToUse = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (importerToUse == null) {
|
||||
throw new RuntimeException("Sensor importer not found: " + requestedImporterName);
|
||||
}
|
||||
logger.log(Level.INFO,
|
||||
"Going to import sensor data file with importer " + importerToUse.getClass().getSimpleName());
|
||||
try (BufferedInputStream in = new BufferedInputStream(fi.getInputStream())) {
|
||||
final String filename = fi.getName();
|
||||
try {
|
||||
importerToUse.importFixes(in, new DoubleVectorFixImporter.Callback() {
|
||||
@Override
|
||||
public void addFixes(Iterable<DoubleVectorFix> fixes, TrackFileImportDeviceIdentifier device) {
|
||||
storeFixes(fixes, device);
|
||||
jsonResult.addDeviceIndentifier(device);
|
||||
}
|
||||
}, filename, requestedImporterName, enableDownsampler);
|
||||
logger.log(Level.INFO, "Successfully imported file " + requestedImporterName);
|
||||
} catch (FormatNotSupportedException e) {
|
||||
jsonResult.add(requestedImporterName, filename, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the uploaded file items.
|
||||
*/
|
||||
@Override
|
||||
protected void process(List<FileItem> fileItems, HttpServletRequest req, HttpServletResponse resp)
|
||||
throws IOException {
|
||||
JsonHolder jsonResult = new JsonHolder(logger);
|
||||
ImportResultDTO importResult = new ImportResultDTO(logger);
|
||||
boolean enableDownsampler = false;
|
||||
try {
|
||||
String importerName = null;
|
||||
@@ -116,30 +47,12 @@ public class SensorDataImportServlet extends AbstractFileUploadServlet {
|
||||
filesAndImporterNames.add(new Pair<>(importerName, fi));
|
||||
}
|
||||
}
|
||||
importFiles(enableDownsampler, jsonResult, filesAndImporterNames);
|
||||
new SensorDataImporter(getService(), getContext()).importFiles(enableDownsampler, importResult, filesAndImporterNames);
|
||||
} catch (Exception e) {
|
||||
jsonResult.add(e);
|
||||
importResult.add(e);
|
||||
} finally {
|
||||
jsonResult.writeJSONString(resp);
|
||||
resp.setContentType("text/html;charset=UTF-8");
|
||||
ImportResultSerializer.serializeImportResult(importResult).writeJSONString(resp.getWriter());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all {@link DoubleVectorFixImporter} service references in the OSGi context.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private Collection<DoubleVectorFixImporter> getOSGiRegisteredImporters() {
|
||||
List<DoubleVectorFixImporter> result = new ArrayList<>();
|
||||
Collection<ServiceReference<DoubleVectorFixImporter>> refs;
|
||||
try {
|
||||
refs = getContext().getServiceReferences(DoubleVectorFixImporter.class, null);
|
||||
for (ServiceReference<DoubleVectorFixImporter> ref : refs) {
|
||||
result.add(getContext().getService(ref));
|
||||
}
|
||||
} catch (InvalidSyntaxException e) {
|
||||
logger.log(Level.WARNING, "Could not create OSGi filter");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
package com.sap.sailing.server.gateway.trackfiles.impl;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apache.commons.fileupload.FileItem;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.InvalidSyntaxException;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
|
||||
import com.sap.sailing.domain.trackimport.DoubleVectorFixImporter;
|
||||
import com.sap.sailing.domain.trackimport.FormatNotSupportedException;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sailing.server.gateway.trackfiles.impl.ImportResultDTO.TrackImportDTO;
|
||||
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.TimeRange;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
|
||||
public class SensorDataImporter {
|
||||
private static final Logger logger = Logger.getLogger(SensorDataImporter.class.getName());
|
||||
|
||||
private final RacingEventService service;
|
||||
private final BundleContext context;
|
||||
|
||||
public SensorDataImporter(RacingEventService service, BundleContext context) {
|
||||
this.service = service;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the requested importer in the importers provided by the OSGi registry and imports the priovided sensor
|
||||
* data file.
|
||||
*
|
||||
* @param importerNamesAndFiles
|
||||
* the file items together with the names of the importer to use for importing the respective file's
|
||||
* contents; the importer names are matched against {@link DoubleVectorFixImporter#getType()} for all
|
||||
* importers found registered in the OSGi registry. The first matching importer is used for the file. The
|
||||
* importer is selected on a per-file basis.
|
||||
* @return
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void importFiles(boolean enableDownsampler, ImportResultDTO result, Iterable<Pair<String, FileItem>> importerNamesAndFiles)
|
||||
throws IOException {
|
||||
final Collection<DoubleVectorFixImporter> availableImporters = new LinkedHashSet<>();
|
||||
availableImporters.addAll(getOSGiRegisteredImporters());
|
||||
for (Pair<String, FileItem> file : importerNamesAndFiles) {
|
||||
final String requestedImporterName = file.getA();
|
||||
final FileItem fi = file.getB();
|
||||
DoubleVectorFixImporter importerToUse = null;
|
||||
for (DoubleVectorFixImporter candidate : availableImporters) {
|
||||
if (candidate.getType().equals(requestedImporterName)) {
|
||||
importerToUse = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (importerToUse == null) {
|
||||
throw new RuntimeException("Sensor importer not found: " + requestedImporterName);
|
||||
}
|
||||
logger.log(Level.INFO,
|
||||
"Going to import sensor data file with importer " + importerToUse.getClass().getSimpleName());
|
||||
|
||||
HashSet<TrackFileImportDeviceIdentifier> deviceIds = new HashSet<>();
|
||||
try (BufferedInputStream in = new BufferedInputStream(fi.getInputStream())) {
|
||||
final String filename = fi.getName();
|
||||
try {
|
||||
importerToUse.importFixes(in, new DoubleVectorFixImporter.Callback() {
|
||||
@Override
|
||||
public void addFixes(Iterable<DoubleVectorFix> fixes, TrackFileImportDeviceIdentifier device) {
|
||||
storeFixes(fixes, device);
|
||||
deviceIds.add(device);
|
||||
}
|
||||
}, filename, requestedImporterName, enableDownsampler);
|
||||
logger.log(Level.INFO, "Successfully imported file " + requestedImporterName);
|
||||
} catch (FormatNotSupportedException e) {
|
||||
result.add(requestedImporterName, filename, e);
|
||||
}
|
||||
}
|
||||
for (TrackFileImportDeviceIdentifier device : deviceIds) {
|
||||
TimeRange range = service.getSensorFixStore().getTimeRangeCoveredByFixes(device);
|
||||
long amount = service.getSensorFixStore().getNumberOfFixes(device);
|
||||
result.addTrackData(new TrackImportDTO(device.getId(), range, amount));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void storeFixes(Iterable<DoubleVectorFix> fixes, DeviceIdentifier deviceIdentifier) {
|
||||
try {
|
||||
service.getSensorFixStore().storeFixes(deviceIdentifier, fixes);
|
||||
} catch (NoCorrespondingServiceRegisteredException e) {
|
||||
logger.log(Level.WARNING, "Could not store fix for " + deviceIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all {@link DoubleVectorFixImporter} service references in the OSGi context.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private Collection<DoubleVectorFixImporter> getOSGiRegisteredImporters() {
|
||||
List<DoubleVectorFixImporter> result = new ArrayList<>();
|
||||
Collection<ServiceReference<DoubleVectorFixImporter>> refs;
|
||||
try {
|
||||
refs = context.getServiceReferences(DoubleVectorFixImporter.class, null);
|
||||
for (ServiceReference<DoubleVectorFixImporter> ref : refs) {
|
||||
result.add(context.getService(ref));
|
||||
}
|
||||
} catch (InvalidSyntaxException e) {
|
||||
logger.log(Level.WARNING, "Could not create OSGi filter");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+6
-106
@@ -1,33 +1,18 @@
|
||||
package com.sap.sailing.server.gateway.trackfiles.impl;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.fileupload.FileItem;
|
||||
import org.osgi.framework.Filter;
|
||||
import org.osgi.framework.InvalidSyntaxException;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
|
||||
import com.sap.sailing.domain.trackimport.FormatNotSupportedException;
|
||||
import com.sap.sailing.domain.trackimport.GPSFixImporter;
|
||||
import com.sap.sailing.domain.trackimport.GPSFixImporter.Callback;
|
||||
import com.sap.sailing.server.gateway.impl.AbstractFileUploadServlet;
|
||||
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
|
||||
/**
|
||||
@@ -53,92 +38,10 @@ public class TrackFilesImportServlet extends AbstractFileUploadServlet {
|
||||
private static final long serialVersionUID = 1120226743039934620L;
|
||||
private static final Logger logger = Logger.getLogger(TrackFilesImportServlet.class.getName());
|
||||
|
||||
public void storeFix(GPSFix fix, DeviceIdentifier deviceIdentifier) {
|
||||
try {
|
||||
getService().getSensorFixStore().storeFix(deviceIdentifier, fix);
|
||||
} catch (NoCorrespondingServiceRegisteredException e) {
|
||||
logger.log(Level.WARNING, "Could not store fix for " + deviceIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
Collection<GPSFixImporter> getGPSFixImporters(String fileExtension) {
|
||||
List<GPSFixImporter> result = new ArrayList<>();
|
||||
Collection<ServiceReference<GPSFixImporter>> refs;
|
||||
try {
|
||||
Filter filter = null;
|
||||
if (fileExtension != null) {
|
||||
filter = getContext()
|
||||
.createFilter(String.format("(%s=%s)", GPSFixImporter.FILE_EXTENSION_PROPERTY, fileExtension));
|
||||
}
|
||||
refs = getContext().getServiceReferences(GPSFixImporter.class, filter == null ? null : filter.toString());
|
||||
for (ServiceReference<GPSFixImporter> ref : refs) {
|
||||
result.add(getContext().getService(ref));
|
||||
}
|
||||
} catch (InvalidSyntaxException e) {
|
||||
logger.log(Level.WARNING, "Could not create OSGi filter for file extension");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void importFiles(Iterable<Pair<String, FileItem>> files, JsonHolder jsonResult,
|
||||
GPSFixImporter preferredImporter) throws IOException {
|
||||
for (Pair<String, FileItem> pair : files) {
|
||||
final String fileName = pair.getA();
|
||||
final FileItem fileItem = pair.getB();
|
||||
String fileExt = null;
|
||||
if (fileName.contains(".")) {
|
||||
fileExt = fileName.substring(fileName.lastIndexOf(".") + 1);
|
||||
}
|
||||
Set<GPSFixImporter> importersToTry = new LinkedHashSet<>();
|
||||
if (preferredImporter != null) {
|
||||
importersToTry.add(preferredImporter);
|
||||
}
|
||||
importersToTry.addAll(getGPSFixImporters(fileExt));
|
||||
importersToTry.addAll(getGPSFixImporters(null));
|
||||
logger.log(Level.INFO, "System knows " + importersToTry.size() + " importers: "
|
||||
+ importersToTry.stream().map(i -> i.getType()).collect(Collectors.joining(", ")));
|
||||
AtomicBoolean succeeded = new AtomicBoolean(false);
|
||||
parsersLoop: for (GPSFixImporter importer : importersToTry) {
|
||||
|
||||
logger.log(Level.INFO, "Trying to import file " + fileName + " with importer " + importer.getType());
|
||||
try (BufferedInputStream in = new BufferedInputStream(fileItem.getInputStream())) {
|
||||
try {
|
||||
boolean ok = importer.importFixes(in, new Callback() {
|
||||
@Override
|
||||
public void addFix(GPSFix fix, TrackFileImportDeviceIdentifier device) {
|
||||
storeFix(fix, device);
|
||||
jsonResult.addDeviceIndentifier(device);
|
||||
}
|
||||
}, true, fileName);
|
||||
if (ok) {
|
||||
succeeded.set(ok);
|
||||
} else {
|
||||
logger.log(Level.FINE,
|
||||
"Importer " + importer.getType() + " did not succesfully import fixes");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.INFO, "Failed with " + e.getClass().getSimpleName()
|
||||
+ " while importing file using " + importer.getType());
|
||||
if (importer == preferredImporter) {
|
||||
jsonResult.add(importer.getClass().getName(), fileName, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (succeeded.get()) {
|
||||
logger.log(Level.INFO, "Successfully imported file " + fileName + " using " + importer.getType());
|
||||
break parsersLoop;
|
||||
}
|
||||
}
|
||||
if (!succeeded.get()) {
|
||||
jsonResult.noImporterSucceeded(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void process(List<FileItem> fileItems, HttpServletRequest req, HttpServletResponse resp)
|
||||
throws IOException {
|
||||
JsonHolder jsonResult = new JsonHolder(logger);
|
||||
ImportResultDTO importResult = new ImportResultDTO(logger);
|
||||
try {
|
||||
String prefImporterType = null;
|
||||
List<Pair<String, FileItem>> files = new ArrayList<>();
|
||||
@@ -151,19 +54,16 @@ public class TrackFilesImportServlet extends AbstractFileUploadServlet {
|
||||
}
|
||||
}
|
||||
}
|
||||
GPSFixImporter preferredImporter = null;
|
||||
if (prefImporterType != null && !prefImporterType.isEmpty()) {
|
||||
preferredImporter = getServiceFinderFactory().createServiceFinder(GPSFixImporter.class)
|
||||
.findService(prefImporterType);
|
||||
}
|
||||
importFiles(files, jsonResult, preferredImporter);
|
||||
new TrackFilesImporter(getService(), getServiceFinderFactory(), getContext()).importFixes(importResult,
|
||||
prefImporterType, files);
|
||||
// setJsonResponseHeader(resp);
|
||||
// DO NOT set a JSON response header. This causes the browser to wrap the response in a
|
||||
// <pre> tag when uploading from GWT, as this is an AJAX-request inside an iFrame.
|
||||
} catch (Exception e) {
|
||||
jsonResult.add(e);
|
||||
importResult.add(e);
|
||||
} finally {
|
||||
jsonResult.writeJSONString(resp);
|
||||
resp.setContentType("text/html;charset=UTF-8");
|
||||
ImportResultSerializer.serializeImportResult(importResult).writeJSONString(resp.getWriter());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
package com.sap.sailing.server.gateway.trackfiles.impl;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.fileupload.FileItem;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.Filter;
|
||||
import org.osgi.framework.InvalidSyntaxException;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
|
||||
import com.sap.sailing.domain.trackimport.GPSFixImporter;
|
||||
import com.sap.sailing.domain.trackimport.GPSFixImporter.Callback;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sailing.server.gateway.trackfiles.impl.ImportResultDTO.TrackImportDTO;
|
||||
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.TimeRange;
|
||||
import com.sap.sse.common.TypeBasedServiceFinderFactory;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
|
||||
public class TrackFilesImporter {
|
||||
private static final Logger logger = Logger.getLogger(TrackFilesImporter.class.getName());
|
||||
|
||||
private final RacingEventService service;
|
||||
private final TypeBasedServiceFinderFactory serviceFinderFactory;
|
||||
private final BundleContext context;
|
||||
|
||||
public TrackFilesImporter(RacingEventService service, TypeBasedServiceFinderFactory serviceFinderFactory, BundleContext context) {
|
||||
this.service = service;
|
||||
this.serviceFinderFactory = serviceFinderFactory;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public void importFixes(ImportResultDTO jsonResult, String prefImporterType, List<Pair<String, FileItem>> files)
|
||||
throws IOException {
|
||||
GPSFixImporter preferredImporter = null;
|
||||
if (prefImporterType != null && !prefImporterType.isEmpty()) {
|
||||
preferredImporter = serviceFinderFactory.createServiceFinder(GPSFixImporter.class)
|
||||
.findService(prefImporterType);
|
||||
}
|
||||
importFilesWithPreferredImporter(files, jsonResult, preferredImporter);
|
||||
}
|
||||
|
||||
void importFilesWithPreferredImporter(Iterable<Pair<String, FileItem>> files, ImportResultDTO jsonResult,
|
||||
GPSFixImporter preferredImporter) throws IOException {
|
||||
for (Pair<String, FileItem> pair : files) {
|
||||
final String fileName = pair.getA();
|
||||
final FileItem fileItem = pair.getB();
|
||||
String fileExt = null;
|
||||
if (fileName.contains(".")) {
|
||||
fileExt = fileName.substring(fileName.lastIndexOf(".") + 1);
|
||||
}
|
||||
Set<GPSFixImporter> importersToTry = new LinkedHashSet<>();
|
||||
if (preferredImporter != null) {
|
||||
importersToTry.add(preferredImporter);
|
||||
}
|
||||
importersToTry.addAll(getGPSFixImporters(fileExt));
|
||||
importersToTry.addAll(getGPSFixImporters(null));
|
||||
logger.log(Level.INFO, "System knows " + importersToTry.size() + " importers: "
|
||||
+ importersToTry.stream().map(i -> i.getType()).collect(Collectors.joining(", ")));
|
||||
AtomicBoolean succeeded = new AtomicBoolean(false);
|
||||
parsersLoop: for (GPSFixImporter importer : importersToTry) {
|
||||
|
||||
HashSet<TrackFileImportDeviceIdentifier> deviceIds = new HashSet<>();
|
||||
logger.log(Level.INFO, "Trying to import file " + fileName + " with importer " + importer.getType());
|
||||
try (BufferedInputStream in = new BufferedInputStream(fileItem.getInputStream())) {
|
||||
try {
|
||||
boolean ok = importer.importFixes(in, new Callback() {
|
||||
@Override
|
||||
public void addFix(GPSFix fix, TrackFileImportDeviceIdentifier device) {
|
||||
storeFix(fix, device);
|
||||
deviceIds.add(device);
|
||||
}
|
||||
}, true, fileName);
|
||||
if (ok) {
|
||||
succeeded.set(ok);
|
||||
} else {
|
||||
logger.log(Level.FINE,
|
||||
"Importer " + importer.getType() + " did not succesfully import fixes");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.INFO, "Failed with " + e.getClass().getSimpleName()
|
||||
+ " while importing file using " + importer.getType());
|
||||
if (importer == preferredImporter) {
|
||||
jsonResult.add(importer.getClass().getName(), fileName, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (TrackFileImportDeviceIdentifier device : deviceIds) {
|
||||
additionalDataExtractor(jsonResult, device);
|
||||
}
|
||||
if (succeeded.get()) {
|
||||
logger.log(Level.INFO, "Successfully imported file " + fileName + " using " + importer.getType());
|
||||
break parsersLoop;
|
||||
}
|
||||
}
|
||||
if (!succeeded.get()) {
|
||||
jsonResult.noImporterSucceeded(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void additionalDataExtractor(ImportResultDTO jsonResult, TrackFileImportDeviceIdentifier device)
|
||||
throws TransformationException {
|
||||
TimeRange range = service.getSensorFixStore().getTimeRangeCoveredByFixes(device);
|
||||
long amount = service.getSensorFixStore().getNumberOfFixes(device);
|
||||
jsonResult.addTrackData(new TrackImportDTO(device.getId(), range, amount));
|
||||
}
|
||||
|
||||
|
||||
void storeFix(GPSFix fix, DeviceIdentifier deviceIdentifier) {
|
||||
try {
|
||||
service.getSensorFixStore().storeFix(deviceIdentifier, fix);
|
||||
} catch (NoCorrespondingServiceRegisteredException e) {
|
||||
logger.log(Level.WARNING, "Could not store fix for " + deviceIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
Collection<GPSFixImporter> getGPSFixImporters(String fileExtension) {
|
||||
List<GPSFixImporter> result = new ArrayList<>();
|
||||
Collection<ServiceReference<GPSFixImporter>> refs;
|
||||
try {
|
||||
Filter filter = null;
|
||||
if (fileExtension != null) {
|
||||
filter = context
|
||||
.createFilter(String.format("(%s=%s)", GPSFixImporter.FILE_EXTENSION_PROPERTY, fileExtension));
|
||||
}
|
||||
refs = context.getServiceReferences(GPSFixImporter.class, filter == null ? null : filter.toString());
|
||||
for (ServiceReference<GPSFixImporter> ref : refs) {
|
||||
result.add(context.getService(ref));
|
||||
}
|
||||
} catch (InvalidSyntaxException e) {
|
||||
logger.log(Level.WARNING, "Could not create OSGi filter for file extension");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+8
-160
@@ -1,12 +1,7 @@
|
||||
package com.sap.sailing.server.gateway.windimport;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -24,127 +19,19 @@ import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.trackimport.FormatNotSupportedException;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.server.gateway.SailingServerHttpServlet;
|
||||
import com.sap.sailing.server.gateway.windimport.AbstractWindImportServlet.WindImportResult.RaceEntry;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sailing.server.gateway.windimport.AbstractWindImporter.UploadRequest;
|
||||
import com.sap.sailing.server.gateway.windimport.AbstractWindImporter.WindImportResult;
|
||||
|
||||
public abstract class AbstractWindImportServlet extends SailingServerHttpServlet {
|
||||
private static final Logger logger = Logger.getLogger(AbstractWindImportServlet.class.getName());
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static class UploadRequest {
|
||||
public String boatId;
|
||||
public final List<FileItem> files = new ArrayList<FileItem>();
|
||||
public List<RegattaAndRaceIdentifier> races = new ArrayList<RegattaAndRaceIdentifier>();;
|
||||
}
|
||||
|
||||
static class WindImportResult {
|
||||
private Date first;
|
||||
private Date last;
|
||||
public String error;
|
||||
|
||||
public final List<RaceEntry> raceEntries = new ArrayList<RaceEntry>();
|
||||
|
||||
public Date getFirst() {
|
||||
return first;
|
||||
}
|
||||
|
||||
public Date getLast() {
|
||||
return last;
|
||||
}
|
||||
|
||||
public void update(Wind newWind) {
|
||||
Date newDate = newWind.getTimePoint().asDate();
|
||||
if (this.first == null || newDate.before(this.first)) {
|
||||
this.first = newDate;
|
||||
}
|
||||
if (this.last == null || newDate.after(this.last)) {
|
||||
this.last = newDate;
|
||||
}
|
||||
}
|
||||
|
||||
RaceEntry addRaceEntry(String regattaName, String raceName) {
|
||||
RaceEntry raceEntry = new RaceEntry(regattaName, raceName);
|
||||
raceEntries.add(raceEntry);
|
||||
return raceEntry;
|
||||
}
|
||||
|
||||
static class RaceEntry {
|
||||
public final String regattaName;
|
||||
public final String raceName;
|
||||
private int count;
|
||||
private Date first;
|
||||
private Date last;
|
||||
|
||||
private RaceEntry(String regattaName, String raceName) {
|
||||
this.regattaName = regattaName;
|
||||
this.raceName = raceName;
|
||||
}
|
||||
|
||||
public void update(Wind newWind) {
|
||||
count++;
|
||||
Date newDate = newWind.getTimePoint().asDate();
|
||||
if (this.first == null || newDate.before(this.first)) {
|
||||
this.first = newDate;
|
||||
}
|
||||
if (this.last == null || newDate.after(this.last)) {
|
||||
this.last = newDate;
|
||||
}
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public Date getFirst() {
|
||||
return first;
|
||||
}
|
||||
|
||||
public Date getLast() {
|
||||
return last;
|
||||
}
|
||||
|
||||
private JSONObject json() {
|
||||
JSONObject result = new JSONObject();
|
||||
result.put("regattaName", regattaName);
|
||||
result.put("raceName", raceName);
|
||||
result.put("count", getCount());
|
||||
if (getFirst() != null) {
|
||||
result.put("first", getFirst().getTime());
|
||||
}
|
||||
if (getLast() != null) {
|
||||
result.put("last", getLast().getTime());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public JSONObject json() {
|
||||
JSONObject result = new JSONObject();
|
||||
if (getFirst() != null) {
|
||||
result.put("first", getFirst().getTime());
|
||||
}
|
||||
if (getLast() != null) {
|
||||
result.put("last", getLast().getTime());
|
||||
}
|
||||
result.put("error", error);
|
||||
JSONArray raceEntriesJson = new JSONArray();
|
||||
for (RaceEntry raceEntry : raceEntries) {
|
||||
if (raceEntry.count > 0) {
|
||||
raceEntriesJson.add(raceEntry.json());
|
||||
}
|
||||
}
|
||||
result.put("raceEntries", raceEntriesJson);
|
||||
return result;
|
||||
}
|
||||
|
||||
private final AbstractWindImporter importer;
|
||||
|
||||
public AbstractWindImportServlet(AbstractWindImporter importer) {
|
||||
this.importer = importer;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -157,41 +44,7 @@ public abstract class AbstractWindImportServlet extends SailingServerHttpServlet
|
||||
WindImportResult windImportResult = new WindImportResult();
|
||||
try {
|
||||
UploadRequest uploadRequest = readRequest(request);
|
||||
WindSource windSource = getWindSource(uploadRequest);
|
||||
List<DynamicTrackedRace> trackedRaces = new ArrayList<DynamicTrackedRace>();
|
||||
if (uploadRequest.races.size() > 0) {
|
||||
for (RegattaAndRaceIdentifier raceEntry : uploadRequest.races) {
|
||||
DynamicTrackedRace trackedRace = getService().getTrackedRace(raceEntry);
|
||||
if (trackedRace != null) {
|
||||
trackedRaces.add(trackedRace);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (Regatta regatta : getService().getAllRegattas()) {
|
||||
for (RaceDefinition raceDefinition : regatta.getAllRaces()) {
|
||||
trackedRaces.add(getService().getTrackedRegatta(regatta).getTrackedRace(raceDefinition));
|
||||
}
|
||||
}
|
||||
}
|
||||
final Map<InputStream, String> streamsWithFilenames = new HashMap<>();
|
||||
for (FileItem file : uploadRequest.files) {
|
||||
streamsWithFilenames.put(file.getInputStream(), file.getName());
|
||||
}
|
||||
Iterable<Wind> windFixes = importWind(streamsWithFilenames);
|
||||
if (!Util.isEmpty(windFixes)) {
|
||||
for (DynamicTrackedRace trackedRace : trackedRaces) {
|
||||
RegattaAndRaceIdentifier raceIdentifier = trackedRace.getRaceIdentifier();
|
||||
RaceEntry raceEntry = windImportResult.addRaceEntry(raceIdentifier.getRegattaName(),
|
||||
raceIdentifier.getRaceName());
|
||||
for (Wind wind : windFixes) {
|
||||
windImportResult.update(wind);
|
||||
if (trackedRace.recordWind(wind, windSource)) {
|
||||
raceEntry.update(wind);
|
||||
}
|
||||
}
|
||||
getService().getPolarDataService().insertExistingFixes(trackedRace);
|
||||
}
|
||||
}
|
||||
importer.importWindForUploadRequest(getService(), windImportResult, uploadRequest);
|
||||
// Use text/html to prevent browsers from wrapping the response body,
|
||||
// see "Handling File Upload Responses in GWT" at http://www.artofsolving.com/node/50
|
||||
} catch (Exception e) {
|
||||
@@ -202,11 +55,6 @@ public abstract class AbstractWindImportServlet extends SailingServerHttpServlet
|
||||
response.getWriter().append(windImportResult.json().toJSONString());
|
||||
}
|
||||
|
||||
protected abstract Iterable<Wind> importWind(Map<InputStream, String> streamsWithFilenames)
|
||||
throws IOException, InterruptedException, FormatNotSupportedException;
|
||||
|
||||
protected abstract WindSource getWindSource(UploadRequest uploadRequest);
|
||||
|
||||
private UploadRequest readRequest(HttpServletRequest req) throws FileUploadException, ParseException {
|
||||
UploadRequest result = new UploadRequest();
|
||||
// http://commons.apache.org/fileupload/using.html
|
||||
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
package com.sap.sailing.server.gateway.windimport;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.fileupload.FileItem;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.trackimport.FormatNotSupportedException;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sailing.server.gateway.windimport.AbstractWindImporter.WindImportResult.RaceEntry;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public abstract class AbstractWindImporter {
|
||||
public static class UploadRequest {
|
||||
public String boatId;
|
||||
public final List<FileItem> files = new ArrayList<FileItem>();
|
||||
public List<RegattaAndRaceIdentifier> races = new ArrayList<RegattaAndRaceIdentifier>();;
|
||||
}
|
||||
|
||||
public static class WindImportResult {
|
||||
private Date first;
|
||||
private Date last;
|
||||
public String error;
|
||||
|
||||
public final List<RaceEntry> raceEntries = new ArrayList<RaceEntry>();
|
||||
|
||||
public Date getFirst() {
|
||||
return first;
|
||||
}
|
||||
|
||||
public Date getLast() {
|
||||
return last;
|
||||
}
|
||||
|
||||
public void update(Wind newWind) {
|
||||
Date newDate = newWind.getTimePoint().asDate();
|
||||
if (this.first == null || newDate.before(this.first)) {
|
||||
this.first = newDate;
|
||||
}
|
||||
if (this.last == null || newDate.after(this.last)) {
|
||||
this.last = newDate;
|
||||
}
|
||||
}
|
||||
|
||||
RaceEntry addRaceEntry(String regattaName, String raceName) {
|
||||
RaceEntry raceEntry = new RaceEntry(regattaName, raceName);
|
||||
raceEntries.add(raceEntry);
|
||||
return raceEntry;
|
||||
}
|
||||
|
||||
static class RaceEntry {
|
||||
public final String regattaName;
|
||||
public final String raceName;
|
||||
private int count;
|
||||
private Date first;
|
||||
private Date last;
|
||||
|
||||
private RaceEntry(String regattaName, String raceName) {
|
||||
this.regattaName = regattaName;
|
||||
this.raceName = raceName;
|
||||
}
|
||||
|
||||
public void update(Wind newWind) {
|
||||
count++;
|
||||
Date newDate = newWind.getTimePoint().asDate();
|
||||
if (this.first == null || newDate.before(this.first)) {
|
||||
this.first = newDate;
|
||||
}
|
||||
if (this.last == null || newDate.after(this.last)) {
|
||||
this.last = newDate;
|
||||
}
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public Date getFirst() {
|
||||
return first;
|
||||
}
|
||||
|
||||
public Date getLast() {
|
||||
return last;
|
||||
}
|
||||
|
||||
private JSONObject json() {
|
||||
JSONObject result = new JSONObject();
|
||||
result.put("regattaName", regattaName);
|
||||
result.put("raceName", raceName);
|
||||
result.put("count", getCount());
|
||||
if (getFirst() != null) {
|
||||
result.put("first", getFirst().getTime());
|
||||
}
|
||||
if (getLast() != null) {
|
||||
result.put("last", getLast().getTime());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public JSONObject json() {
|
||||
JSONObject result = new JSONObject();
|
||||
if (getFirst() != null) {
|
||||
result.put("first", getFirst().getTime());
|
||||
}
|
||||
if (getLast() != null) {
|
||||
result.put("last", getLast().getTime());
|
||||
}
|
||||
result.put("error", error);
|
||||
JSONArray raceEntriesJson = new JSONArray();
|
||||
for (RaceEntry raceEntry : raceEntries) {
|
||||
if (raceEntry.count > 0) {
|
||||
raceEntriesJson.add(raceEntry.json());
|
||||
}
|
||||
}
|
||||
result.put("raceEntries", raceEntriesJson);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public void importWindForUploadRequest(RacingEventService service, WindImportResult windImportResult, UploadRequest uploadRequest)
|
||||
throws IOException, InterruptedException, FormatNotSupportedException {
|
||||
WindSource windSource = getWindSource(uploadRequest);
|
||||
List<DynamicTrackedRace> trackedRaces = new ArrayList<DynamicTrackedRace>();
|
||||
if (uploadRequest.races.size() > 0) {
|
||||
for (RegattaAndRaceIdentifier raceEntry : uploadRequest.races) {
|
||||
DynamicTrackedRace trackedRace = service.getTrackedRace(raceEntry);
|
||||
if (trackedRace != null) {
|
||||
trackedRaces.add(trackedRace);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (Regatta regatta : service.getAllRegattas()) {
|
||||
for (RaceDefinition raceDefinition : regatta.getAllRaces()) {
|
||||
trackedRaces.add(service.getTrackedRegatta(regatta).getTrackedRace(raceDefinition));
|
||||
}
|
||||
}
|
||||
}
|
||||
final Map<InputStream, String> streamsWithFilenames = new HashMap<>();
|
||||
for (FileItem file : uploadRequest.files) {
|
||||
streamsWithFilenames.put(file.getInputStream(), file.getName());
|
||||
}
|
||||
importWindToWindSourceAndTrackedRaces(service, windImportResult, windSource, trackedRaces, streamsWithFilenames);
|
||||
}
|
||||
|
||||
public void importWindToWindSourceAndTrackedRaces(RacingEventService service, WindImportResult windImportResult, WindSource windSource,
|
||||
List<DynamicTrackedRace> trackedRaces, final Map<InputStream, String> streamsWithFilenames)
|
||||
throws IOException, InterruptedException, FormatNotSupportedException {
|
||||
Iterable<Wind> windFixes = importWind(streamsWithFilenames);
|
||||
if (!Util.isEmpty(windFixes)) {
|
||||
for (DynamicTrackedRace trackedRace : trackedRaces) {
|
||||
RegattaAndRaceIdentifier raceIdentifier = trackedRace.getRaceIdentifier();
|
||||
RaceEntry raceEntry = windImportResult.addRaceEntry(raceIdentifier.getRegattaName(),
|
||||
raceIdentifier.getRaceName());
|
||||
for (Wind wind : windFixes) {
|
||||
windImportResult.update(wind);
|
||||
if (trackedRace.recordWind(wind, windSource)) {
|
||||
raceEntry.update(wind);
|
||||
}
|
||||
}
|
||||
service.getPolarDataService().insertExistingFixes(trackedRace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Iterable<Wind> importWind(Map<InputStream, String> streamsWithFilenames)
|
||||
throws IOException, InterruptedException, FormatNotSupportedException;
|
||||
|
||||
protected abstract WindSource getWindSource(UploadRequest uploadRequest);
|
||||
}
|
||||
+2
-110
@@ -1,119 +1,11 @@
|
||||
package com.sap.sailing.server.gateway.windimport.bravo;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.WindImpl;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceWithAdditionalID;
|
||||
import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
|
||||
import com.sap.sailing.domain.trackimport.BaseDoubleVectorFixImporter.Callback;
|
||||
import com.sap.sailing.domain.trackimport.FormatNotSupportedException;
|
||||
import com.sap.sailing.server.gateway.windimport.AbstractWindImportServlet;
|
||||
import com.sap.sailing.server.trackfiles.impl.BaseBravoDataImporterImpl;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
public class BravoWindImportServlet extends AbstractWindImportServlet {
|
||||
private static final String BRAVO_WIND_IMPORT = "Bravo Wind Import";
|
||||
private static final String GZIP_SUFFIX = ".gz";
|
||||
private static final long serialVersionUID = -4547876638456305135L;
|
||||
private static final Logger logger = Logger.getLogger(BravoWindImportServlet.class.getName());
|
||||
|
||||
@Override
|
||||
protected WindSource getWindSource(UploadRequest uploadRequest) {
|
||||
final WindSource windSource;
|
||||
final String sourceName;
|
||||
logger.info("Importing Bravo wind data from "+uploadRequest.files);
|
||||
if (uploadRequest.files != null && !uploadRequest.files.isEmpty()) {
|
||||
sourceName = uploadRequest.files.stream().map(f->f.getName()).collect(Collectors.joining(", "));
|
||||
} else {
|
||||
sourceName = BRAVO_WIND_IMPORT;
|
||||
}
|
||||
windSource = new WindSourceWithAdditionalID(WindSourceType.EXPEDITION, sourceName + "@" + MillisecondsTimePoint.now());
|
||||
return windSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterable<Wind> importWind(Map<InputStream, String> inputStreamsAndFilenames) throws IOException, InterruptedException, FormatNotSupportedException {
|
||||
final Iterable<Wind> result;
|
||||
if (inputStreamsAndFilenames != null && inputStreamsAndFilenames.size() == 1) {
|
||||
logger.info("Reading Bravo wind data from "+inputStreamsAndFilenames.values().iterator().next());
|
||||
result = readWind(inputStreamsAndFilenames.values().iterator().next(), inputStreamsAndFilenames.keySet().iterator().next());
|
||||
} else {
|
||||
final List<Wind> windList = new LinkedList<>();
|
||||
for (final Entry<InputStream, String> inputStreamAndFileName : inputStreamsAndFilenames.entrySet()) {
|
||||
logger.info("Reading Bravo wind data from "+inputStreamAndFileName.getValue());
|
||||
Util.addAll(readWind(inputStreamAndFileName.getValue(), inputStreamAndFileName.getKey()), windList);
|
||||
}
|
||||
result = windList;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static enum Fields {
|
||||
Lat, Lon, TWS, TWD;
|
||||
}
|
||||
|
||||
private Iterable<Wind> readWind(String filename, InputStream inputStream) throws InterruptedException, IOException, FormatNotSupportedException {
|
||||
final List<Wind> result = new LinkedList<>();
|
||||
Map<String, Integer> columnsMap = new HashMap<>();
|
||||
for (final Fields field : Fields.values()) {
|
||||
columnsMap.put(field.name(), field.ordinal());
|
||||
}
|
||||
final BaseBravoDataImporterImpl importer = new BaseBravoDataImporterImpl(columnsMap, BRAVO_WIND_IMPORT);
|
||||
final Callback callback = new Callback() {
|
||||
@Override
|
||||
public void addFixes(Iterable<DoubleVectorFix> fixes, TrackFileImportDeviceIdentifier device) {
|
||||
for (final DoubleVectorFix fix : fixes) {
|
||||
// latitude / longitude are represented in funny NMEA-like way; the value divided by 100 as
|
||||
// a floored integer represents the full degrees; the value modulo 100 represents the decimal
|
||||
// minutes. Example: the pair (4124.645890, 213.738670) stands for N41�24.645890 E002�13.738670
|
||||
final Wind wind = new WindImpl(new DegreePosition(FunnyDegreeConverter.funnyLatLng(fix.get(Fields.Lat.ordinal())),
|
||||
FunnyDegreeConverter.funnyLatLng(fix.get(Fields.Lon.ordinal()))),
|
||||
fix.getTimePoint(), new KnotSpeedWithBearingImpl(fix.get(Fields.TWS.ordinal()),
|
||||
new DegreeBearingImpl(fix.get(Fields.TWD.ordinal())).reverse()));
|
||||
result.add(wind);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (filename.toLowerCase().endsWith(".zip")) {
|
||||
logger.info("Bravo file "+filename+" is a ZIP file");
|
||||
try (final ZipInputStream zipInputStream = new ZipInputStream(inputStream)) {
|
||||
ZipEntry entry;
|
||||
while ((entry=zipInputStream.getNextEntry()) != null) {
|
||||
if (entry.getName().toLowerCase().endsWith(".txt")) {
|
||||
logger.info("Reading Bravo wind data from "+filename+"'s ZIP entry "+entry.getName());
|
||||
importer.importFixes(zipInputStream, callback, entry.getName(), BRAVO_WIND_IMPORT, /* downsample */ false);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final String actualFileName;
|
||||
if (filename.toLowerCase().endsWith(GZIP_SUFFIX)) {
|
||||
inputStream = new GZIPInputStream(inputStream);
|
||||
actualFileName = filename.substring(0, filename.length()-GZIP_SUFFIX.length());
|
||||
} else {
|
||||
actualFileName = filename;
|
||||
}
|
||||
importer.importFixes(inputStream, callback, actualFileName, BRAVO_WIND_IMPORT, /* downsample */ false);
|
||||
}
|
||||
return result;
|
||||
public BravoWindImportServlet() {
|
||||
super(new BravoWindImporter());
|
||||
}
|
||||
}
|
||||
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
package com.sap.sailing.server.gateway.windimport.bravo;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.WindImpl;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceWithAdditionalID;
|
||||
import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
|
||||
import com.sap.sailing.domain.trackimport.BaseDoubleVectorFixImporter.Callback;
|
||||
import com.sap.sailing.domain.trackimport.FormatNotSupportedException;
|
||||
import com.sap.sailing.server.gateway.windimport.AbstractWindImporter;
|
||||
import com.sap.sailing.server.trackfiles.impl.BaseBravoDataImporterImpl;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
public class BravoWindImporter extends AbstractWindImporter {
|
||||
private static final String BRAVO_WIND_IMPORT = "Bravo Wind Import";
|
||||
private static final String GZIP_SUFFIX = ".gz";
|
||||
private static final Logger logger = Logger.getLogger(BravoWindImporter.class.getName());
|
||||
|
||||
@Override
|
||||
protected WindSource getWindSource(UploadRequest uploadRequest) {
|
||||
final WindSource windSource;
|
||||
final String sourceName;
|
||||
logger.info("Importing Bravo wind data from "+uploadRequest.files);
|
||||
if (uploadRequest.files != null && !uploadRequest.files.isEmpty()) {
|
||||
sourceName = uploadRequest.files.stream().map(f->f.getName()).collect(Collectors.joining(", "));
|
||||
} else {
|
||||
sourceName = BRAVO_WIND_IMPORT;
|
||||
}
|
||||
windSource = new WindSourceWithAdditionalID(WindSourceType.EXPEDITION, sourceName + "@" + MillisecondsTimePoint.now());
|
||||
return windSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterable<Wind> importWind(Map<InputStream, String> inputStreamsAndFilenames) throws IOException, InterruptedException, FormatNotSupportedException {
|
||||
final Iterable<Wind> result;
|
||||
if (inputStreamsAndFilenames != null && inputStreamsAndFilenames.size() == 1) {
|
||||
logger.info("Reading Bravo wind data from "+inputStreamsAndFilenames.values().iterator().next());
|
||||
result = readWind(inputStreamsAndFilenames.values().iterator().next(), inputStreamsAndFilenames.keySet().iterator().next());
|
||||
} else {
|
||||
final List<Wind> windList = new LinkedList<>();
|
||||
for (final Entry<InputStream, String> inputStreamAndFileName : inputStreamsAndFilenames.entrySet()) {
|
||||
logger.info("Reading Bravo wind data from "+inputStreamAndFileName.getValue());
|
||||
Util.addAll(readWind(inputStreamAndFileName.getValue(), inputStreamAndFileName.getKey()), windList);
|
||||
}
|
||||
result = windList;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static enum Fields {
|
||||
Lat, Lon, TWS, TWD;
|
||||
}
|
||||
|
||||
private Iterable<Wind> readWind(String filename, InputStream inputStream) throws InterruptedException, IOException, FormatNotSupportedException {
|
||||
final List<Wind> result = new LinkedList<>();
|
||||
Map<String, Integer> columnsMap = new HashMap<>();
|
||||
for (final Fields field : Fields.values()) {
|
||||
columnsMap.put(field.name(), field.ordinal());
|
||||
}
|
||||
final BaseBravoDataImporterImpl importer = new BaseBravoDataImporterImpl(columnsMap, BRAVO_WIND_IMPORT);
|
||||
final Callback callback = new Callback() {
|
||||
@Override
|
||||
public void addFixes(Iterable<DoubleVectorFix> fixes, TrackFileImportDeviceIdentifier device) {
|
||||
for (final DoubleVectorFix fix : fixes) {
|
||||
// latitude / longitude are represented in funny NMEA-like way; the value divided by 100 as
|
||||
// a floored integer represents the full degrees; the value modulo 100 represents the decimal
|
||||
// minutes. Example: the pair (4124.645890, 213.738670) stands for N41�24.645890 E002�13.738670
|
||||
final Wind wind = new WindImpl(new DegreePosition(FunnyDegreeConverter.funnyLatLng(fix.get(Fields.Lat.ordinal())),
|
||||
FunnyDegreeConverter.funnyLatLng(fix.get(Fields.Lon.ordinal()))),
|
||||
fix.getTimePoint(), new KnotSpeedWithBearingImpl(fix.get(Fields.TWS.ordinal()),
|
||||
new DegreeBearingImpl(fix.get(Fields.TWD.ordinal())).reverse()));
|
||||
result.add(wind);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (filename.toLowerCase().endsWith(".zip")) {
|
||||
logger.info("Bravo file "+filename+" is a ZIP file");
|
||||
try (final ZipInputStream zipInputStream = new ZipInputStream(inputStream)) {
|
||||
ZipEntry entry;
|
||||
while ((entry=zipInputStream.getNextEntry()) != null) {
|
||||
if (entry.getName().toLowerCase().endsWith(".txt")) {
|
||||
logger.info("Reading Bravo wind data from "+filename+"'s ZIP entry "+entry.getName());
|
||||
importer.importFixes(zipInputStream, callback, entry.getName(), BRAVO_WIND_IMPORT, /* downsample */ false);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final String actualFileName;
|
||||
if (filename.toLowerCase().endsWith(GZIP_SUFFIX)) {
|
||||
inputStream = new GZIPInputStream(inputStream);
|
||||
actualFileName = filename.substring(0, filename.length()-GZIP_SUFFIX.length());
|
||||
} else {
|
||||
actualFileName = filename;
|
||||
}
|
||||
importer.importFixes(inputStream, callback, actualFileName, BRAVO_WIND_IMPORT, /* downsample */ false);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+3
-31
@@ -1,40 +1,12 @@
|
||||
package com.sap.sailing.server.gateway.windimport.expedition;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceImpl;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceWithAdditionalID;
|
||||
import com.sap.sailing.server.gateway.windimport.AbstractWindImportServlet;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public class WindImportServlet extends AbstractWindImportServlet {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected WindSource getWindSource(UploadRequest uploadRequest) {
|
||||
WindSource windSource;
|
||||
if (uploadRequest.boatId == null) {
|
||||
windSource = new WindSourceImpl(WindSourceType.EXPEDITION);
|
||||
} else {
|
||||
windSource = new WindSourceWithAdditionalID(WindSourceType.EXPEDITION, uploadRequest.boatId);
|
||||
}
|
||||
return windSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterable<Wind> importWind(Map<InputStream, String> streamsWithFilenames) throws IOException {
|
||||
final List<Wind> result = new ArrayList<>();
|
||||
for (final InputStream inputStream : streamsWithFilenames.keySet()) {
|
||||
Util.addAll(WindLogParser.importWind(inputStream), result);
|
||||
}
|
||||
return result;
|
||||
|
||||
public WindImportServlet() {
|
||||
super(new WindImporter());
|
||||
}
|
||||
}
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package com.sap.sailing.server.gateway.windimport.expedition;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceImpl;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceWithAdditionalID;
|
||||
import com.sap.sailing.domain.trackimport.FormatNotSupportedException;
|
||||
import com.sap.sailing.server.gateway.windimport.AbstractWindImporter;
|
||||
import com.sap.sailing.server.trackfiles.impl.CompressedStreamsUtil;
|
||||
import com.sap.sailing.server.trackfiles.impl.ExpeditionImportFileHandler;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public class WindImporter extends AbstractWindImporter {
|
||||
|
||||
@Override
|
||||
protected WindSource getWindSource(UploadRequest uploadRequest) {
|
||||
WindSource windSource;
|
||||
if (uploadRequest.boatId == null) {
|
||||
windSource = new WindSourceImpl(WindSourceType.EXPEDITION);
|
||||
} else {
|
||||
windSource = new WindSourceWithAdditionalID(WindSourceType.EXPEDITION, uploadRequest.boatId);
|
||||
}
|
||||
return windSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterable<Wind> importWind(Map<InputStream, String> streamsWithFilenames) throws IOException, FormatNotSupportedException {
|
||||
final List<Wind> result = new ArrayList<>();
|
||||
for (final Map.Entry<InputStream, String> entry : streamsWithFilenames.entrySet()) {
|
||||
CompressedStreamsUtil.handlePotentiallyCompressedFiles(entry.getValue(), entry.getKey(), new ExpeditionImportFileHandler() {
|
||||
@Override
|
||||
protected void handleExpeditionFile(String fileName, InputStream inputStream) throws IOException {
|
||||
Util.addAll(WindLogParser.importWind(inputStream), result);
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+3
-30
@@ -1,38 +1,11 @@
|
||||
package com.sap.sailing.server.gateway.windimport.grib;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceImpl;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceWithAdditionalID;
|
||||
import com.sap.sailing.grib.GribWindField;
|
||||
import com.sap.sailing.grib.GribWindFieldFactory;
|
||||
import com.sap.sailing.server.gateway.windimport.AbstractWindImportServlet;
|
||||
|
||||
public class GribWindImportServlet extends AbstractWindImportServlet {
|
||||
private static final long serialVersionUID = -4547876638456305135L;
|
||||
private static final Logger logger = Logger.getLogger(GribWindImportServlet.class.getName());
|
||||
|
||||
@Override
|
||||
protected WindSource getWindSource(UploadRequest uploadRequest) {
|
||||
WindSource windSource;
|
||||
if (uploadRequest.boatId == null) {
|
||||
windSource = new WindSourceImpl(WindSourceType.WEB);
|
||||
} else {
|
||||
windSource = new WindSourceWithAdditionalID(WindSourceType.WEB, uploadRequest.boatId);
|
||||
}
|
||||
return windSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterable<Wind> importWind(Map<InputStream, String> inputStreamsAndFilenames) throws IOException {
|
||||
final GribWindField windField = GribWindFieldFactory.INSTANCE.createGribWindFieldFromStreams(logger, Level.INFO, inputStreamsAndFilenames);
|
||||
return windField.getAllWindFixes();
|
||||
|
||||
public GribWindImportServlet() {
|
||||
super(new GribWindImporter());
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user