mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-25 06:58:39 +00:00
Merge remote-tracking branch 'origin/master' into competitor_filtering
Conflicts: java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/CompetitorSelectionModel.java java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/CompetitorSelectionProvider.java java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardPanel.java java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java
This commit is contained in:
@@ -35,3 +35,4 @@ Like businesses, sailors need the latest information to make strategic decisions
|
|||||||
* [Maven Repository Browser](http://maven.sapsailing.com/maven/)
|
* [Maven Repository Browser](http://maven.sapsailing.com/maven/)
|
||||||
* [Main Sailing Website](http://www.sapsailing.com)
|
* [Main Sailing Website](http://www.sapsailing.com)
|
||||||
* [Visitor Statistics](http://analysis.sapsailing.com/)
|
* [Visitor Statistics](http://analysis.sapsailing.com/)
|
||||||
|
* [Traffic and CPU for app01](http://mrtg.sapsailing.com/)
|
||||||
Executable → Regular
@@ -11,4 +11,5 @@ Export-Package: com.sap.sailing.domain.common,
|
|||||||
com.sap.sailing.domain.common.impl,
|
com.sap.sailing.domain.common.impl,
|
||||||
com.sap.sailing.domain.common.quadtree,
|
com.sap.sailing.domain.common.quadtree,
|
||||||
com.sap.sailing.domain.common.quadtree.impl;x-friends:="com.sap.sailing.domain.test",
|
com.sap.sailing.domain.common.quadtree.impl;x-friends:="com.sap.sailing.domain.test",
|
||||||
com.sap.sailing.domain.common.racelog
|
com.sap.sailing.domain.common.racelog,
|
||||||
|
com.sap.sailing.domain.common.dto
|
||||||
|
|||||||
+5
-4
@@ -1,5 +1,6 @@
|
|||||||
package com.sap.sailing.gwt.ui.shared;
|
package com.sap.sailing.domain.common.dto;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@@ -8,13 +9,13 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import com.google.gwt.user.client.rpc.IsSerializable;
|
|
||||||
import com.sap.sailing.domain.base.RaceColumn;
|
|
||||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||||
|
|
||||||
public abstract class AbstractLeaderboardDTO implements IsSerializable {
|
public abstract class AbstractLeaderboardDTO implements Serializable {
|
||||||
|
private static final long serialVersionUID = -205106531931903527L;
|
||||||
|
|
||||||
public String name;
|
public String name;
|
||||||
|
|
||||||
private List<RaceColumnDTO> races;
|
private List<RaceColumnDTO> races;
|
||||||
+4
-3
@@ -1,8 +1,9 @@
|
|||||||
package com.sap.sailing.gwt.ui.shared;
|
package com.sap.sailing.domain.common.dto;
|
||||||
|
|
||||||
import com.google.gwt.user.client.rpc.IsSerializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
public class BoatClassDTO extends NamedDTO implements IsSerializable {
|
public class BoatClassDTO extends NamedDTO implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1981789833769906676L;
|
||||||
private double hullLengthInMeters;
|
private double hullLengthInMeters;
|
||||||
|
|
||||||
BoatClassDTO() {}
|
BoatClassDTO() {}
|
||||||
+4
-3
@@ -1,8 +1,9 @@
|
|||||||
package com.sap.sailing.gwt.ui.shared;
|
package com.sap.sailing.domain.common.dto;
|
||||||
|
|
||||||
import com.google.gwt.user.client.rpc.IsSerializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
public class CompetitorDTO extends NamedDTO implements IsSerializable {
|
public class CompetitorDTO extends NamedDTO implements Serializable {
|
||||||
|
private static final long serialVersionUID = -4997852354821083154L;
|
||||||
public String twoLetterIsoCountryCode;
|
public String twoLetterIsoCountryCode;
|
||||||
public String threeLetterIocCountryCode;
|
public String threeLetterIocCountryCode;
|
||||||
public String countryName;
|
public String countryName;
|
||||||
+3
-3
@@ -1,9 +1,9 @@
|
|||||||
package com.sap.sailing.gwt.ui.shared;
|
package com.sap.sailing.domain.common.dto;
|
||||||
|
|
||||||
import com.google.gwt.user.client.rpc.IsSerializable;
|
|
||||||
import com.sap.sailing.domain.common.Color;
|
import com.sap.sailing.domain.common.Color;
|
||||||
|
|
||||||
public class FleetDTO extends NamedDTO implements IsSerializable {
|
public class FleetDTO extends NamedDTO {
|
||||||
|
private static final long serialVersionUID = 1336494392278190103L;
|
||||||
private Color color;
|
private Color color;
|
||||||
private int orderNo;
|
private int orderNo;
|
||||||
|
|
||||||
+5
-4
@@ -1,5 +1,6 @@
|
|||||||
package com.sap.sailing.gwt.ui.shared;
|
package com.sap.sailing.domain.common.dto;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -7,8 +8,6 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import com.google.gwt.user.client.rpc.IsSerializable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Captures the serializable properties of a leaderboard which in particular has the competitors, any optional display
|
* Captures the serializable properties of a leaderboard which in particular has the competitors, any optional display
|
||||||
* name mappings for the competitors, races and their net / total points as well as possible reasons for maximum points
|
* name mappings for the competitors, races and their net / total points as well as possible reasons for maximum points
|
||||||
@@ -17,7 +16,9 @@ import com.google.gwt.user.client.rpc.IsSerializable;
|
|||||||
* @author Axel Uhl (d043530)
|
* @author Axel Uhl (d043530)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class LeaderboardDTO extends AbstractLeaderboardDTO implements IsSerializable {
|
public class LeaderboardDTO extends AbstractLeaderboardDTO implements Serializable {
|
||||||
|
private static final long serialVersionUID = -520930809792750648L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The competitor list, ordered ascending by total rank
|
* The competitor list, ordered ascending by total rank
|
||||||
*/
|
*/
|
||||||
+7
-5
@@ -1,8 +1,8 @@
|
|||||||
package com.sap.sailing.gwt.ui.shared;
|
package com.sap.sailing.domain.common.dto;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.google.gwt.user.client.rpc.IsSerializable;
|
|
||||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||||
import com.sap.sailing.domain.common.RaceIdentifier;
|
import com.sap.sailing.domain.common.RaceIdentifier;
|
||||||
import com.sap.sailing.domain.common.Tack;
|
import com.sap.sailing.domain.common.Tack;
|
||||||
@@ -15,7 +15,9 @@ import com.sap.sailing.domain.common.Tack;
|
|||||||
* @author Axel Uhl (D043530)
|
* @author Axel Uhl (D043530)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class LeaderboardEntryDTO implements IsSerializable {
|
public class LeaderboardEntryDTO implements Serializable {
|
||||||
|
private static final long serialVersionUID = -4678693781217869837L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identifies the race in which the competitor achieved this score. This makes it possible to find out in which
|
* Identifies the race in which the competitor achieved this score. This makes it possible to find out in which
|
||||||
* fleet the competitor started in this column.
|
* fleet the competitor started in this column.
|
||||||
@@ -56,8 +58,8 @@ public class LeaderboardEntryDTO implements IsSerializable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* If <code>null</code>, no leg details are known yet, the race is not being tracked or the details
|
* If <code>null</code>, no leg details are known yet, the race is not being tracked or the details
|
||||||
* haven't been requested from the server yet. Otherwise, the list holds one entry per {@link Leg} of the
|
* haven't been requested from the server yet. Otherwise, the list holds one entry per <code>Leg</code> of the
|
||||||
* {@link Course} being sailed in the race for which this object holds the scoring details.
|
* <code>Course</code> being sailed in the race for which this object holds the scoring details.
|
||||||
*/
|
*/
|
||||||
public List<LegEntryDTO> legDetails;
|
public List<LegEntryDTO> legDetails;
|
||||||
|
|
||||||
+4
-4
@@ -1,17 +1,17 @@
|
|||||||
package com.sap.sailing.gwt.ui.shared;
|
package com.sap.sailing.domain.common.dto;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.google.gwt.user.client.rpc.IsSerializable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds data about one competitor and all races represented by the owning {@link LeaderboardDTO leaderboard}.
|
* Holds data about one competitor and all races represented by the owning {@link LeaderboardDTO leaderboard}.
|
||||||
*
|
*
|
||||||
* @author Axel Uhl (D043530)
|
* @author Axel Uhl (D043530)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class LeaderboardRowDTO implements IsSerializable {
|
public class LeaderboardRowDTO implements Serializable {
|
||||||
|
private static final long serialVersionUID = -5421934148931661900L;
|
||||||
public CompetitorDTO competitor;
|
public CompetitorDTO competitor;
|
||||||
public Map<String, LeaderboardEntryDTO> fieldsByRaceColumnName;
|
public Map<String, LeaderboardEntryDTO> fieldsByRaceColumnName;
|
||||||
public Double carriedPoints;
|
public Double carriedPoints;
|
||||||
+4
-3
@@ -1,8 +1,8 @@
|
|||||||
package com.sap.sailing.gwt.ui.shared;
|
package com.sap.sailing.domain.common.dto;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.google.gwt.user.client.rpc.IsSerializable;
|
|
||||||
import com.sap.sailing.domain.common.ManeuverType;
|
import com.sap.sailing.domain.common.ManeuverType;
|
||||||
import com.sap.sailing.domain.common.NauticalSide;
|
import com.sap.sailing.domain.common.NauticalSide;
|
||||||
|
|
||||||
@@ -14,7 +14,8 @@ import com.sap.sailing.domain.common.NauticalSide;
|
|||||||
* @author Axel Uhl (D043530)
|
* @author Axel Uhl (D043530)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class LegEntryDTO implements IsSerializable {
|
public class LegEntryDTO implements Serializable {
|
||||||
|
private static final long serialVersionUID = -1236734337344886025L;
|
||||||
public Double distanceTraveledInMeters;
|
public Double distanceTraveledInMeters;
|
||||||
public Double averageSpeedOverGroundInKnots;
|
public Double averageSpeedOverGroundInKnots;
|
||||||
public int rank;
|
public int rank;
|
||||||
+4
-3
@@ -1,8 +1,9 @@
|
|||||||
package com.sap.sailing.gwt.ui.shared;
|
package com.sap.sailing.domain.common.dto;
|
||||||
|
|
||||||
import com.google.gwt.user.client.rpc.IsSerializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
public class NamedDTO implements IsSerializable {
|
public class NamedDTO implements Serializable {
|
||||||
|
private static final long serialVersionUID = -6620231501480297257L;
|
||||||
public String name;
|
public String name;
|
||||||
|
|
||||||
public NamedDTO() {}
|
public NamedDTO() {}
|
||||||
+3
-5
@@ -1,9 +1,7 @@
|
|||||||
package com.sap.sailing.gwt.ui.shared;
|
package com.sap.sailing.domain.common.dto;
|
||||||
|
|
||||||
import com.google.gwt.user.client.rpc.IsSerializable;
|
|
||||||
|
|
||||||
public class PlacemarkDTO extends NamedDTO implements IsSerializable {
|
|
||||||
|
|
||||||
|
public class PlacemarkDTO extends NamedDTO {
|
||||||
|
private static final long serialVersionUID = -6734956459060435983L;
|
||||||
private String countryCode;
|
private String countryCode;
|
||||||
private PositionDTO position;
|
private PositionDTO position;
|
||||||
private long population;
|
private long population;
|
||||||
+3
-5
@@ -1,14 +1,12 @@
|
|||||||
package com.sap.sailing.gwt.ui.shared;
|
package com.sap.sailing.domain.common.dto;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.google.gwt.user.client.rpc.IsSerializable;
|
public class PlacemarkOrderDTO extends NamedDTO {
|
||||||
|
private static final long serialVersionUID = -4981887843843495494L;
|
||||||
public class PlacemarkOrderDTO extends NamedDTO implements IsSerializable {
|
|
||||||
|
|
||||||
private List<PlacemarkDTO> placemarks;
|
private List<PlacemarkDTO> placemarks;
|
||||||
|
|
||||||
public PlacemarkOrderDTO() {
|
public PlacemarkOrderDTO() {
|
||||||
+4
-9
@@ -1,9 +1,9 @@
|
|||||||
package com.sap.sailing.gwt.ui.shared;
|
package com.sap.sailing.domain.common.dto;
|
||||||
|
|
||||||
import com.google.gwt.i18n.client.NumberFormat;
|
import java.io.Serializable;
|
||||||
import com.google.gwt.user.client.rpc.IsSerializable;
|
|
||||||
|
|
||||||
public class PositionDTO implements IsSerializable {
|
public class PositionDTO implements Serializable {
|
||||||
|
private static final long serialVersionUID = -8799012230990258044L;
|
||||||
public double latDeg;
|
public double latDeg;
|
||||||
public double lngDeg;
|
public double lngDeg;
|
||||||
|
|
||||||
@@ -19,11 +19,6 @@ public class PositionDTO implements IsSerializable {
|
|||||||
return "("+latDeg+", "+lngDeg+")";
|
return "("+latDeg+", "+lngDeg+")";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toFormattedString() {
|
|
||||||
NumberFormat fmt = NumberFormat.getFormat("#.###");
|
|
||||||
return fmt.format(latDeg)+", "+fmt.format(lngDeg);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
+4
-3
@@ -1,5 +1,6 @@
|
|||||||
package com.sap.sailing.gwt.ui.shared;
|
package com.sap.sailing.domain.common.dto;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -8,12 +9,12 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import com.google.gwt.user.client.rpc.IsSerializable;
|
|
||||||
import com.sap.sailing.domain.common.RaceIdentifier;
|
import com.sap.sailing.domain.common.RaceIdentifier;
|
||||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||||
import com.sap.sailing.domain.common.TimingConstants;
|
import com.sap.sailing.domain.common.TimingConstants;
|
||||||
|
|
||||||
public class RaceColumnDTO extends NamedDTO implements IsSerializable {
|
public class RaceColumnDTO extends NamedDTO implements Serializable {
|
||||||
|
private static final long serialVersionUID = -3228244237400937852L;
|
||||||
private boolean medalRace;
|
private boolean medalRace;
|
||||||
private List<FleetDTO> fleets;
|
private List<FleetDTO> fleets;
|
||||||
private Map<FleetDTO, RegattaAndRaceIdentifier> trackedRaceIdentifiersPerFleet;
|
private Map<FleetDTO, RegattaAndRaceIdentifier> trackedRaceIdentifiersPerFleet;
|
||||||
+2
-1
@@ -1,6 +1,7 @@
|
|||||||
package com.sap.sailing.gwt.ui.shared;
|
package com.sap.sailing.domain.common.dto;
|
||||||
|
|
||||||
public class RaceColumnInSeriesDTO extends RaceColumnDTO {
|
public class RaceColumnInSeriesDTO extends RaceColumnDTO {
|
||||||
|
private static final long serialVersionUID = 3308901125173317674L;
|
||||||
private String seriesName;
|
private String seriesName;
|
||||||
private String regattaName;
|
private String regattaName;
|
||||||
|
|
||||||
+4
-3
@@ -1,12 +1,13 @@
|
|||||||
package com.sap.sailing.gwt.ui.shared;
|
package com.sap.sailing.domain.common.dto;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import com.google.gwt.user.client.rpc.IsSerializable;
|
|
||||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||||
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
||||||
|
|
||||||
public class RaceDTO extends NamedDTO implements IsSerializable {
|
public class RaceDTO extends NamedDTO {
|
||||||
|
private static final long serialVersionUID = 2613189982608149975L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells if this race is currently being tracked, meaning that a {@link RaceTracker} is
|
* Tells if this race is currently being tracked, meaning that a {@link RaceTracker} is
|
||||||
* listening for incoming GPS fixes, mark passings etc., to update a {@link TrackedRace} object
|
* listening for incoming GPS fixes, mark passings etc., to update a {@link TrackedRace} object
|
||||||
+5
-3
@@ -1,9 +1,11 @@
|
|||||||
package com.sap.sailing.gwt.ui.shared;
|
package com.sap.sailing.domain.common.dto;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
import com.google.gwt.user.client.rpc.IsSerializable;
|
|
||||||
import com.sap.sailing.domain.common.TrackedRaceStatusEnum;
|
import com.sap.sailing.domain.common.TrackedRaceStatusEnum;
|
||||||
|
|
||||||
public class RaceStatusDTO implements IsSerializable {
|
public class RaceStatusDTO implements Serializable {
|
||||||
|
private static final long serialVersionUID = -5665104615048232751L;
|
||||||
public TrackedRaceStatusEnum status;
|
public TrackedRaceStatusEnum status;
|
||||||
public double loadingProgress;
|
public double loadingProgress;
|
||||||
|
|
||||||
+4
-3
@@ -1,10 +1,11 @@
|
|||||||
package com.sap.sailing.gwt.ui.shared;
|
package com.sap.sailing.domain.common.dto;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import com.google.gwt.user.client.rpc.IsSerializable;
|
public class TrackedRaceDTO implements Serializable {
|
||||||
|
private static final long serialVersionUID = -9040930745014670924L;
|
||||||
|
|
||||||
public class TrackedRaceDTO implements IsSerializable {
|
|
||||||
/**
|
/**
|
||||||
* Default constructor for GWT-Serialization
|
* Default constructor for GWT-Serialization
|
||||||
*/
|
*/
|
||||||
+6
@@ -407,6 +407,12 @@ public class StoreAndForward implements Runnable {
|
|||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.log(Level.SEVERE, "Exception in StoreAndForward", e);
|
logger.log(Level.SEVERE, "Exception in StoreAndForward", e);
|
||||||
|
try {
|
||||||
|
Thread.sleep(100); // if the exception persists, wait a little, hoping something may recover
|
||||||
|
} catch (InterruptedException e1) {
|
||||||
|
logger.log(Level.INFO, "StoreAndForward.run interrupted; setting stopped=true", e1);
|
||||||
|
stopped = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.info("StoreAndForward is closing receiving server socket");
|
logger.info("StoreAndForward is closing receiving server socket");
|
||||||
|
|||||||
+19
-1
@@ -5,11 +5,13 @@ import static org.junit.Assert.assertTrue;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.net.BindException;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
@@ -55,7 +57,23 @@ public class ActivelyConnectingStoreAndForwardTest {
|
|||||||
sailMasterDummyListenerThread = new Thread("ActivelyConnectingStoreAndForwardTest-Listener") {
|
sailMasterDummyListenerThread = new Thread("ActivelyConnectingStoreAndForwardTest-Listener") {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
ServerSocket ss = new ServerSocket(RECEIVE_PORT);
|
ServerSocket ss = null;
|
||||||
|
for (int numberOfTries=0; numberOfTries<3 && ss == null; numberOfTries++) {
|
||||||
|
try {
|
||||||
|
ss = new ServerSocket(RECEIVE_PORT);
|
||||||
|
} catch (BindException be) {
|
||||||
|
logger.log(Level.INFO, "Couldn't bind server socket in StoreAndForward"+
|
||||||
|
(numberOfTries<2?". Trying again...":""), be);
|
||||||
|
if (numberOfTries == 2) {
|
||||||
|
throw be;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
synchronized (ActivelyConnectingStoreAndForwardTest.this) {
|
synchronized (ActivelyConnectingStoreAndForwardTest.this) {
|
||||||
sendingSocket = ss.accept();
|
sendingSocket = ss.accept();
|
||||||
logger.info("ActivelyConnectingStoreAndForwardTest-Listener accepted socket connect request on port "+RECEIVE_PORT);
|
logger.info("ActivelyConnectingStoreAndForwardTest-Listener accepted socket connect request on port "+RECEIVE_PORT);
|
||||||
|
|||||||
+19
-3
@@ -8,6 +8,7 @@ import static org.junit.Assert.assertTrue;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.net.BindException;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
@@ -17,6 +18,7 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.NavigableSet;
|
import java.util.NavigableSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
@@ -87,8 +89,20 @@ public class EndToEndListeningStoreAndFowardTest {
|
|||||||
swissTimingAdapterPersistence = SwissTimingAdapterPersistence.INSTANCE;
|
swissTimingAdapterPersistence = SwissTimingAdapterPersistence.INSTANCE;
|
||||||
swissTimingAdapterPersistence.dropAllMessageData();
|
swissTimingAdapterPersistence.dropAllMessageData();
|
||||||
swissTimingAdapterPersistence.dropAllRaceMasterData();
|
swissTimingAdapterPersistence.dropAllRaceMasterData();
|
||||||
storeAndForward = new StoreAndForward(RECEIVE_PORT, CLIENT_PORT, SwissTimingFactory.INSTANCE,
|
storeAndForward = null;
|
||||||
swissTimingAdapterPersistence, mongoDBService);
|
for (int numberOfTries = 0; numberOfTries < 3 && storeAndForward == null; numberOfTries++) {
|
||||||
|
try {
|
||||||
|
storeAndForward = new StoreAndForward(RECEIVE_PORT, CLIENT_PORT, SwissTimingFactory.INSTANCE,
|
||||||
|
swissTimingAdapterPersistence, mongoDBService);
|
||||||
|
} catch (BindException be) {
|
||||||
|
logger.log(Level.INFO, "Couldn't bind server socket in StoreAndForward"+
|
||||||
|
(numberOfTries<2?". Trying again...":""), be);
|
||||||
|
if (numberOfTries == 2) {
|
||||||
|
throw be;
|
||||||
|
}
|
||||||
|
Thread.sleep(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
sendingSocket = new Socket("localhost", RECEIVE_PORT);
|
sendingSocket = new Socket("localhost", RECEIVE_PORT);
|
||||||
sendingStream = sendingSocket.getOutputStream();
|
sendingStream = sendingSocket.getOutputStream();
|
||||||
swissTimingFactory = SwissTimingFactory.INSTANCE;
|
swissTimingFactory = SwissTimingFactory.INSTANCE;
|
||||||
@@ -114,7 +128,9 @@ public class EndToEndListeningStoreAndFowardTest {
|
|||||||
racingEventService.stopTracking(raceHandle.getRegatta());
|
racingEventService.stopTracking(raceHandle.getRegatta());
|
||||||
}
|
}
|
||||||
logger.info("Calling StoreAndForward.stop() in tearDown");
|
logger.info("Calling StoreAndForward.stop() in tearDown");
|
||||||
storeAndForward.stop();
|
if (storeAndForward != null) {
|
||||||
|
storeAndForward.stop();
|
||||||
|
}
|
||||||
logger.exiting(getClass().getName(), "tearDown");
|
logger.exiting(getClass().getName(), "tearDown");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -159,7 +159,7 @@ public class DomainFactoryImpl implements DomainFactory {
|
|||||||
com.sap.sailing.domain.base.Course domainCourse = new CourseImpl("Course", waypoints);
|
com.sap.sailing.domain.base.Course domainCourse = new CourseImpl("Course", waypoints);
|
||||||
BoatClass boatClass = getOrCreateBoatClassFromRaceID(raceID);
|
BoatClass boatClass = getOrCreateBoatClassFromRaceID(raceID);
|
||||||
logger.info("Creating RaceDefinitionImpl for race "+raceID);
|
logger.info("Creating RaceDefinitionImpl for race "+raceID);
|
||||||
RaceDefinition result = new RaceDefinitionImpl(raceID, domainCourse, boatClass, competitors);
|
RaceDefinition result = new RaceDefinitionImpl(regatta.getId().toString()+"/"+raceID, domainCourse, boatClass, competitors);
|
||||||
regatta.addRace(result);
|
regatta.addRace(result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
+519
-519
File diff suppressed because it is too large
Load Diff
+6
@@ -4,6 +4,7 @@ import java.io.Serializable;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.sap.sailing.domain.base.RaceDefinition;
|
||||||
import com.sap.sailing.domain.base.Regatta;
|
import com.sap.sailing.domain.base.Regatta;
|
||||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||||
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||||
@@ -44,4 +45,9 @@ public class DummyTrackedRegattaRegistry implements TrackedRegattaRegistry {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRaceBeingTracked(RaceDefinition r) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ Export-Package: com.sap.sailing.domain.base,
|
|||||||
com.sap.sailing.domain.confidence,
|
com.sap.sailing.domain.confidence,
|
||||||
com.sap.sailing.domain.confidence.impl;x-friends:="com.sap.sailing.domain.test",
|
com.sap.sailing.domain.confidence.impl;x-friends:="com.sap.sailing.domain.test",
|
||||||
com.sap.sailing.domain.leaderboard,
|
com.sap.sailing.domain.leaderboard,
|
||||||
|
com.sap.sailing.domain.leaderboard.caching,
|
||||||
com.sap.sailing.domain.leaderboard.impl,
|
com.sap.sailing.domain.leaderboard.impl,
|
||||||
com.sap.sailing.domain.leaderboard.meta,
|
com.sap.sailing.domain.leaderboard.meta,
|
||||||
com.sap.sailing.domain.polarsheets,
|
com.sap.sailing.domain.polarsheets,
|
||||||
@@ -24,4 +25,5 @@ Bundle-ActivationPolicy: lazy
|
|||||||
Require-Bundle: com.googlecode.java-diff-utils;bundle-version="1.3.0",
|
Require-Bundle: com.googlecode.java-diff-utils;bundle-version="1.3.0",
|
||||||
com.sap.sailing.domain.shared.android;bundle-version="1.0.0",
|
com.sap.sailing.domain.shared.android;bundle-version="1.0.0",
|
||||||
com.sap.sailing.domain.common,
|
com.sap.sailing.domain.common,
|
||||||
org.json.simple;bundle-version="1.1.0"
|
org.json.simple;bundle-version="1.1.0",
|
||||||
|
com.sap.sailing.geocoding
|
||||||
|
|||||||
@@ -3,14 +3,23 @@ package com.sap.sailing.domain.base;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import com.sap.sailing.domain.base.impl.DomainFactoryImpl;
|
import com.sap.sailing.domain.base.impl.DomainFactoryImpl;
|
||||||
import com.sap.sailing.domain.common.MarkType;
|
import com.sap.sailing.domain.common.MarkType;
|
||||||
import com.sap.sailing.domain.common.NauticalSide;
|
import com.sap.sailing.domain.common.NauticalSide;
|
||||||
|
import com.sap.sailing.domain.common.Placemark;
|
||||||
|
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||||
import com.sap.sailing.domain.common.TimePoint;
|
import com.sap.sailing.domain.common.TimePoint;
|
||||||
|
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.FleetDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.PlacemarkDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.RaceDTO;
|
||||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||||
|
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||||
|
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||||
|
|
||||||
public interface DomainFactory extends SharedDomainFactory {
|
public interface DomainFactory extends SharedDomainFactory {
|
||||||
static DomainFactory INSTANCE = new DomainFactoryImpl();
|
static DomainFactory INSTANCE = new DomainFactoryImpl();
|
||||||
@@ -82,4 +91,16 @@ public interface DomainFactory extends SharedDomainFactory {
|
|||||||
|
|
||||||
ScoringScheme createScoringScheme(ScoringSchemeType scoringSchemeType);
|
ScoringScheme createScoringScheme(ScoringSchemeType scoringSchemeType);
|
||||||
|
|
||||||
|
CompetitorDTO convertToCompetitorDTO(Competitor c);
|
||||||
|
|
||||||
|
FleetDTO convertToFleetDTO(Series series, Fleet fleet);
|
||||||
|
|
||||||
|
FleetDTO convertToFleetDTO(RaceColumn raceColumn, Fleet fleet);
|
||||||
|
|
||||||
|
RaceDTO createRaceDTO(TrackedRegattaRegistry trackedRegattaRegistry, boolean b, RegattaAndRaceIdentifier raceIdentifier, TrackedRace trackedRace);
|
||||||
|
|
||||||
|
PlacemarkDTO convertToPlacemarkDTO(Placemark placemark);
|
||||||
|
|
||||||
|
List<CompetitorDTO> getCompetitorDTOList(List<Competitor> competitors);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+166
@@ -6,29 +6,52 @@ import java.io.Serializable;
|
|||||||
import java.lang.ref.Reference;
|
import java.lang.ref.Reference;
|
||||||
import java.lang.ref.ReferenceQueue;
|
import java.lang.ref.ReferenceQueue;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import com.sap.sailing.domain.base.Boat;
|
import com.sap.sailing.domain.base.Boat;
|
||||||
import com.sap.sailing.domain.base.BoatClass;
|
import com.sap.sailing.domain.base.BoatClass;
|
||||||
import com.sap.sailing.domain.base.Competitor;
|
import com.sap.sailing.domain.base.Competitor;
|
||||||
import com.sap.sailing.domain.base.ControlPoint;
|
import com.sap.sailing.domain.base.ControlPoint;
|
||||||
import com.sap.sailing.domain.base.DomainFactory;
|
import com.sap.sailing.domain.base.DomainFactory;
|
||||||
|
import com.sap.sailing.domain.base.Fleet;
|
||||||
import com.sap.sailing.domain.base.Gate;
|
import com.sap.sailing.domain.base.Gate;
|
||||||
import com.sap.sailing.domain.base.Mark;
|
import com.sap.sailing.domain.base.Mark;
|
||||||
import com.sap.sailing.domain.base.Nationality;
|
import com.sap.sailing.domain.base.Nationality;
|
||||||
import com.sap.sailing.domain.base.ObjectInputStreamResolvingAgainstDomainFactory;
|
import com.sap.sailing.domain.base.ObjectInputStreamResolvingAgainstDomainFactory;
|
||||||
|
import com.sap.sailing.domain.base.RaceColumn;
|
||||||
|
import com.sap.sailing.domain.base.RaceColumnInSeries;
|
||||||
|
import com.sap.sailing.domain.base.Series;
|
||||||
import com.sap.sailing.domain.base.Team;
|
import com.sap.sailing.domain.base.Team;
|
||||||
import com.sap.sailing.domain.base.Waypoint;
|
import com.sap.sailing.domain.base.Waypoint;
|
||||||
|
import com.sap.sailing.domain.common.CountryCode;
|
||||||
|
import com.sap.sailing.domain.common.Distance;
|
||||||
import com.sap.sailing.domain.common.MarkType;
|
import com.sap.sailing.domain.common.MarkType;
|
||||||
import com.sap.sailing.domain.common.NauticalSide;
|
import com.sap.sailing.domain.common.NauticalSide;
|
||||||
|
import com.sap.sailing.domain.common.Placemark;
|
||||||
|
import com.sap.sailing.domain.common.Position;
|
||||||
|
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||||
import com.sap.sailing.domain.common.TimePoint;
|
import com.sap.sailing.domain.common.TimePoint;
|
||||||
import com.sap.sailing.domain.common.WithID;
|
import com.sap.sailing.domain.common.WithID;
|
||||||
|
import com.sap.sailing.domain.common.dto.BoatClassDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.FleetDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.PlacemarkDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.PlacemarkOrderDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.PositionDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.RaceDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.TrackedRaceDTO;
|
||||||
|
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||||
import com.sap.sailing.domain.leaderboard.impl.HighPoint;
|
import com.sap.sailing.domain.leaderboard.impl.HighPoint;
|
||||||
import com.sap.sailing.domain.leaderboard.impl.HighPointExtremeSailingSeriesOverall;
|
import com.sap.sailing.domain.leaderboard.impl.HighPointExtremeSailingSeriesOverall;
|
||||||
@@ -36,10 +59,17 @@ import com.sap.sailing.domain.leaderboard.impl.HighPointFirstGets10LastBreaksTie
|
|||||||
import com.sap.sailing.domain.leaderboard.impl.HighPointLastBreaksTie;
|
import com.sap.sailing.domain.leaderboard.impl.HighPointLastBreaksTie;
|
||||||
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
|
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
|
||||||
import com.sap.sailing.domain.leaderboard.impl.LowPointWinnerGetsZero;
|
import com.sap.sailing.domain.leaderboard.impl.LowPointWinnerGetsZero;
|
||||||
|
import com.sap.sailing.domain.tracking.GPSFix;
|
||||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||||
|
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||||
|
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||||
import com.sap.sailing.domain.tracking.impl.MarkPassingImpl;
|
import com.sap.sailing.domain.tracking.impl.MarkPassingImpl;
|
||||||
|
import com.sap.sailing.domain.tracking.impl.TrackedRaceImpl;
|
||||||
|
import com.sap.sailing.geocoding.ReverseGeocoder;
|
||||||
|
|
||||||
public class DomainFactoryImpl implements DomainFactory {
|
public class DomainFactoryImpl implements DomainFactory {
|
||||||
|
private static Logger logger = Logger.getLogger(DomainFactoryImpl.class.getName());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure that the <em>same</em> string is used as key that is also used to set the {@link Nationality}
|
* Ensure that the <em>same</em> string is used as key that is also used to set the {@link Nationality}
|
||||||
* object's {@link Nationality#getThreeLetterIOCAcronym() IOC code}.
|
* object's {@link Nationality#getThreeLetterIOCAcronym() IOC code}.
|
||||||
@@ -68,6 +98,8 @@ public class DomainFactoryImpl implements DomainFactory {
|
|||||||
|
|
||||||
private final ReferenceQueue<Waypoint> waypointCacheReferenceQueue;
|
private final ReferenceQueue<Waypoint> waypointCacheReferenceQueue;
|
||||||
|
|
||||||
|
private final WeakHashMap<Competitor, CompetitorDTO> weakCompetitorDTOCache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Weak references to {@link Waypoint} objects of this type are registered with
|
* Weak references to {@link Waypoint} objects of this type are registered with
|
||||||
* {@link DomainFactoryImpl#waypointCacheReferenceQueue} upon construction so that when their referents are no
|
* {@link DomainFactoryImpl#waypointCacheReferenceQueue} upon construction so that when their referents are no
|
||||||
@@ -94,6 +126,7 @@ public class DomainFactoryImpl implements DomainFactory {
|
|||||||
private final Set<String> mayStartWithNoUpwindLeg;
|
private final Set<String> mayStartWithNoUpwindLeg;
|
||||||
|
|
||||||
public DomainFactoryImpl() {
|
public DomainFactoryImpl() {
|
||||||
|
weakCompetitorDTOCache = new WeakHashMap<Competitor, CompetitorDTO>();
|
||||||
waypointCacheReferenceQueue = new ReferenceQueue<Waypoint>();
|
waypointCacheReferenceQueue = new ReferenceQueue<Waypoint>();
|
||||||
nationalityCache = new HashMap<String, Nationality>();
|
nationalityCache = new HashMap<String, Nationality>();
|
||||||
markCache = new HashMap<Serializable, Mark>();
|
markCache = new HashMap<Serializable, Mark>();
|
||||||
@@ -294,4 +327,137 @@ public class DomainFactoryImpl implements DomainFactory {
|
|||||||
}
|
}
|
||||||
throw new RuntimeException("Unknown scoring scheme type "+scoringSchemeType.name());
|
throw new RuntimeException("Unknown scoring scheme type "+scoringSchemeType.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompetitorDTO convertToCompetitorDTO(Competitor c) {
|
||||||
|
CompetitorDTO competitorDTO = weakCompetitorDTOCache.get(c);
|
||||||
|
if (competitorDTO == null) {
|
||||||
|
CountryCode countryCode = c.getTeam().getNationality().getCountryCode();
|
||||||
|
competitorDTO = new CompetitorDTO(c.getName(), countryCode == null ? ""
|
||||||
|
: countryCode.getTwoLetterISOCode(),
|
||||||
|
countryCode == null ? "" : countryCode.getThreeLetterIOCCode(), countryCode == null ? ""
|
||||||
|
: countryCode.getName(), c.getBoat().getSailID(), c.getId().toString(),
|
||||||
|
new BoatClassDTO(c.getBoat().getBoatClass().getName(), c.getBoat().getBoatClass().getHullLength()
|
||||||
|
.getMeters()));
|
||||||
|
weakCompetitorDTOCache.put(c, competitorDTO);
|
||||||
|
}
|
||||||
|
return competitorDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FleetDTO convertToFleetDTO(Series series, Fleet fleet) {
|
||||||
|
return new FleetDTO(fleet.getName(), series.getName(), fleet.getOrdering(), fleet.getColor());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FleetDTO convertToFleetDTO(RaceColumn raceColumn, Fleet fleet) {
|
||||||
|
String seriesNameOfFleet = null;
|
||||||
|
if (raceColumn instanceof RaceColumnInSeries) {
|
||||||
|
seriesNameOfFleet = ((RaceColumnInSeries) raceColumn).getSeries().getName();
|
||||||
|
}
|
||||||
|
return new FleetDTO(fleet.getName(), seriesNameOfFleet, fleet.getOrdering(), fleet.getColor());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RaceDTO createRaceDTO(TrackedRegattaRegistry trackedRegattaRegistry, boolean withGeoLocationData, RegattaAndRaceIdentifier raceIdentifier, TrackedRace trackedRace) {
|
||||||
|
// Optional: Getting the places of the race
|
||||||
|
PlacemarkOrderDTO racePlaces = withGeoLocationData ? getRacePlaces(trackedRace) : null;
|
||||||
|
TrackedRaceDTO trackedRaceDTO = new TrackedRaceDTO();
|
||||||
|
trackedRaceDTO.startOfTracking = trackedRace.getStartOfTracking() == null ? null : trackedRace.getStartOfTracking().asDate();
|
||||||
|
trackedRaceDTO.hasWindData = trackedRace.hasWindData();
|
||||||
|
trackedRaceDTO.hasGPSData = trackedRace.hasGPSData();
|
||||||
|
RaceDTO raceDTO = new RaceDTO(raceIdentifier, trackedRaceDTO, trackedRegattaRegistry.isRaceBeingTracked(trackedRace.getRace()));
|
||||||
|
raceDTO.places = racePlaces;
|
||||||
|
raceDTO.startOfRace = trackedRace.getStartOfRace() == null ? null : trackedRace.getStartOfRace().asDate();
|
||||||
|
raceDTO.endOfRace = trackedRace.getEndOfRace() == null ? null : trackedRace.getEndOfRace().asDate();
|
||||||
|
return raceDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PlacemarkOrderDTO getRacePlaces(TrackedRace trackedRace) {
|
||||||
|
Pair<Placemark, Placemark> startAndFinish = getStartFinishPlacemarksForTrackedRace(trackedRace);
|
||||||
|
PlacemarkOrderDTO racePlaces = new PlacemarkOrderDTO();
|
||||||
|
if (startAndFinish.getA() != null) {
|
||||||
|
racePlaces.getPlacemarks().add(convertToPlacemarkDTO(startAndFinish.getA()));
|
||||||
|
}
|
||||||
|
if (startAndFinish.getB() != null) {
|
||||||
|
racePlaces.getPlacemarks().add(convertToPlacemarkDTO(startAndFinish.getB()));
|
||||||
|
}
|
||||||
|
if (racePlaces.isEmpty()) {
|
||||||
|
racePlaces = null;
|
||||||
|
}
|
||||||
|
return racePlaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Pair<Placemark, Placemark> getStartFinishPlacemarksForTrackedRace(TrackedRace race) {
|
||||||
|
double radiusCalculationFactor = 10.0;
|
||||||
|
Placemark startBest = null;
|
||||||
|
Placemark finishBest = null;
|
||||||
|
|
||||||
|
// Get start postition
|
||||||
|
Iterator<Mark> startMarks = race.getRace().getCourse().getFirstWaypoint().getMarks().iterator();
|
||||||
|
GPSFix startMarkFix = startMarks.hasNext() ? race.getOrCreateTrack(startMarks.next()).getLastRawFix() : null;
|
||||||
|
Position startPosition = startMarkFix != null ? startMarkFix.getPosition() : null;
|
||||||
|
if (startPosition != null) {
|
||||||
|
try {
|
||||||
|
// Get distance to nearest placemark and calculate the search radius
|
||||||
|
Placemark startNearest = ReverseGeocoder.INSTANCE.getPlacemarkNearest(startPosition);
|
||||||
|
if (startNearest != null) {
|
||||||
|
Distance startNearestDistance = startNearest.distanceFrom(startPosition);
|
||||||
|
double startRadius = startNearestDistance.getKilometers() * radiusCalculationFactor;
|
||||||
|
|
||||||
|
// Get the estimated best start place
|
||||||
|
startBest = ReverseGeocoder.INSTANCE.getPlacemarkLast(startPosition, startRadius,
|
||||||
|
new Placemark.ByPopulationDistanceRatio(startPosition));
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.throwing(TrackedRaceImpl.class.getName(), "getPlaceOrder()", e);
|
||||||
|
} catch (org.json.simple.parser.ParseException e) {
|
||||||
|
logger.throwing(TrackedRaceImpl.class.getName(), "getPlaceOrder()", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get finish position
|
||||||
|
Iterator<Mark> finishMarks = race.getRace().getCourse().getFirstWaypoint().getMarks().iterator();
|
||||||
|
GPSFix finishMarkFix = finishMarks.hasNext() ? race.getOrCreateTrack(finishMarks.next()).getLastRawFix() : null;
|
||||||
|
Position finishPosition = finishMarkFix != null ? finishMarkFix.getPosition() : null;
|
||||||
|
if (startPosition != null && finishPosition != null) {
|
||||||
|
if (startPosition.getDistance(finishPosition).getKilometers() <= ReverseGeocoder.POSITION_CACHE_DISTANCE_LIMIT_IN_KM) {
|
||||||
|
finishBest = startBest;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
// Get distance to nearest placemark and calculate the search radius
|
||||||
|
Placemark finishNearest = ReverseGeocoder.INSTANCE.getPlacemarkNearest(finishPosition);
|
||||||
|
Distance finishNearestDistance = finishNearest.distanceFrom(finishPosition);
|
||||||
|
double finishRadius = finishNearestDistance.getKilometers() * radiusCalculationFactor;
|
||||||
|
|
||||||
|
// Get the estimated best finish place
|
||||||
|
finishBest = ReverseGeocoder.INSTANCE.getPlacemarkLast(finishPosition, finishRadius,
|
||||||
|
new Placemark.ByPopulationDistanceRatio(finishPosition));
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.throwing(TrackedRaceImpl.class.getName(), "getPlaceOrder()", e);
|
||||||
|
} catch (org.json.simple.parser.ParseException e) {
|
||||||
|
logger.throwing(TrackedRaceImpl.class.getName(), "getPlaceOrder()", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Pair<Placemark, Placemark> placemarks = new Pair<Placemark, Placemark>(startBest, finishBest);
|
||||||
|
return placemarks;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PlacemarkDTO convertToPlacemarkDTO(Placemark placemark) {
|
||||||
|
Position position = placemark.getPosition();
|
||||||
|
return new PlacemarkDTO(placemark.getName(), placemark.getCountryCode(), new PositionDTO(position.getLatDeg(),
|
||||||
|
position.getLngDeg()), placemark.getPopulation());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CompetitorDTO> getCompetitorDTOList(List<Competitor> competitors) {
|
||||||
|
List<CompetitorDTO> result = new ArrayList<CompetitorDTO>();
|
||||||
|
for (Competitor competitor : competitors) {
|
||||||
|
result.add(convertToCompetitorDTO(competitor));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,13 +60,6 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
|
|||||||
*/
|
*/
|
||||||
private final boolean persistent;
|
private final boolean persistent;
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a regatta with an empty {@link RaceLogStore}.
|
|
||||||
*/
|
|
||||||
public RegattaImpl(String baseName, BoatClass boatClass, TrackedRegattaRegistry trackedRegattaRegistry, ScoringScheme scoringScheme, Serializable id) {
|
|
||||||
this(EmptyRaceLogStore.INSTANCE, baseName, boatClass, trackedRegattaRegistry, scoringScheme, id, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a regatta with an empty {@link RaceLogStore}.
|
* Constructs a regatta with an empty {@link RaceLogStore}.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
package com.sap.sailing.domain.leaderboard;
|
package com.sap.sailing.domain.leaderboard;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
import com.sap.sailing.domain.base.Competitor;
|
import com.sap.sailing.domain.base.Competitor;
|
||||||
import com.sap.sailing.domain.base.CourseArea;
|
import com.sap.sailing.domain.base.CourseArea;
|
||||||
|
import com.sap.sailing.domain.base.DomainFactory;
|
||||||
import com.sap.sailing.domain.base.Fleet;
|
import com.sap.sailing.domain.base.Fleet;
|
||||||
import com.sap.sailing.domain.base.RaceColumn;
|
import com.sap.sailing.domain.base.RaceColumn;
|
||||||
import com.sap.sailing.domain.base.RaceColumnListener;
|
import com.sap.sailing.domain.base.RaceColumnListener;
|
||||||
@@ -16,9 +19,12 @@ import com.sap.sailing.domain.common.Named;
|
|||||||
import com.sap.sailing.domain.common.NoWindException;
|
import com.sap.sailing.domain.common.NoWindException;
|
||||||
import com.sap.sailing.domain.common.Speed;
|
import com.sap.sailing.domain.common.Speed;
|
||||||
import com.sap.sailing.domain.common.TimePoint;
|
import com.sap.sailing.domain.common.TimePoint;
|
||||||
|
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
|
||||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||||
|
import com.sap.sailing.domain.leaderboard.caching.LiveLeaderboardUpdater;
|
||||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||||
|
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A leaderboard is used to display the results of one or more {@link TrackedRace races}. It manages the competitors'
|
* A leaderboard is used to display the results of one or more {@link TrackedRace races}. It manages the competitors'
|
||||||
@@ -61,6 +67,10 @@ public interface Leaderboard extends Named {
|
|||||||
Fleet getFleet();
|
Fleet getFleet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LeaderboardDTO computeDTO(final TimePoint timePoint,
|
||||||
|
final Collection<String> namesOfRaceColumnsForWhichToLoadLegDetails, final boolean waitForLatestAnalyses, TrackedRegattaRegistry trackedRegattaRegistry, DomainFactory baseDomainFactory)
|
||||||
|
throws NoWindException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains the unique set of {@link Competitor} objects from all {@link TrackedRace}s currently linked to this
|
* Obtains the unique set of {@link Competitor} objects from all {@link TrackedRace}s currently linked to this
|
||||||
* leaderboard, with suppressed competitors removed. See also {@link #getAllCompetitors()} which also returns
|
* leaderboard, with suppressed competitors removed. See also {@link #getAllCompetitors()} which also returns
|
||||||
@@ -381,4 +391,43 @@ public interface Leaderboard extends Named {
|
|||||||
* @return the default {@link CourseArea} for all races of this leaderboard.
|
* @return the default {@link CourseArea} for all races of this leaderboard.
|
||||||
*/
|
*/
|
||||||
CourseArea getDefaultCourseArea();
|
CourseArea getDefaultCourseArea();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Must be called when the leaderboard is removed from its server, becoming in accessible. This will give the leaderboard
|
||||||
|
* a chance to release all its resources that won't be collected or freed automatically. In particular, a leaderboard may
|
||||||
|
* hold on to listeners which in turn are registered with {@link TrackedRace}s and therefore won't be released to the garbage
|
||||||
|
* collector unless the tracked race becomes unreferenced. This may take long because the tracked race can generally
|
||||||
|
* be referenced by more than one leaderboard. For example, a test leaderboard may additionally reference a tracked
|
||||||
|
* race already referenced by an "official" leaderboard. When the test leaderboard is removed, its listeners would not
|
||||||
|
* be released and avoid garbage-collecting the test leaderboard. When calling this method, the leaderboard will cleanly
|
||||||
|
* unregister its listeners from the tracked races and therefore become eligible for garbage collection.
|
||||||
|
*/
|
||||||
|
void destroy();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a data transfer object (DTO) that has the leaderboard's data for the race columns with basic information
|
||||||
|
* for all columns, and with detailed information for those columns whose names are provided in
|
||||||
|
* <code>namesOfRaceColumnsForWhichToLoadLegDetails</code>. The leaderboard is evaluated at <code>timePoint</code>,
|
||||||
|
* or, if <code>timePoint</code> is <code>null</code>, for the "live" time point (now - delay).
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* The implementation uses different approaches for caching the results. For "live" requests, a
|
||||||
|
* {@link LiveLeaderboardUpdater} is used to keep refreshing the cached results. Other queries are managed by a
|
||||||
|
* {@link LeaderboardDTOCache} which remembers a number of results before it starts evicting the least frequently
|
||||||
|
* used ones.
|
||||||
|
*
|
||||||
|
* @param timePoint
|
||||||
|
* <code>null</code> for "live" results for the time point "now" - delay; otherwise, the explicit time
|
||||||
|
* point at which to evaluate the leaderboard status
|
||||||
|
* @param namesOfRaceColumnsForWhichToLoadLegDetails
|
||||||
|
* the names of the race columns of which to expand the details in the result
|
||||||
|
* @param trackedRegattaRegistry
|
||||||
|
* used to determine which of the races are still being tracked and which ones are not
|
||||||
|
* @param baseDomainFactory
|
||||||
|
* required as factory and cache for various DTO types
|
||||||
|
*/
|
||||||
|
LeaderboardDTO getLeaderboardDTO(TimePoint timePoint,
|
||||||
|
Collection<String> namesOfRaceColumnsForWhichToLoadLegDetails,
|
||||||
|
TrackedRegattaRegistry trackedRegattaRegistry, DomainFactory baseDomainFactory) throws NoWindException,
|
||||||
|
InterruptedException, ExecutionException;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -15,6 +15,7 @@ import com.sap.sailing.domain.base.Waypoint;
|
|||||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||||
import com.sap.sailing.domain.common.TimePoint;
|
import com.sap.sailing.domain.common.TimePoint;
|
||||||
import com.sap.sailing.domain.common.WindSource;
|
import com.sap.sailing.domain.common.WindSource;
|
||||||
|
import com.sap.sailing.domain.leaderboard.caching.LeaderboardCache;
|
||||||
import com.sap.sailing.domain.racelog.RaceLogEvent;
|
import com.sap.sailing.domain.racelog.RaceLogEvent;
|
||||||
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
|
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
|
||||||
import com.sap.sailing.domain.tracking.GPSFix;
|
import com.sap.sailing.domain.tracking.GPSFix;
|
||||||
|
|||||||
+4
-1
@@ -1,4 +1,7 @@
|
|||||||
package com.sap.sailing.domain.leaderboard;
|
package com.sap.sailing.domain.leaderboard.caching;
|
||||||
|
|
||||||
|
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||||
|
import com.sap.sailing.domain.leaderboard.LeaderboardCacheManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for leaderboard state cache management. When passed to a {@link LeaderboardCacheManager}, leaderboards
|
* Interface for leaderboard state cache management. When passed to a {@link LeaderboardCacheManager}, leaderboards
|
||||||
+61
-77
@@ -1,10 +1,9 @@
|
|||||||
package com.sap.sailing.gwt.ui.server;
|
package com.sap.sailing.domain.leaderboard.caching;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.WeakHashMap;
|
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
@@ -15,18 +14,19 @@ import java.util.concurrent.ThreadPoolExecutor;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.sap.sailing.domain.base.DomainFactory;
|
||||||
import com.sap.sailing.domain.base.RaceColumnListener;
|
import com.sap.sailing.domain.base.RaceColumnListener;
|
||||||
import com.sap.sailing.domain.common.NoWindException;
|
import com.sap.sailing.domain.common.NoWindException;
|
||||||
import com.sap.sailing.domain.common.TimePoint;
|
import com.sap.sailing.domain.common.TimePoint;
|
||||||
|
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
|
||||||
import com.sap.sailing.domain.common.impl.Util;
|
import com.sap.sailing.domain.common.impl.Util;
|
||||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||||
import com.sap.sailing.domain.leaderboard.LeaderboardCache;
|
|
||||||
import com.sap.sailing.domain.leaderboard.LeaderboardCacheManager;
|
import com.sap.sailing.domain.leaderboard.LeaderboardCacheManager;
|
||||||
import com.sap.sailing.domain.leaderboard.ScoreCorrection;
|
import com.sap.sailing.domain.leaderboard.ScoreCorrection;
|
||||||
import com.sap.sailing.domain.leaderboard.ScoreCorrectionListener;
|
import com.sap.sailing.domain.leaderboard.ScoreCorrectionListener;
|
||||||
import com.sap.sailing.domain.tracking.RaceChangeListener;
|
import com.sap.sailing.domain.tracking.RaceChangeListener;
|
||||||
import com.sap.sailing.gwt.ui.shared.LeaderboardDTO;
|
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||||
import com.sap.sailing.util.impl.LockUtil;
|
import com.sap.sailing.util.impl.LockUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,13 +45,13 @@ public class LeaderboardDTOCache implements LeaderboardCache {
|
|||||||
private static final Logger logger = Logger.getLogger(LeaderboardDTOCache.class.getName());
|
private static final Logger logger = Logger.getLogger(LeaderboardDTOCache.class.getName());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In live operations, {@link #getLeaderboardByName(String, Date, Collection)} is the application's
|
* In live operations, {@link #getLeaderboardByName(Date, Collection, DomainFactory, TrackedRegattaRegistry)} is the application's
|
||||||
* bottleneck. When two clients ask the same data for the same leaderboard with their
|
* bottleneck. When two clients ask the same data for the same leaderboard with their
|
||||||
* <code>waitForLatestAnalyses</code> parameters set to <code>false</code>, expansion state and (quantized) time
|
* <code>waitForLatestAnalyses</code> parameters set to <code>false</code>, expansion state and (quantized) time
|
||||||
* stamp, no two computations should be spawned for the two clients. Instead, if the computation is still running,
|
* stamp, no two computations should be spawned for the two clients. Instead, if the computation is still running,
|
||||||
* all clients asking the same wait for the single result. Results are cached in this LRU-based evicting cache.
|
* all clients asking the same wait for the single result. Results are cached in this LRU-based evicting cache.
|
||||||
*/
|
*/
|
||||||
private final WeakHashMap<Leaderboard, Map<Util.Pair<TimePoint, Collection<String>>, FutureTask<LeaderboardDTO>>> leaderboardCache;
|
private final Map<Util.Pair<TimePoint, Collection<String>>, FutureTask<LeaderboardDTO>> leaderboardCache;
|
||||||
private int leaderboardByNameCacheHitCount;
|
private int leaderboardByNameCacheHitCount;
|
||||||
private int leaderboardByNameCacheMissCount;
|
private int leaderboardByNameCacheMissCount;
|
||||||
|
|
||||||
@@ -62,51 +62,45 @@ public class LeaderboardDTOCache implements LeaderboardCache {
|
|||||||
*/
|
*/
|
||||||
private final boolean waitForLatestAnalyses;
|
private final boolean waitForLatestAnalyses;
|
||||||
|
|
||||||
private final SailingServiceImpl sailingService;
|
private static final int THREAD_POOL_SIZE = Math.max(Runtime.getRuntime().availableProcessors(), 3);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A multi-threaded executor for the currently running leaderboard requests, executing the {@link Future}s currently
|
* A multi-threaded executor for the currently running leaderboard requests, executing the {@link Future}s currently
|
||||||
* pending.
|
* pending.
|
||||||
*/
|
*/
|
||||||
private final Executor computeLeadearboardByNameExecutor;
|
private static final Executor computeLeadearboardByNameExecutor = new ThreadPoolExecutor(/* corePoolSize */ THREAD_POOL_SIZE,
|
||||||
|
/* maximumPoolSize */ THREAD_POOL_SIZE,
|
||||||
|
/* keepAliveTime */ 60, TimeUnit.SECONDS,
|
||||||
|
/* workQueue */ new LinkedBlockingQueue<Runnable>());
|
||||||
|
|
||||||
private final LeaderboardCacheManager leaderboardCacheManager;
|
private final LeaderboardCacheManager leaderboardCacheManager;
|
||||||
|
|
||||||
public LeaderboardDTOCache(SailingServiceImpl sailingService, boolean waitForLatestAnalyses) {
|
private final Leaderboard leaderboard;
|
||||||
this.sailingService = sailingService;
|
|
||||||
|
public LeaderboardDTOCache(boolean waitForLatestAnalyses, Leaderboard leaderboard) {
|
||||||
|
this.leaderboard = leaderboard;
|
||||||
this.waitForLatestAnalyses = waitForLatestAnalyses;
|
this.waitForLatestAnalyses = waitForLatestAnalyses;
|
||||||
// if the leaderboard becomes weakly referenced and eventually GCed, then so can the cached results for it
|
// if the leaderboard becomes weakly referenced and eventually GCed, then so can the cached results for it
|
||||||
this.leaderboardCache = new WeakHashMap<Leaderboard, Map<Util.Pair<TimePoint, Collection<String>>, FutureTask<LeaderboardDTO>>>();
|
this.leaderboardCache = new LinkedHashMap<Pair<TimePoint, Collection<String>>, FutureTask<LeaderboardDTO>>() {
|
||||||
this.leaderboardCacheManager = new LeaderboardCacheManager(this);
|
|
||||||
final int THREAD_POOL_SIZE = Math.max(Runtime.getRuntime().availableProcessors(), 3);
|
|
||||||
this.computeLeadearboardByNameExecutor =
|
|
||||||
new ThreadPoolExecutor(/* corePoolSize */ THREAD_POOL_SIZE,
|
|
||||||
/* maximumPoolSize */ THREAD_POOL_SIZE,
|
|
||||||
/* keepAliveTime */ 60, TimeUnit.SECONDS,
|
|
||||||
/* workQueue */ new LinkedBlockingQueue<Runnable>());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invalidate(Leaderboard leaderboard) {
|
|
||||||
synchronized (leaderboardCache) {
|
|
||||||
leaderboardCache.remove(leaderboard);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void add(Leaderboard leaderboard) {
|
|
||||||
LinkedHashMap<Pair<TimePoint, Collection<String>>, FutureTask<LeaderboardDTO>> map = new LinkedHashMap<Pair<TimePoint, Collection<String>>, FutureTask<LeaderboardDTO>>() {
|
|
||||||
private static final long serialVersionUID = 7287916997229815039L;
|
private static final long serialVersionUID = 7287916997229815039L;
|
||||||
@Override
|
@Override
|
||||||
protected boolean removeEldestEntry(Map.Entry<Pair<TimePoint, Collection<String>>, FutureTask<LeaderboardDTO>> e) {
|
protected boolean removeEldestEntry(Map.Entry<Pair<TimePoint, Collection<String>>, FutureTask<LeaderboardDTO>> e) {
|
||||||
return size() > 10; // remember 10 LeaderboardDTOs per leaderborad
|
return size() > 10; // remember 10 LeaderboardDTOs per leaderborad
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
this.leaderboardCacheManager = new LeaderboardCacheManager(this);
|
||||||
|
this.leaderboardCacheManager.add(leaderboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invalidate(Leaderboard leaderboard) {
|
||||||
synchronized (leaderboardCache) {
|
synchronized (leaderboardCache) {
|
||||||
leaderboardCache.put(leaderboard, map);
|
leaderboardCache.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(Leaderboard leaderboard) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the cache holds entries for the <code>leaderboard</code> requested, compare <code>timePoint</code> to the
|
* If the cache holds entries for the <code>leaderboard</code> requested, compare <code>timePoint</code> to the
|
||||||
* {@link #getLatestModification latest modification} affecting the <code>leaderboard</code>. If
|
* {@link #getLatestModification latest modification} affecting the <code>leaderboard</code>. If
|
||||||
@@ -119,9 +113,9 @@ public class LeaderboardDTOCache implements LeaderboardCache {
|
|||||||
* {@link SailingServiceImpl#computeLeaderboardByName(Leaderboard, TimePoint, Collection, boolean)} if a new cache
|
* {@link SailingServiceImpl#computeLeaderboardByName(Leaderboard, TimePoint, Collection, boolean)} if a new cache
|
||||||
* entry needs to be computed. Caching distinguished between
|
* entry needs to be computed. Caching distinguished between
|
||||||
*/
|
*/
|
||||||
public LeaderboardDTO getLeaderboardByName(final Leaderboard leaderboard, final TimePoint timePoint,
|
public LeaderboardDTO getLeaderboardByName(final TimePoint timePoint, final Collection<String> namesOfRaceColumnsForWhichToLoadLegDetails,
|
||||||
final Collection<String> namesOfRaceColumnsForWhichToLoadLegDetails)
|
final DomainFactory baseDomainFactory, final TrackedRegattaRegistry trackedRegattaRegistry) throws NoWindException, InterruptedException,
|
||||||
throws NoWindException, InterruptedException, ExecutionException {
|
ExecutionException {
|
||||||
long startOfRequestHandling = System.currentTimeMillis();
|
long startOfRequestHandling = System.currentTimeMillis();
|
||||||
final TimePoint adjustedTimePoint;
|
final TimePoint adjustedTimePoint;
|
||||||
TimePoint timePointOfLastModification = leaderboard.getTimePointOfLatestModification();
|
TimePoint timePointOfLastModification = leaderboard.getTimePointOfLatestModification();
|
||||||
@@ -134,50 +128,40 @@ public class LeaderboardDTOCache implements LeaderboardCache {
|
|||||||
Util.Pair<TimePoint, Collection<String>> key = new Util.Pair<TimePoint, Collection<String>>(adjustedTimePoint,
|
Util.Pair<TimePoint, Collection<String>> key = new Util.Pair<TimePoint, Collection<String>>(adjustedTimePoint,
|
||||||
namesOfRaceColumnsForWhichToLoadLegDetails);
|
namesOfRaceColumnsForWhichToLoadLegDetails);
|
||||||
FutureTask<LeaderboardDTO> future = null;
|
FutureTask<LeaderboardDTO> future = null;
|
||||||
Map<Pair<TimePoint, Collection<String>>, FutureTask<LeaderboardDTO>> map = null;
|
|
||||||
boolean cacheHit = false;
|
boolean cacheHit = false;
|
||||||
synchronized (leaderboardCache) {
|
/*
|
||||||
map = leaderboardCache.get(leaderboard);
|
* Waiting for latest analyzes results largely regards wind estimation and maneuver cache; see SmartFutureCache.
|
||||||
if (map == null) {
|
* Even if waitForLatestAnalysis is requested, it is OK to cache. The cache would be invalidated when the race
|
||||||
future = null;
|
* changes, forcing a new re-calculation based on the latest analysis results. Once the race stabilizes, the
|
||||||
leaderboardCacheManager.add(leaderboard); // adds it to leaderboardCache by calling back our add(Leaderboard) method
|
* latest analysis results for maneuvers and wind estimation will no longer change and can quickly be obtained
|
||||||
map = leaderboardCache.get(leaderboard);
|
* from the respective SmartFutureCache. At the same time, if a LeaderboardDTOCache entry is found, that was
|
||||||
} else {
|
* based on the latest analysis results at the time. If new evidence is received, that would also invalidate the
|
||||||
/*
|
* LeaderboardDTOCache. Therefore, it's okay to re-use the LeaderboardDTOCache match even if the latest analysis
|
||||||
* Waiting for latest analyzes results largely regards wind estimation and maneuver cache; see
|
* results are requested.
|
||||||
* SmartFutureCache. Even if waitForLatestAnalysis is requested, it is OK to cache. The cache would be
|
*/
|
||||||
* invalidated when the race changes, forcing a new re-calculation based on the latest analysis results.
|
future = leaderboardCache.get(key);
|
||||||
* Once the race stabilizes, the latest analysis results for maneuvers and wind estimation will no
|
if (future == null) {
|
||||||
* longer change and can quickly be obtained from the respective SmartFutureCache. At the same time, if
|
final Thread callerThread = Thread.currentThread();
|
||||||
* a LeaderboardDTOCache entry is found, that was based on the latest analysis results at the time. If
|
future = new FutureTask<LeaderboardDTO>(new Callable<LeaderboardDTO>() {
|
||||||
* new evidence is received, that would also invalidate the LeaderboardDTOCache. Therefore, it's okay to
|
@Override
|
||||||
* re-use the LeaderboardDTOCache match even if the latest analysis results are requested.
|
public LeaderboardDTO call() throws Exception {
|
||||||
*/
|
// The outer getLeaderboardByName(...) method will always wait for this future's completion.
|
||||||
future = map.get(key);
|
// Therefore, it's safe to propagate the calling thread's locks to this one:
|
||||||
}
|
LockUtil.propagateLockSetFrom(callerThread);
|
||||||
if (future == null) {
|
try {
|
||||||
final Thread callerThread = Thread.currentThread();
|
LeaderboardDTO result = leaderboard.computeDTO(adjustedTimePoint,
|
||||||
future = new FutureTask<LeaderboardDTO>(new Callable<LeaderboardDTO>() {
|
namesOfRaceColumnsForWhichToLoadLegDetails, waitForLatestAnalyses,
|
||||||
@Override
|
trackedRegattaRegistry, baseDomainFactory);
|
||||||
public LeaderboardDTO call() throws Exception {
|
return result;
|
||||||
// The outer getLeaderboardByName(...) method will always wait for this future's completion.
|
} finally {
|
||||||
// Therefore, it's safe to propagate the calling thread's locks to this one:
|
LockUtil.unpropagateLockSetFrom(callerThread);
|
||||||
LockUtil.propagateLockSetFrom(callerThread);
|
|
||||||
try {
|
|
||||||
LeaderboardDTO result = sailingService.computeLeaderboardByName(leaderboard,
|
|
||||||
adjustedTimePoint, namesOfRaceColumnsForWhichToLoadLegDetails,
|
|
||||||
waitForLatestAnalyses);
|
|
||||||
return result;
|
|
||||||
} finally {
|
|
||||||
LockUtil.unpropagateLockSetFrom(callerThread);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
computeLeadearboardByNameExecutor.execute(future);
|
});
|
||||||
map.put(key, future);
|
computeLeadearboardByNameExecutor.execute(future);
|
||||||
} else {
|
leaderboardCache.put(key, future);
|
||||||
cacheHit = true;
|
} else {
|
||||||
}
|
cacheHit = true;
|
||||||
}
|
}
|
||||||
if (cacheHit) {
|
if (cacheHit) {
|
||||||
leaderboardByNameCacheHitCount++;
|
leaderboardByNameCacheHitCount++;
|
||||||
+14
-8
@@ -1,4 +1,4 @@
|
|||||||
package com.sap.sailing.gwt.ui.server;
|
package com.sap.sailing.domain.leaderboard.caching;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -8,11 +8,13 @@ import java.util.Set;
|
|||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.sap.sailing.domain.base.DomainFactory;
|
||||||
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
||||||
import com.sap.sailing.domain.common.NoWindException;
|
import com.sap.sailing.domain.common.NoWindException;
|
||||||
import com.sap.sailing.domain.common.TimePoint;
|
import com.sap.sailing.domain.common.TimePoint;
|
||||||
|
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
|
||||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||||
import com.sap.sailing.gwt.ui.shared.LeaderboardDTO;
|
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computing a leaderboard live, particularly when the fleet tracked is large, requires considerable resources.
|
* Computing a leaderboard live, particularly when the fleet tracked is large, requires considerable resources.
|
||||||
@@ -54,8 +56,6 @@ public class LiveLeaderboardUpdater implements Runnable {
|
|||||||
|
|
||||||
private final Leaderboard leaderboard;
|
private final Leaderboard leaderboard;
|
||||||
|
|
||||||
private final SailingServiceImpl sailingService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Live leaderboard results containing column details for all column names in
|
* Live leaderboard results containing column details for all column names in
|
||||||
* {@link #columnNamesForWhichCurrentLiveLeaderboardHasTheDetails}. May be <code>null</code> if
|
* {@link #columnNamesForWhichCurrentLiveLeaderboardHasTheDetails}. May be <code>null</code> if
|
||||||
@@ -100,10 +100,15 @@ public class LiveLeaderboardUpdater implements Runnable {
|
|||||||
* takes longer than {@link #UPDATE_TIMEOUT_IN_MILLIS} milliseconds.
|
* takes longer than {@link #UPDATE_TIMEOUT_IN_MILLIS} milliseconds.
|
||||||
*/
|
*/
|
||||||
private Thread thread;
|
private Thread thread;
|
||||||
|
|
||||||
|
private TrackedRegattaRegistry trackedRegattaRegistry;
|
||||||
|
|
||||||
|
private DomainFactory baseDomainFactory;
|
||||||
|
|
||||||
public LiveLeaderboardUpdater(Leaderboard leaderboard, SailingServiceImpl sailingService) {
|
public LiveLeaderboardUpdater(Leaderboard leaderboard, TrackedRegattaRegistry trackedRegattaRegistry, DomainFactory baseDomainFactory) {
|
||||||
this.leaderboard = leaderboard;
|
this.leaderboard = leaderboard;
|
||||||
this.sailingService = sailingService;
|
this.trackedRegattaRegistry = trackedRegattaRegistry;
|
||||||
|
this.baseDomainFactory = baseDomainFactory;
|
||||||
this.timePointOfLastRequestForColumnDetails = new HashMap<String, TimePoint>();
|
this.timePointOfLastRequestForColumnDetails = new HashMap<String, TimePoint>();
|
||||||
this.columnNamesForWhichCurrentLiveLeaderboardHasTheDetails = new HashSet<String>();
|
this.columnNamesForWhichCurrentLiveLeaderboardHasTheDetails = new HashSet<String>();
|
||||||
}
|
}
|
||||||
@@ -248,8 +253,9 @@ public class LiveLeaderboardUpdater implements Runnable {
|
|||||||
TimePoint timeLastUpdateWasStarted = now;
|
TimePoint timeLastUpdateWasStarted = now;
|
||||||
try {
|
try {
|
||||||
final Set<String> namesOfRaceColumnsForWhichToLoadLegDetails = getColumnNamesForWhichToFetchDetails(timePoint);
|
final Set<String> namesOfRaceColumnsForWhichToLoadLegDetails = getColumnNamesForWhichToFetchDetails(timePoint);
|
||||||
LeaderboardDTO newCacheValue = sailingService.computeLeaderboardByName(leaderboard, timePoint,
|
LeaderboardDTO newCacheValue = leaderboard.computeDTO(timePoint,
|
||||||
namesOfRaceColumnsForWhichToLoadLegDetails, /* waitForLatestAnalyses */false);
|
namesOfRaceColumnsForWhichToLoadLegDetails, /* waitForLatestAnalyses */false,
|
||||||
|
trackedRegattaRegistry, baseDomainFactory);
|
||||||
updateCacheContents(namesOfRaceColumnsForWhichToLoadLegDetails, newCacheValue);
|
updateCacheContents(namesOfRaceColumnsForWhichToLoadLegDetails, newCacheValue);
|
||||||
} catch (NoWindException e) {
|
} catch (NoWindException e) {
|
||||||
logger.info("Unable to update cached leaderboard results for leaderboard " + leaderboard.getName() + ": "
|
logger.info("Unable to update cached leaderboard results for leaderboard " + leaderboard.getName() + ": "
|
||||||
+750
-4
@@ -1,41 +1,85 @@
|
|||||||
package com.sap.sailing.domain.leaderboard.impl;
|
package com.sap.sailing.domain.leaderboard.impl;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.NavigableSet;
|
import java.util.NavigableSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.FutureTask;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
import java.util.concurrent.RunnableFuture;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import com.sap.sailing.domain.base.Competitor;
|
import com.sap.sailing.domain.base.Competitor;
|
||||||
|
import com.sap.sailing.domain.base.Course;
|
||||||
|
import com.sap.sailing.domain.base.DomainFactory;
|
||||||
import com.sap.sailing.domain.base.Fleet;
|
import com.sap.sailing.domain.base.Fleet;
|
||||||
import com.sap.sailing.domain.base.Leg;
|
import com.sap.sailing.domain.base.Leg;
|
||||||
|
import com.sap.sailing.domain.base.Mark;
|
||||||
import com.sap.sailing.domain.base.RaceColumn;
|
import com.sap.sailing.domain.base.RaceColumn;
|
||||||
import com.sap.sailing.domain.base.RaceColumnListener;
|
import com.sap.sailing.domain.base.RaceColumnListener;
|
||||||
|
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||||
|
import com.sap.sailing.domain.base.Waypoint;
|
||||||
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
||||||
import com.sap.sailing.domain.common.Distance;
|
import com.sap.sailing.domain.common.Distance;
|
||||||
import com.sap.sailing.domain.common.LegType;
|
import com.sap.sailing.domain.common.LegType;
|
||||||
|
import com.sap.sailing.domain.common.ManeuverType;
|
||||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||||
|
import com.sap.sailing.domain.common.NoWindError;
|
||||||
import com.sap.sailing.domain.common.NoWindException;
|
import com.sap.sailing.domain.common.NoWindException;
|
||||||
|
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||||
|
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
||||||
import com.sap.sailing.domain.common.Speed;
|
import com.sap.sailing.domain.common.Speed;
|
||||||
import com.sap.sailing.domain.common.TimePoint;
|
import com.sap.sailing.domain.common.TimePoint;
|
||||||
|
import com.sap.sailing.domain.common.WindSource;
|
||||||
|
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.FleetDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.LeaderboardEntryDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.LeaderboardRowDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.LegEntryDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.RaceDTO;
|
||||||
import com.sap.sailing.domain.common.impl.Util;
|
import com.sap.sailing.domain.common.impl.Util;
|
||||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||||
import com.sap.sailing.domain.leaderboard.ScoreCorrection.Result;
|
|
||||||
import com.sap.sailing.domain.leaderboard.NumberOfCompetitorsInLeaderboardFetcher;
|
import com.sap.sailing.domain.leaderboard.NumberOfCompetitorsInLeaderboardFetcher;
|
||||||
|
import com.sap.sailing.domain.leaderboard.ScoreCorrection.Result;
|
||||||
import com.sap.sailing.domain.leaderboard.SettableScoreCorrection;
|
import com.sap.sailing.domain.leaderboard.SettableScoreCorrection;
|
||||||
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
||||||
|
import com.sap.sailing.domain.leaderboard.caching.LeaderboardDTOCache;
|
||||||
|
import com.sap.sailing.domain.leaderboard.caching.LiveLeaderboardUpdater;
|
||||||
import com.sap.sailing.domain.racelog.RaceLogEvent;
|
import com.sap.sailing.domain.racelog.RaceLogEvent;
|
||||||
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
|
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
|
||||||
|
import com.sap.sailing.domain.tracking.GPSFix;
|
||||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||||
|
import com.sap.sailing.domain.tracking.Maneuver;
|
||||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||||
|
import com.sap.sailing.domain.tracking.MarkPassingManeuver;
|
||||||
|
import com.sap.sailing.domain.tracking.RaceChangeListener;
|
||||||
|
import com.sap.sailing.domain.tracking.TrackedLeg;
|
||||||
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
|
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
|
||||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||||
|
import com.sap.sailing.domain.tracking.TrackedRaceStatus;
|
||||||
|
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||||
|
import com.sap.sailing.domain.tracking.Wind;
|
||||||
import com.sap.sailing.util.impl.RaceColumnListeners;
|
import com.sap.sailing.util.impl.RaceColumnListeners;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -49,6 +93,8 @@ import com.sap.sailing.util.impl.RaceColumnListeners;
|
|||||||
*/
|
*/
|
||||||
public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, RaceColumnListener {
|
public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, RaceColumnListener {
|
||||||
private static final long serialVersionUID = 330156778603279333L;
|
private static final long serialVersionUID = 330156778603279333L;
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(AbstractSimpleLeaderboardImpl.class.getName());
|
||||||
|
|
||||||
static final Double DOUBLE_0 = new Double(0);
|
static final Double DOUBLE_0 = new Double(0);
|
||||||
|
|
||||||
@@ -78,6 +124,27 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
|||||||
* A synchronized set that manages the difference between {@link #getCompetitors()} and {@link #getAllCompetitors()}.
|
* A synchronized set that manages the difference between {@link #getCompetitors()} and {@link #getAllCompetitors()}.
|
||||||
*/
|
*/
|
||||||
private final Set<Competitor> suppressedCompetitors;
|
private final Set<Competitor> suppressedCompetitors;
|
||||||
|
|
||||||
|
private final Map<Pair<TrackedRace, Competitor>, RunnableFuture<RaceDetails>> raceDetailsAtEndOfTrackingCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This executor needs to be a different one than {@link #executor} because the tasks run by {@link #executor}
|
||||||
|
* can depend on the results of the tasks run by {@link #raceDetailsExecutor}, and an {@link Executor} doesn't
|
||||||
|
* move a task that is blocked by waiting for another {@link FutureTask} to the side but blocks permanently,
|
||||||
|
* ending in a deadlock (one that cannot easily be detected by the Eclipse debugger either).
|
||||||
|
*/
|
||||||
|
private transient Executor raceDetailsExecutor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to remove all these listeners from their tracked races when this servlet is {@link #destroy() destroyed}.
|
||||||
|
*/
|
||||||
|
private transient Set<CacheInvalidationListener> cacheInvalidationListeners;
|
||||||
|
|
||||||
|
private transient ThreadPoolExecutor executor;
|
||||||
|
|
||||||
|
private transient LiveLeaderboardUpdater liveLeaderboardUpdater;
|
||||||
|
|
||||||
|
private transient LeaderboardDTOCache leaderboardDTOCache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A leaderboard entry representing a snapshot of a cell at a given time point for a single race/competitor.
|
* A leaderboard entry representing a snapshot of a cell at a given time point for a single race/competitor.
|
||||||
@@ -170,14 +237,129 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public AbstractSimpleLeaderboardImpl(SettableScoreCorrection scoreCorrection,
|
/**
|
||||||
ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
* Handles the invalidation of the {@link SailingServiceImpl#raceDetailsAtEndOfTrackingCache} entries if the tracked race
|
||||||
|
* changes in any way.
|
||||||
|
*
|
||||||
|
* @author Axel Uhl (D043530)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private class CacheInvalidationListener implements RaceChangeListener {
|
||||||
|
private final TrackedRace trackedRace;
|
||||||
|
private final Competitor competitor;
|
||||||
|
|
||||||
|
public CacheInvalidationListener(TrackedRace trackedRace, Competitor competitor) {
|
||||||
|
this.trackedRace = trackedRace;
|
||||||
|
this.competitor = competitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TrackedRace getTrackedRace() {
|
||||||
|
return trackedRace;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeFromTrackedRace() {
|
||||||
|
trackedRace.removeListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void invalidateCacheAndRemoveThisListenerFromTrackedRace() {
|
||||||
|
synchronized (raceDetailsAtEndOfTrackingCache) {
|
||||||
|
raceDetailsAtEndOfTrackingCache.remove(new Pair<TrackedRace, Competitor>(trackedRace, competitor));
|
||||||
|
removeFromTrackedRace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void competitorPositionChanged(GPSFixMoving fix, Competitor competitor) {
|
||||||
|
invalidateCacheAndRemoveThisListenerFromTrackedRace();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void statusChanged(TrackedRaceStatus newStatus) {
|
||||||
|
// when the status changes away from LOADING, calculations may start or resume, making it necessary to clear the cache
|
||||||
|
invalidateCacheAndRemoveThisListenerFromTrackedRace();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void markPositionChanged(GPSFix fix, Mark mark) {
|
||||||
|
invalidateCacheAndRemoveThisListenerFromTrackedRace();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void markPassingReceived(Competitor competitor, Map<Waypoint, MarkPassing> oldMarkPassings,
|
||||||
|
Iterable<MarkPassing> markPassings) {
|
||||||
|
invalidateCacheAndRemoveThisListenerFromTrackedRace();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void speedAveragingChanged(long oldMillisecondsOverWhichToAverage, long newMillisecondsOverWhichToAverage) {
|
||||||
|
invalidateCacheAndRemoveThisListenerFromTrackedRace();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void windDataReceived(Wind wind, WindSource windSource) {
|
||||||
|
invalidateCacheAndRemoveThisListenerFromTrackedRace();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void windDataRemoved(Wind wind, WindSource windSource) {
|
||||||
|
invalidateCacheAndRemoveThisListenerFromTrackedRace();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void windAveragingChanged(long oldMillisecondsOverWhichToAverage, long newMillisecondsOverWhichToAverage) {
|
||||||
|
invalidateCacheAndRemoveThisListenerFromTrackedRace();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void raceTimesChanged(TimePoint startOfTracking, TimePoint endOfTracking, TimePoint startTimeReceived) {
|
||||||
|
invalidateCacheAndRemoveThisListenerFromTrackedRace();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delayToLiveChanged(long delayToLiveInMillis) {
|
||||||
|
invalidateCacheAndRemoveThisListenerFromTrackedRace();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void windSourcesToExcludeChanged(Iterable<? extends WindSource> windSourcesToExclude) {
|
||||||
|
invalidateCacheAndRemoveThisListenerFromTrackedRace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractSimpleLeaderboardImpl(SettableScoreCorrection scoreCorrection, ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||||
this.carriedPoints = new HashMap<Competitor, Double>();
|
this.carriedPoints = new HashMap<Competitor, Double>();
|
||||||
this.scoreCorrection = scoreCorrection;
|
this.scoreCorrection = scoreCorrection;
|
||||||
this.displayNames = new HashMap<Competitor, String>();
|
this.displayNames = new HashMap<Competitor, String>();
|
||||||
this.resultDiscardingRule = resultDiscardingRule;
|
this.resultDiscardingRule = resultDiscardingRule;
|
||||||
this.suppressedCompetitors = Collections.synchronizedSet(new HashSet<Competitor>());
|
this.suppressedCompetitors = Collections.synchronizedSet(new HashSet<Competitor>());
|
||||||
raceColumnListeners = new RaceColumnListeners();
|
this.raceColumnListeners = new RaceColumnListeners();
|
||||||
|
this.raceDetailsAtEndOfTrackingCache = new HashMap<Pair<TrackedRace, Competitor>, RunnableFuture<RaceDetails>>();
|
||||||
|
initTransientFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
|
||||||
|
ois.defaultReadObject();
|
||||||
|
initTransientFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initTransientFields() {
|
||||||
|
this.raceDetailsExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
|
||||||
|
this.cacheInvalidationListeners = new HashSet<CacheInvalidationListener>();
|
||||||
|
// When many updates are triggered in a short period of time by a single thread, ensure that the single thread
|
||||||
|
// providing the updates is not outperformed by all the re-calculations happening here. Leave at least one
|
||||||
|
// core to other things, but by using at least three threads ensure that no simplistic deadlocks may occur.
|
||||||
|
final int THREAD_POOL_SIZE = Math.max(Runtime.getRuntime().availableProcessors(), 3);
|
||||||
|
executor = new ThreadPoolExecutor(/* corePoolSize */ THREAD_POOL_SIZE,
|
||||||
|
/* maximumPoolSize */ THREAD_POOL_SIZE,
|
||||||
|
/* keepAliveTime */ 60, TimeUnit.SECONDS,
|
||||||
|
/* workQueue */ new LinkedBlockingQueue<Runnable>());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
for (CacheInvalidationListener cacheInvalidationListener : cacheInvalidationListeners) {
|
||||||
|
cacheInvalidationListener.removeFromTrackedRace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -490,6 +672,21 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
|||||||
@Override
|
@Override
|
||||||
public void trackedRaceUnlinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
|
public void trackedRaceUnlinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
|
||||||
getRaceColumnListeners().notifyListenersAboutTrackedRaceUnlinked(raceColumn, fleet, trackedRace);
|
getRaceColumnListeners().notifyListenersAboutTrackedRaceUnlinked(raceColumn, fleet, trackedRace);
|
||||||
|
// It's generally possible that a leaderboard links to the same tracked race in multiple columns / fleets;
|
||||||
|
// only if it no longer references the trackedRace currently unlinked from one column/fleet, also unlink
|
||||||
|
// all cache invalidation listeners for said trackedRace
|
||||||
|
if (!Util.contains(getTrackedRaces(), trackedRace)) {
|
||||||
|
synchronized (cacheInvalidationListeners) {
|
||||||
|
for (Iterator<CacheInvalidationListener> cacheInvalidationListenerIter=cacheInvalidationListeners.iterator();
|
||||||
|
cacheInvalidationListenerIter.hasNext(); ) {
|
||||||
|
CacheInvalidationListener cacheInvalidationListener = cacheInvalidationListenerIter.next();
|
||||||
|
if (cacheInvalidationListener.getTrackedRace() == trackedRace) {
|
||||||
|
cacheInvalidationListener.removeFromTrackedRace();
|
||||||
|
cacheInvalidationListenerIter.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -769,4 +966,553 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
|||||||
public void raceLogEventAdded(RaceColumn raceColumn, RaceLogIdentifier raceLogIdentifier, RaceLogEvent event) {
|
public void raceLogEventAdded(RaceColumn raceColumn, RaceLogIdentifier raceLogIdentifier, RaceLogEvent event) {
|
||||||
getRaceColumnListeners().notifyListenersAboutRaceLogEventAdded(raceColumn, raceLogIdentifier, event);
|
getRaceColumnListeners().notifyListenersAboutRaceLogEventAdded(raceColumn, raceLogIdentifier, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LeaderboardDTO computeDTO(final TimePoint timePoint,
|
||||||
|
final Collection<String> namesOfRaceColumnsForWhichToLoadLegDetails, final boolean waitForLatestAnalyses,
|
||||||
|
TrackedRegattaRegistry trackedRegattaRegistry, final DomainFactory baseDomainFactory)
|
||||||
|
throws NoWindException {
|
||||||
|
long startOfRequestHandling = System.currentTimeMillis();
|
||||||
|
LeaderboardDTO result = null;
|
||||||
|
result = new LeaderboardDTO(this.getScoreCorrection().getTimePointOfLastCorrectionsValidity()==null ?
|
||||||
|
null : this.getScoreCorrection().getTimePointOfLastCorrectionsValidity().asDate(),
|
||||||
|
this.getScoreCorrection()==null?null:this.getScoreCorrection().getComment(),
|
||||||
|
this.getScoringScheme().isHigherBetter());
|
||||||
|
result.competitors = new ArrayList<CompetitorDTO>();
|
||||||
|
result.name = this.getName();
|
||||||
|
result.competitorDisplayNames = new HashMap<CompetitorDTO, String>();
|
||||||
|
for (Competitor suppressedCompetitor : this.getSuppressedCompetitors()) {
|
||||||
|
result.setSuppressed(baseDomainFactory.convertToCompetitorDTO(suppressedCompetitor), true);
|
||||||
|
}
|
||||||
|
for (RaceColumn raceColumn : this.getRaceColumns()) {
|
||||||
|
RaceColumnDTO raceColumnDTO = result.createEmptyRaceColumn(raceColumn.getName(), raceColumn.isMedalRace(),
|
||||||
|
this.getScoringScheme().isValidInTotalScore(this, raceColumn, timePoint));
|
||||||
|
for (Fleet fleet : raceColumn.getFleets()) {
|
||||||
|
TimePoint latestTimePointAfterQueryTimePointWhenATrackedRaceWasLive = null;
|
||||||
|
RegattaAndRaceIdentifier raceIdentifier = null;
|
||||||
|
RaceDTO race = null;
|
||||||
|
TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
|
||||||
|
|
||||||
|
final FleetDTO fleetDTO = baseDomainFactory.convertToFleetDTO(raceColumn, fleet);
|
||||||
|
if (trackedRace != null) {
|
||||||
|
raceIdentifier = new RegattaNameAndRaceName(trackedRace.getTrackedRegatta().getRegatta()
|
||||||
|
.getName(), trackedRace.getRace().getName());
|
||||||
|
race = baseDomainFactory.createRaceDTO(trackedRegattaRegistry, false, raceIdentifier, trackedRace);
|
||||||
|
if (trackedRace.hasStarted(timePoint) && trackedRace.hasGPSData() && trackedRace.hasWindData()) {
|
||||||
|
TimePoint liveTimePointForTrackedRace = timePoint;
|
||||||
|
final TimePoint endOfRace = trackedRace.getEndOfRace();
|
||||||
|
if (endOfRace != null) {
|
||||||
|
liveTimePointForTrackedRace = endOfRace;
|
||||||
|
}
|
||||||
|
latestTimePointAfterQueryTimePointWhenATrackedRaceWasLive = liveTimePointForTrackedRace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: the RaceColumnDTO won't be created by the following addRace call because it has been created
|
||||||
|
// above by the result.createEmptyRaceColumn call
|
||||||
|
result.addRace(raceColumn.getName(), raceColumn.getExplicitFactor(), raceColumn.getFactor(),
|
||||||
|
fleetDTO, raceColumn.isMedalRace(), raceIdentifier, race);
|
||||||
|
if (latestTimePointAfterQueryTimePointWhenATrackedRaceWasLive != null) {
|
||||||
|
raceColumnDTO.setWhenLastTrackedRaceWasLive(fleetDTO, latestTimePointAfterQueryTimePointWhenATrackedRaceWasLive.asDate());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.setCompetitorsFromBestToWorst(raceColumnDTO, baseDomainFactory.getCompetitorDTOList(this.getCompetitorsFromBestToWorst(raceColumn, timePoint)));
|
||||||
|
}
|
||||||
|
result.setDelayToLiveInMillisForLatestRace(this.getDelayToLiveInMillis());
|
||||||
|
result.rows = new HashMap<CompetitorDTO, LeaderboardRowDTO>();
|
||||||
|
result.hasCarriedPoints = this.hasCarriedPoints();
|
||||||
|
result.discardThresholds = this.getResultDiscardingRule().getDiscardIndexResultsStartingWithHowManyRaces();
|
||||||
|
// Computing the competitor leg ranks is expensive, especially in live mode, in case new events keep invalidating
|
||||||
|
// the ranks cache in TrackedLegImpl. Then problem then is that the sorting based on wind data is repeated for each
|
||||||
|
// competitor, leading to square effort. We therefore need to compute the leg ranks for those race where leg details
|
||||||
|
// are requested only once and pass them into getLeaderboardEntryDTO
|
||||||
|
final Map<Leg, LinkedHashMap<Competitor, Integer>> legRanksCache = new HashMap<Leg, LinkedHashMap<Competitor,Integer>>();
|
||||||
|
for (final RaceColumn raceColumn : this.getRaceColumns()) {
|
||||||
|
// if details for the column are requested, cache the leg's ranks
|
||||||
|
if (namesOfRaceColumnsForWhichToLoadLegDetails != null
|
||||||
|
&& namesOfRaceColumnsForWhichToLoadLegDetails.contains(raceColumn.getName())) {
|
||||||
|
for (Fleet fleet : raceColumn.getFleets()) {
|
||||||
|
TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
|
||||||
|
if (trackedRace != null) {
|
||||||
|
trackedRace.getRace().getCourse().lockForRead();
|
||||||
|
try {
|
||||||
|
for (TrackedLeg trackedLeg : trackedRace.getTrackedLegs()) {
|
||||||
|
legRanksCache.put(trackedLeg.getLeg(), trackedLeg.getRanks(timePoint));
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
trackedRace.getRace().getCourse().unlockAfterRead();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (final Competitor competitor : this.getCompetitorsFromBestToWorst(timePoint)) {
|
||||||
|
CompetitorDTO competitorDTO = baseDomainFactory.convertToCompetitorDTO(competitor);
|
||||||
|
LeaderboardRowDTO row = new LeaderboardRowDTO();
|
||||||
|
row.competitor = competitorDTO;
|
||||||
|
row.fieldsByRaceColumnName = new HashMap<String, LeaderboardEntryDTO>();
|
||||||
|
row.carriedPoints = this.hasCarriedPoints(competitor) ? this.getCarriedPoints(competitor) : null;
|
||||||
|
addOverallDetailsToRow(timePoint, competitor, row);
|
||||||
|
result.competitors.add(competitorDTO);
|
||||||
|
Map<String, Future<LeaderboardEntryDTO>> futuresForColumnName = new HashMap<String, Future<LeaderboardEntryDTO>>();
|
||||||
|
for (final RaceColumn raceColumn : this.getRaceColumns()) {
|
||||||
|
RunnableFuture<LeaderboardEntryDTO> future = new FutureTask<LeaderboardEntryDTO>(new Callable<LeaderboardEntryDTO>() {
|
||||||
|
@Override
|
||||||
|
public LeaderboardEntryDTO call() {
|
||||||
|
try {
|
||||||
|
Entry entry = AbstractSimpleLeaderboardImpl.this.getEntry(competitor, raceColumn, timePoint);
|
||||||
|
return getLeaderboardEntryDTO(entry, raceColumn, competitor, timePoint,
|
||||||
|
namesOfRaceColumnsForWhichToLoadLegDetails != null
|
||||||
|
&& namesOfRaceColumnsForWhichToLoadLegDetails.contains(raceColumn.getName()),
|
||||||
|
waitForLatestAnalyses, legRanksCache, baseDomainFactory);
|
||||||
|
} catch (NoWindException e) {
|
||||||
|
logger.info("Exception trying to compute leaderboard entry for competitor "+competitor.getName()+
|
||||||
|
" in race column "+raceColumn.getName()+": "+e.getMessage());
|
||||||
|
logger.throwing(AbstractSimpleLeaderboardImpl.class.getName(), "computeLeaderboardByName.future.call()", e);
|
||||||
|
throw new NoWindError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
executor.execute(future);
|
||||||
|
futuresForColumnName.put(raceColumn.getName(), future);
|
||||||
|
}
|
||||||
|
for (Map.Entry<String, Future<LeaderboardEntryDTO>> raceColumnNameAndFuture : futuresForColumnName.entrySet()) {
|
||||||
|
try {
|
||||||
|
row.fieldsByRaceColumnName.put(raceColumnNameAndFuture.getKey(), raceColumnNameAndFuture.getValue().get());
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (ExecutionException e) {
|
||||||
|
// See also bug 1371: for stability reasons, don't let the exception percolate but rather accept null values.
|
||||||
|
// If new evidence is provided, a re-calculation of the leaderboard will be triggered anyway. So this helps
|
||||||
|
// robustness from a user's perspective.
|
||||||
|
logger.log(Level.SEVERE, AbstractSimpleLeaderboardImpl.class.getName()+".computeDTO("
|
||||||
|
+this.getName()+", "+timePoint+", "+namesOfRaceColumnsForWhichToLoadLegDetails+
|
||||||
|
"): exception during computing leaderboard entry for competitor "+competitor.getName()+
|
||||||
|
" in race column "+raceColumnNameAndFuture.getKey()+". Leaving empty.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.rows.put(competitorDTO, row);
|
||||||
|
String displayName = this.getDisplayName(competitor);
|
||||||
|
if (displayName != null) {
|
||||||
|
result.competitorDisplayNames.put(competitorDTO, displayName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.info("computeLeaderboardByName("+this.getName()+", "+timePoint+", "+namesOfRaceColumnsForWhichToLoadLegDetails+") took "+
|
||||||
|
(System.currentTimeMillis()-startOfRequestHandling)+"ms");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addOverallDetailsToRow(final TimePoint timePoint,
|
||||||
|
final Competitor competitor, LeaderboardRowDTO row) throws NoWindException {
|
||||||
|
final Pair<GPSFixMoving, Speed> maximumSpeedOverGround = this.getMaximumSpeedOverGround(competitor, timePoint);
|
||||||
|
if (maximumSpeedOverGround != null && maximumSpeedOverGround.getB() != null) {
|
||||||
|
row.maximumSpeedOverGroundInKnots = maximumSpeedOverGround.getB().getKnots();
|
||||||
|
row.whenMaximumSpeedOverGroundWasAchieved = maximumSpeedOverGround.getA().getTimePoint().asDate();
|
||||||
|
}
|
||||||
|
final Long totalTimeSailedDownwindInMilliseconds = this.getTotalTimeSailedInLegTypeInMilliseconds(competitor, LegType.DOWNWIND, timePoint);
|
||||||
|
row.totalTimeSailedDownwindInSeconds = totalTimeSailedDownwindInMilliseconds==null?null:1./1000.*totalTimeSailedDownwindInMilliseconds;
|
||||||
|
final Long totalTimeSailedUpwindInMilliseconds = this.getTotalTimeSailedInLegTypeInMilliseconds(competitor, LegType.UPWIND, timePoint);
|
||||||
|
row.totalTimeSailedUpwindInSeconds = totalTimeSailedUpwindInMilliseconds==null?null:1./1000.*totalTimeSailedUpwindInMilliseconds;
|
||||||
|
final Long totalTimeSailedReachingInMilliseconds = this.getTotalTimeSailedInLegTypeInMilliseconds(competitor, LegType.REACHING, timePoint);
|
||||||
|
row.totalTimeSailedReachingInSeconds = totalTimeSailedReachingInMilliseconds==null?null:1./1000.*totalTimeSailedReachingInMilliseconds;
|
||||||
|
final Long totalTimeSailedInMilliseconds = this.getTotalTimeSailedInMilliseconds(competitor, timePoint);
|
||||||
|
row.totalTimeSailedInSeconds = totalTimeSailedInMilliseconds==null?null:1./1000.*totalTimeSailedInMilliseconds;
|
||||||
|
final Distance totalDistanceTraveledInMeters = this.getTotalDistanceTraveled(competitor, timePoint);
|
||||||
|
row.totalDistanceTraveledInMeters = totalDistanceTraveledInMeters==null?null:totalDistanceTraveledInMeters.getMeters();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param waitForLatestAnalyses
|
||||||
|
* if <code>false</code>, this method is allowed to read the maneuver analysis results from a cache that
|
||||||
|
* may not reflect all data already received; otherwise, the method will always block for the latest
|
||||||
|
* cache updates to have happened before returning.
|
||||||
|
* @param baseDomainFactory TODO
|
||||||
|
*/
|
||||||
|
private LeaderboardEntryDTO getLeaderboardEntryDTO(Entry entry, RaceColumn raceColumn, Competitor competitor,
|
||||||
|
TimePoint timePoint, boolean addLegDetails, boolean waitForLatestAnalyses,
|
||||||
|
Map<Leg, LinkedHashMap<Competitor, Integer>> legRanksCache, DomainFactory baseDomainFactory) throws NoWindException {
|
||||||
|
LeaderboardEntryDTO entryDTO = new LeaderboardEntryDTO();
|
||||||
|
TrackedRace trackedRace = raceColumn.getTrackedRace(competitor);
|
||||||
|
entryDTO.race = trackedRace == null ? null : trackedRace.getRaceIdentifier();
|
||||||
|
entryDTO.netPoints = entry.getNetPoints();
|
||||||
|
entryDTO.netPointsCorrected = entry.isNetPointsCorrected();
|
||||||
|
entryDTO.totalPoints = entry.getTotalPoints();
|
||||||
|
entryDTO.reasonForMaxPoints = entry.getMaxPointsReason();
|
||||||
|
entryDTO.discarded = entry.isDiscarded();
|
||||||
|
if (addLegDetails && trackedRace != null) {
|
||||||
|
try {
|
||||||
|
RaceDetails raceDetails = getRaceDetails(trackedRace, competitor, timePoint, waitForLatestAnalyses, legRanksCache);
|
||||||
|
entryDTO.legDetails = raceDetails.getLegDetails();
|
||||||
|
entryDTO.windwardDistanceToOverallLeaderInMeters = raceDetails.getWindwardDistanceToOverallLeader() == null ? null
|
||||||
|
: raceDetails.getWindwardDistanceToOverallLeader().getMeters();
|
||||||
|
entryDTO.averageCrossTrackErrorInMeters = raceDetails.getAverageCrossTrackError() == null ? null
|
||||||
|
: raceDetails.getAverageCrossTrackError().getMeters();
|
||||||
|
final TimePoint startOfRace = trackedRace.getStartOfRace();
|
||||||
|
if (startOfRace != null) {
|
||||||
|
Distance distanceToStartLineAtStartOfRace = trackedRace.getDistanceToStartLine(competitor,
|
||||||
|
startOfRace);
|
||||||
|
entryDTO.distanceToStartLineAtStartOfRaceInMeters = distanceToStartLineAtStartOfRace == null ? null
|
||||||
|
: distanceToStartLineAtStartOfRace.getMeters();
|
||||||
|
Speed speedAtStartTime = trackedRace.getTrack(competitor).getEstimatedSpeed(startOfRace);
|
||||||
|
entryDTO.speedOverGroundAtStartOfRaceInKnots = speedAtStartTime == null ? null : speedAtStartTime.getKnots();
|
||||||
|
NavigableSet<MarkPassing> competitorMarkPassings = trackedRace.getMarkPassings(competitor);
|
||||||
|
trackedRace.lockForRead(competitorMarkPassings);
|
||||||
|
try {
|
||||||
|
if (!competitorMarkPassings.isEmpty()) {
|
||||||
|
TimePoint competitorStartTime = competitorMarkPassings.iterator().next().getTimePoint();
|
||||||
|
Speed competitorSpeedWhenPassingStart = trackedRace.getTrack(competitor).getEstimatedSpeed(
|
||||||
|
competitorStartTime);
|
||||||
|
entryDTO.speedOverGroundAtPassingStartWaypointInKnots = competitorSpeedWhenPassingStart == null ? null
|
||||||
|
: competitorSpeedWhenPassingStart.getKnots();
|
||||||
|
entryDTO.startTack = trackedRace.getTack(competitor, competitorStartTime);
|
||||||
|
Distance distanceFromStarboardSideOfStartLineWhenPassingStart = trackedRace.getDistanceFromStarboardSideOfStartLineWhenPassingStart(competitor);
|
||||||
|
entryDTO.distanceToStarboardSideOfStartLineInMeters = distanceFromStarboardSideOfStartLineWhenPassingStart == null ? null :
|
||||||
|
distanceFromStarboardSideOfStartLineWhenPassingStart.getMeters();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
trackedRace.unlockAfterRead(competitorMarkPassings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (ExecutionException e) {
|
||||||
|
throw new RuntimeException(e); // the future used to calculate the leg details was interrupted; escalate as runtime exception
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final Fleet fleet = entry.getFleet();
|
||||||
|
entryDTO.fleet = fleet == null ? null : baseDomainFactory.convertToFleetDTO(raceColumn, fleet);
|
||||||
|
return entryDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class RaceDetails {
|
||||||
|
private final List<LegEntryDTO> legDetails;
|
||||||
|
private final Distance windwardDistanceToOverallLeader;
|
||||||
|
private final Distance averageCrossTrackError;
|
||||||
|
public RaceDetails(List<LegEntryDTO> legDetails, Distance windwardDistanceToOverallLeader,
|
||||||
|
Distance averageCrossTrackError) {
|
||||||
|
super();
|
||||||
|
this.legDetails = legDetails;
|
||||||
|
this.windwardDistanceToOverallLeader = windwardDistanceToOverallLeader;
|
||||||
|
this.averageCrossTrackError = averageCrossTrackError;
|
||||||
|
}
|
||||||
|
public List<LegEntryDTO> getLegDetails() {
|
||||||
|
return legDetails;
|
||||||
|
}
|
||||||
|
public Distance getWindwardDistanceToOverallLeader() {
|
||||||
|
return windwardDistanceToOverallLeader;
|
||||||
|
}
|
||||||
|
public Distance getAverageCrossTrackError() {
|
||||||
|
return averageCrossTrackError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If <code>timePoint</code> is after the end of the race's tracking the query will be adjusted to obtain the values
|
||||||
|
* at the end of the {@link TrackedRace#getEndOfTracking() race's tracking time}. If the time point adjusted this
|
||||||
|
* way equals the end of the tracking time, the query results will be looked up in a cache first and if not found,
|
||||||
|
* they will be stored to the cache after calculating them. A cache invalidation {@link RaceChangeListener listener}
|
||||||
|
* will be registered with the race which will be triggered for any event received by the race.
|
||||||
|
* @param waitForLatestAnalyses
|
||||||
|
* if <code>false</code>, this method is allowed to read the maneuver analysis results from a cache that
|
||||||
|
* may not reflect all data already received; otherwise, the method will always block for the latest
|
||||||
|
* cache updates to have happened before returning.
|
||||||
|
*/
|
||||||
|
private RaceDetails getRaceDetails(TrackedRace trackedRace, Competitor competitor, TimePoint timePoint,
|
||||||
|
boolean waitForLatestAnalyses, Map<Leg, LinkedHashMap<Competitor, Integer>> legRanksCache) throws NoWindException, InterruptedException, ExecutionException {
|
||||||
|
RaceDetails raceDetails;
|
||||||
|
if (trackedRace.getEndOfTracking() != null && trackedRace.getEndOfTracking().compareTo(timePoint) < 0) {
|
||||||
|
raceDetails = getRaceDetailsForEndOfTrackingFromCacheOrCalculateAndCache(trackedRace, competitor, legRanksCache);
|
||||||
|
} else {
|
||||||
|
raceDetails = calculateRaceDetails(trackedRace, competitor, timePoint, waitForLatestAnalyses, legRanksCache);
|
||||||
|
}
|
||||||
|
return raceDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RaceDetails getRaceDetailsForEndOfTrackingFromCacheOrCalculateAndCache(final TrackedRace trackedRace,
|
||||||
|
final Competitor competitor, final Map<Leg, LinkedHashMap<Competitor, Integer>> legRanksCache)
|
||||||
|
throws NoWindException, InterruptedException, ExecutionException {
|
||||||
|
final Pair<TrackedRace, Competitor> key = new Pair<TrackedRace, Competitor>(trackedRace, competitor);
|
||||||
|
RunnableFuture<RaceDetails> raceDetails;
|
||||||
|
synchronized (raceDetailsAtEndOfTrackingCache) {
|
||||||
|
raceDetails = raceDetailsAtEndOfTrackingCache.get(key);
|
||||||
|
if (raceDetails == null) {
|
||||||
|
raceDetails = new FutureTask<RaceDetails>(new Callable<RaceDetails>() {
|
||||||
|
@Override
|
||||||
|
public RaceDetails call() throws Exception {
|
||||||
|
TimePoint end = trackedRace.getEndOfRace();
|
||||||
|
if (end == null) {
|
||||||
|
end = trackedRace.getEndOfTracking();
|
||||||
|
}
|
||||||
|
return calculateRaceDetails(trackedRace, competitor, end,
|
||||||
|
// TODO see bug 1358: for now, use waitForLatest==false until we've switched to optimistic locking for the course read lock
|
||||||
|
/* TODO old comment when it was still true: "because this is done only once after end of tracking" */
|
||||||
|
/* waitForLatestAnalyses (maneuver and cross track error) */ false,
|
||||||
|
legRanksCache);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
raceDetailsExecutor.execute(raceDetails);
|
||||||
|
raceDetailsAtEndOfTrackingCache.put(key, raceDetails);
|
||||||
|
final CacheInvalidationListener cacheInvalidationListener = new CacheInvalidationListener(trackedRace, competitor);
|
||||||
|
trackedRace.addListener(cacheInvalidationListener);
|
||||||
|
cacheInvalidationListeners.add(cacheInvalidationListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return raceDetails.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private RaceDetails calculateRaceDetails(TrackedRace trackedRace, Competitor competitor, TimePoint timePoint,
|
||||||
|
boolean waitForLatestAnalyses, Map<Leg, LinkedHashMap<Competitor, Integer>> legRanksCache) throws NoWindException {
|
||||||
|
List<LegEntryDTO> legDetails;
|
||||||
|
legDetails = new ArrayList<LegEntryDTO>();
|
||||||
|
final Course course = trackedRace.getRace().getCourse();
|
||||||
|
course.lockForRead(); // hold back any course re-configurations while looping over the legs
|
||||||
|
try {
|
||||||
|
for (Leg leg : course.getLegs()) {
|
||||||
|
LegEntryDTO legEntry;
|
||||||
|
// We loop over a copy of the course's legs; during a course change, legs may become "stale," even with
|
||||||
|
// regard to the leg/trackedLeg structures inside the tracked race which is updated by the course change
|
||||||
|
// immediately. That's why we've acquired a read lock for the course above.
|
||||||
|
TrackedLegOfCompetitor trackedLeg = trackedRace.getTrackedLeg(competitor, leg);
|
||||||
|
if (trackedLeg != null && trackedLeg.hasStartedLeg(timePoint)) {
|
||||||
|
legEntry = createLegEntry(trackedLeg, timePoint, waitForLatestAnalyses, legRanksCache);
|
||||||
|
} else {
|
||||||
|
legEntry = null;
|
||||||
|
}
|
||||||
|
legDetails.add(legEntry);
|
||||||
|
}
|
||||||
|
final Distance windwardDistanceToOverallLeader = trackedRace == null ? null : trackedRace
|
||||||
|
.getWindwardDistanceToOverallLeader(competitor, timePoint);
|
||||||
|
final Distance averageCrossTrackError = trackedRace == null ? null : trackedRace.getAverageCrossTrackError(
|
||||||
|
competitor, timePoint, waitForLatestAnalyses);
|
||||||
|
return new RaceDetails(legDetails, windwardDistanceToOverallLeader, averageCrossTrackError);
|
||||||
|
} finally {
|
||||||
|
course.unlockAfterRead();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private LegEntryDTO createLegEntry(TrackedLegOfCompetitor trackedLeg, TimePoint timePoint,
|
||||||
|
boolean waitForLatestAnalyses, Map<Leg, LinkedHashMap<Competitor, Integer>> legRanksCache) throws NoWindException {
|
||||||
|
LegEntryDTO result;
|
||||||
|
if (trackedLeg == null) {
|
||||||
|
result = null;
|
||||||
|
} else {
|
||||||
|
result = new LegEntryDTO();
|
||||||
|
final Speed averageSpeedOverGround = trackedLeg.getAverageSpeedOverGround(timePoint);
|
||||||
|
result.averageSpeedOverGroundInKnots = averageSpeedOverGround == null ? null : averageSpeedOverGround.getKnots();
|
||||||
|
final Distance averageCrossTrackError = trackedLeg.getAverageCrossTrackError(timePoint, waitForLatestAnalyses);
|
||||||
|
result.averageCrossTrackErrorInMeters = averageCrossTrackError == null ? null : averageCrossTrackError.getMeters();
|
||||||
|
Double speedOverGroundInKnots;
|
||||||
|
if (trackedLeg.hasFinishedLeg(timePoint)) {
|
||||||
|
speedOverGroundInKnots = averageSpeedOverGround == null ? null : averageSpeedOverGround.getKnots();
|
||||||
|
} else {
|
||||||
|
final SpeedWithBearing speedOverGround = trackedLeg.getSpeedOverGround(timePoint);
|
||||||
|
speedOverGroundInKnots = speedOverGround == null ? null : speedOverGround.getKnots();
|
||||||
|
}
|
||||||
|
result.currentSpeedOverGroundInKnots = speedOverGroundInKnots == null ? null : speedOverGroundInKnots;
|
||||||
|
Distance distanceTraveled = trackedLeg.getDistanceTraveled(timePoint);
|
||||||
|
result.distanceTraveledInMeters = distanceTraveled == null ? null : distanceTraveled.getMeters();
|
||||||
|
result.estimatedTimeToNextWaypointInSeconds = trackedLeg.getEstimatedTimeToNextMarkInSeconds(timePoint);
|
||||||
|
result.timeInMilliseconds = trackedLeg.getTimeInMilliSeconds(timePoint);
|
||||||
|
result.finished = trackedLeg.hasFinishedLeg(timePoint);
|
||||||
|
result.gapToLeaderInSeconds = trackedLeg.getGapToLeaderInSeconds(timePoint,
|
||||||
|
legRanksCache.get(trackedLeg.getLeg()).entrySet().iterator().next().getKey());
|
||||||
|
if (result.gapToLeaderInSeconds != null) {
|
||||||
|
// FIXME problem: asking just after the beginning of the leg yields very different values from asking for the end of the previous leg.
|
||||||
|
// This is because for the previous leg it's decided based on the mark passings; for the next (current) leg it's decided based on
|
||||||
|
// windward distance and VMG
|
||||||
|
Double gapAtEndOfPreviousLegInSeconds = getGapAtEndOfPreviousLegInSeconds(trackedLeg);
|
||||||
|
if (gapAtEndOfPreviousLegInSeconds != null) {
|
||||||
|
result.gapChangeSinceLegStartInSeconds = result.gapToLeaderInSeconds - gapAtEndOfPreviousLegInSeconds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LinkedHashMap<Competitor, Integer> legRanks = legRanksCache.get(trackedLeg.getLeg());
|
||||||
|
if (legRanks != null) {
|
||||||
|
result.rank = legRanks.get(trackedLeg.getCompetitor());
|
||||||
|
} else {
|
||||||
|
result.rank = trackedLeg.getRank(timePoint);
|
||||||
|
}
|
||||||
|
result.started = trackedLeg.hasStartedLeg(timePoint);
|
||||||
|
Speed velocityMadeGood;
|
||||||
|
if (trackedLeg.hasFinishedLeg(timePoint)) {
|
||||||
|
velocityMadeGood = trackedLeg.getAverageVelocityMadeGood(timePoint);
|
||||||
|
} else {
|
||||||
|
velocityMadeGood = trackedLeg.getVelocityMadeGood(timePoint);
|
||||||
|
}
|
||||||
|
result.velocityMadeGoodInKnots = velocityMadeGood == null ? null : velocityMadeGood.getKnots();
|
||||||
|
Distance windwardDistanceToGo = trackedLeg.getWindwardDistanceToGo(timePoint);
|
||||||
|
result.windwardDistanceToGoInMeters = windwardDistanceToGo == null ? null : windwardDistanceToGo
|
||||||
|
.getMeters();
|
||||||
|
final TimePoint startOfRace = trackedLeg.getTrackedLeg().getTrackedRace().getStartOfRace();
|
||||||
|
if (startOfRace != null && trackedLeg.hasStartedLeg(timePoint)) {
|
||||||
|
// not using trackedLeg.getManeuvers(...) because it may not catch the mark passing maneuver starting this leg
|
||||||
|
// because that may have been detected as slightly before the mark passing time, hence associated with the previous leg
|
||||||
|
List<Maneuver> maneuvers = trackedLeg.getTrackedLeg().getTrackedRace()
|
||||||
|
.getManeuvers(trackedLeg.getCompetitor(), startOfRace, timePoint, waitForLatestAnalyses);
|
||||||
|
if (maneuvers != null) {
|
||||||
|
result.numberOfManeuvers = new HashMap<ManeuverType, Integer>();
|
||||||
|
result.numberOfManeuvers.put(ManeuverType.TACK, 0);
|
||||||
|
result.numberOfManeuvers.put(ManeuverType.JIBE, 0);
|
||||||
|
result.numberOfManeuvers.put(ManeuverType.PENALTY_CIRCLE, 0);
|
||||||
|
Map<ManeuverType, Double> totalManeuverLossInMeters = new HashMap<ManeuverType, Double>();
|
||||||
|
totalManeuverLossInMeters.put(ManeuverType.TACK, 0.0);
|
||||||
|
totalManeuverLossInMeters.put(ManeuverType.JIBE, 0.0);
|
||||||
|
totalManeuverLossInMeters.put(ManeuverType.PENALTY_CIRCLE, 0.0);
|
||||||
|
TimePoint startOfLeg = trackedLeg.getStartTime();
|
||||||
|
for (Maneuver maneuver : maneuvers) {
|
||||||
|
// don't count maneuvers that were in previous legs
|
||||||
|
switch (maneuver.getType()) {
|
||||||
|
case TACK:
|
||||||
|
case JIBE:
|
||||||
|
case PENALTY_CIRCLE:
|
||||||
|
if (!maneuver.getTimePoint().before(startOfLeg) && (!trackedLeg.hasFinishedLeg(timePoint) ||
|
||||||
|
maneuver.getTimePoint().before(trackedLeg.getFinishTime()))) {
|
||||||
|
if (maneuver.getManeuverLoss() != null) {
|
||||||
|
result.numberOfManeuvers.put(maneuver.getType(),
|
||||||
|
result.numberOfManeuvers.get(maneuver.getType()) + 1);
|
||||||
|
totalManeuverLossInMeters.put(maneuver.getType(),
|
||||||
|
totalManeuverLossInMeters.get(maneuver.getType())
|
||||||
|
+ maneuver.getManeuverLoss().getMeters());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MARK_PASSING:
|
||||||
|
// analyze all mark passings, not only those after this leg's start, to catch the mark passing
|
||||||
|
// maneuver starting this leg, even if its time point is slightly before the mark passing starting this leg
|
||||||
|
MarkPassingManeuver mpm = (MarkPassingManeuver) maneuver;
|
||||||
|
if (mpm.getWaypointPassed() == trackedLeg.getLeg().getFrom()) {
|
||||||
|
result.sideToWhichMarkAtLegStartWasRounded = mpm.getSide();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Do nothing here.
|
||||||
|
* Throwing an exception destroys the toggling (and maybe other behaviour) of the leaderboard.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.averageManeuverLossInMeters = new HashMap<ManeuverType, Double>();
|
||||||
|
for (ManeuverType maneuverType : new ManeuverType[] { ManeuverType.TACK, ManeuverType.JIBE,
|
||||||
|
ManeuverType.PENALTY_CIRCLE }) {
|
||||||
|
if (result.numberOfManeuvers.get(maneuverType) != 0) {
|
||||||
|
result.averageManeuverLossInMeters.put(
|
||||||
|
maneuverType,
|
||||||
|
totalManeuverLossInMeters.get(maneuverType)
|
||||||
|
/ result.numberOfManeuvers.get(maneuverType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Double getGapAtEndOfPreviousLegInSeconds(TrackedLegOfCompetitor trackedLeg) throws NoWindException {
|
||||||
|
final Double result;
|
||||||
|
final Course course = trackedLeg.getTrackedLeg().getTrackedRace().getRace().getCourse();
|
||||||
|
course.lockForRead();
|
||||||
|
try {
|
||||||
|
int indexOfStartWaypoint = course.getIndexOfWaypoint(trackedLeg.getLeg().getFrom());
|
||||||
|
if (indexOfStartWaypoint == 0) {
|
||||||
|
// trackedLeg was the first leg; gap is determined by gap of start line passing time points
|
||||||
|
Iterable<MarkPassing> markPassingsForLegStart = trackedLeg.getTrackedLeg().getTrackedRace().getMarkPassingsInOrder(trackedLeg.getLeg().getFrom());
|
||||||
|
trackedLeg.getTrackedLeg().getTrackedRace().lockForRead(markPassingsForLegStart);
|
||||||
|
try {
|
||||||
|
final Iterator<MarkPassing> markPassingsIter = markPassingsForLegStart.iterator();
|
||||||
|
if (markPassingsIter.hasNext()) {
|
||||||
|
TimePoint firstStart = markPassingsIter.next().getTimePoint();
|
||||||
|
final MarkPassing markPassingForFrom = trackedLeg.getTrackedLeg().getTrackedRace()
|
||||||
|
.getMarkPassing(trackedLeg.getCompetitor(), trackedLeg.getLeg().getFrom());
|
||||||
|
if (markPassingForFrom != null) {
|
||||||
|
TimePoint competitorStart = markPassingForFrom.getTimePoint();
|
||||||
|
result = (double) (competitorStart.asMillis() - firstStart.asMillis()) / 1000.;
|
||||||
|
} else {
|
||||||
|
result = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = null;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
trackedLeg.getTrackedLeg().getTrackedRace().unlockAfterRead(markPassingsForLegStart);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TrackedLeg previousTrackedLeg = trackedLeg.getTrackedLeg().getTrackedRace().getTrackedLeg(course.getLegs().get(indexOfStartWaypoint-1));
|
||||||
|
TrackedLegOfCompetitor previousTrackedLegOfCompetitor = previousTrackedLeg.getTrackedLeg(trackedLeg.getCompetitor());
|
||||||
|
result = previousTrackedLegOfCompetitor.getGapToLeaderInSeconds(previousTrackedLegOfCompetitor.getFinishTime());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} finally {
|
||||||
|
course.unlockAfterRead();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private LeaderboardDTO getLiveLeaderboard(Collection<String> namesOfRaceColumnsForWhichToLoadLegDetails,
|
||||||
|
TrackedRegattaRegistry trackedRegattaRegistry, DomainFactory baseDomainFactory) throws NoWindException {
|
||||||
|
LiveLeaderboardUpdater liveLeaderboardUpdater = getLiveLeaderboardUpdater(trackedRegattaRegistry,
|
||||||
|
baseDomainFactory);
|
||||||
|
return liveLeaderboardUpdater.getLiveLeaderboard(namesOfRaceColumnsForWhichToLoadLegDetails);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LiveLeaderboardUpdater getLiveLeaderboardUpdater(TrackedRegattaRegistry trackedRegattaRegistry,
|
||||||
|
DomainFactory baseDomainFactory) {
|
||||||
|
LiveLeaderboardUpdater result = this.liveLeaderboardUpdater;
|
||||||
|
if (result == null) {
|
||||||
|
synchronized (this) {
|
||||||
|
result = this.liveLeaderboardUpdater;
|
||||||
|
if (result == null) {
|
||||||
|
this.liveLeaderboardUpdater = new LiveLeaderboardUpdater(this, trackedRegattaRegistry, baseDomainFactory);
|
||||||
|
result = this.liveLeaderboardUpdater;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LeaderboardDTOCache getLeaderboardDTOCache() {
|
||||||
|
LeaderboardDTOCache result = this.leaderboardDTOCache;
|
||||||
|
if (result == null) {
|
||||||
|
synchronized (this) {
|
||||||
|
result = this.leaderboardDTOCache;
|
||||||
|
if (result == null) {
|
||||||
|
// The leaderboard cache is invalidated upon all competitor and mark position changes; some analyzes
|
||||||
|
// are pretty expensive, such as the maneuver re-calculation. Waiting for the latest analysis after only a
|
||||||
|
// single fix was updated is too expensive if users use the replay feature while a race is still running.
|
||||||
|
// Therefore, using waitForLatestAnalyses==false seems appropriate here.
|
||||||
|
this.leaderboardDTOCache = new LeaderboardDTOCache(/* waitForLatestAnalyses */false, this);
|
||||||
|
result = this.leaderboardDTOCache;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LeaderboardDTO getLeaderboardDTO(TimePoint timePoint, Collection<String> namesOfRaceColumnsForWhichToLoadLegDetails,
|
||||||
|
TrackedRegattaRegistry trackedRegattaRegistry, DomainFactory baseDomainFactory) throws NoWindException, InterruptedException, ExecutionException {
|
||||||
|
LeaderboardDTO result = null;
|
||||||
|
if (timePoint == null) {
|
||||||
|
// date==null means live mode; however, if we're after the end of all races and after all score
|
||||||
|
// corrections, don't use the live leaderboard updater which would keep re-calculating over and over again, but map
|
||||||
|
// this to a usual non-live call which uses the regular LeaderboardDTOCache which is invalidated properly
|
||||||
|
// when the tracked race associations or score corrections or tracked race contents changes:
|
||||||
|
final TimePoint nowMinusDelay = this.getNowMinusDelay();
|
||||||
|
final TimePoint timePointOfLatestModification = this.getTimePointOfLatestModification();
|
||||||
|
if (timePointOfLatestModification != null && !nowMinusDelay.before(timePointOfLatestModification)) {
|
||||||
|
// if there hasn't been any modification to the leaderboard since nowMinusDelay, use non-live mode
|
||||||
|
// and pull the result from the regular leaderboard cache:
|
||||||
|
timePoint = timePointOfLatestModification;
|
||||||
|
} else {
|
||||||
|
// don't use the regular leaderboard cache; the race still seems to be on; use the live leaderboard updater instead:
|
||||||
|
timePoint = null;
|
||||||
|
result = this.getLiveLeaderboard(namesOfRaceColumnsForWhichToLoadLegDetails, trackedRegattaRegistry, baseDomainFactory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (timePoint != null) {
|
||||||
|
// in replay we'd like up-to-date results; they are still cached
|
||||||
|
// which is OK because the cache is invalidated whenever any of the tracked races attached to the
|
||||||
|
// leaderboard changes.
|
||||||
|
result = getLeaderboardDTOCache().getLeaderboardByName(timePoint, namesOfRaceColumnsForWhichToLoadLegDetails,
|
||||||
|
baseDomainFactory, trackedRegattaRegistry);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -41,4 +41,7 @@ public interface TrackedRegattaRegistry {
|
|||||||
* @param raceID the ID as obtained from {@link RaceDefinition#getId()}
|
* @param raceID the ID as obtained from {@link RaceDefinition#getId()}
|
||||||
*/
|
*/
|
||||||
Regatta getRememberedRegattaForRace(Serializable raceID);
|
Regatta getRememberedRegattaForRace(Serializable raceID);
|
||||||
|
|
||||||
|
boolean isRaceBeingTracked(RaceDefinition r);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
bin/
|
||||||
@@ -169,6 +169,13 @@ Computes leaderboard information for sailing races and offers RESTful APIs to al
|
|||||||
version="0.0.0"
|
version="0.0.0"
|
||||||
unpack="false"/>
|
unpack="false"/>
|
||||||
|
|
||||||
|
<plugin
|
||||||
|
id="com.sap.sailing.simulator"
|
||||||
|
download-size="0"
|
||||||
|
install-size="0"
|
||||||
|
version="0.0.0"
|
||||||
|
unpack="false"/>
|
||||||
|
|
||||||
<plugin
|
<plugin
|
||||||
id="com.google.gwt.osgi"
|
id="com.google.gwt.osgi"
|
||||||
download-size="0"
|
download-size="0"
|
||||||
|
|||||||
+3
-3
@@ -11,13 +11,13 @@ import com.google.gwt.user.cellview.client.Column;
|
|||||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||||
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
||||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||||
|
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.LeaderboardRowDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
|
||||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||||
import com.sap.sailing.domain.tractracadapter.TracTracConnectionConstants;
|
import com.sap.sailing.domain.tractracadapter.TracTracConnectionConstants;
|
||||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||||
import com.sap.sailing.gwt.ui.leaderboard.ExpandableSortableColumn;
|
import com.sap.sailing.gwt.ui.leaderboard.ExpandableSortableColumn;
|
||||||
import com.sap.sailing.gwt.ui.shared.LeaderboardDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.LeaderboardRowDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceColumnDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
|
import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.TracTracRaceRecordDTO;
|
import com.sap.sailing.gwt.ui.shared.TracTracRaceRecordDTO;
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -1,5 +1,8 @@
|
|||||||
package com.sap.sailing.gwt.ui.test;
|
package com.sap.sailing.gwt.ui.test;
|
||||||
|
|
||||||
|
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.LeaderboardRowDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
|
||||||
import com.sap.sailing.gwt.ui.client.CompetitorSelectionModel;
|
import com.sap.sailing.gwt.ui.client.CompetitorSelectionModel;
|
||||||
import com.sap.sailing.gwt.ui.client.ErrorReporter;
|
import com.sap.sailing.gwt.ui.client.ErrorReporter;
|
||||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||||
@@ -8,9 +11,6 @@ import com.sap.sailing.gwt.ui.leaderboard.LeaderboardPanel;
|
|||||||
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardSettingsFactory;
|
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardSettingsFactory;
|
||||||
import com.sap.sailing.gwt.ui.leaderboard.SortableColumn;
|
import com.sap.sailing.gwt.ui.leaderboard.SortableColumn;
|
||||||
import com.sap.sailing.gwt.ui.leaderboard.SortedCellTable;
|
import com.sap.sailing.gwt.ui.leaderboard.SortedCellTable;
|
||||||
import com.sap.sailing.gwt.ui.shared.LeaderboardDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.LeaderboardRowDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceColumnDTO;
|
|
||||||
|
|
||||||
public class LeaderboardPanelMock extends LeaderboardPanel {
|
public class LeaderboardPanelMock extends LeaderboardPanel {
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package com.sap.sailing.gwt.ui.test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.sap.sailing.gwt.ui.simulator.util.LineSegment;
|
||||||
|
import com.sap.sailing.gwt.ui.simulator.util.LineSegment.Point;
|
||||||
|
|
||||||
|
public class LineSegmentTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test1() {
|
||||||
|
LineSegment s1 = new LineSegment(0,0,10,10);
|
||||||
|
LineSegment s2 = new LineSegment(10,0,0,10);
|
||||||
|
|
||||||
|
Point intersectionPoint = s1.intersect(s2);
|
||||||
|
if (intersectionPoint != null) {
|
||||||
|
System.out.println("The lines interect at " + intersectionPoint);
|
||||||
|
}
|
||||||
|
assertEquals("Lines do intersect", 5.0, intersectionPoint.getX(),1e-6);
|
||||||
|
assertEquals("Lines do intersect", 5.0, intersectionPoint.getY(),1e-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test2() {
|
||||||
|
LineSegment s1 = new LineSegment(0,0,0,10);
|
||||||
|
LineSegment s2 = new LineSegment(10,0,10,10);
|
||||||
|
|
||||||
|
Point intersectionPoint = s1.intersect(s2);
|
||||||
|
|
||||||
|
assertEquals("Lines do not intersect", null, intersectionPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test3() {
|
||||||
|
|
||||||
|
LineSegment s1 = new LineSegment(53.987292187570304, 10.944955638570837,53.991202136256135, 10.951666848382969);
|
||||||
|
|
||||||
|
LineSegment b1 = new LineSegment(53.977189863832564, 10.886260271572164,53.96560719314814, 10.925463437534281);
|
||||||
|
LineSegment b2 = new LineSegment(53.96560719314814, 10.925463437534281,53.991220287799436, 10.947350263095805);
|
||||||
|
LineSegment b3 = new LineSegment(53.991220287799436, 10.947350263095805,54.00280295848386, 10.90814709713369);
|
||||||
|
LineSegment b4 = new LineSegment(54.00280295848386, 10.90814709713369,53.977189863832564, 10.886260271572164);
|
||||||
|
|
||||||
|
s1.intersect(b1);
|
||||||
|
s1.intersect(b2);
|
||||||
|
s1.intersect(b3);
|
||||||
|
s1.intersect(b4);
|
||||||
|
Point intersectionPoint = s1.intersect(b1);
|
||||||
|
assertEquals("Lines s1 and b1 do not intersect", null, intersectionPoint);
|
||||||
|
intersectionPoint = s1.intersect(b2);
|
||||||
|
assertEquals("Lines s and b2 do not intersect", null, intersectionPoint);
|
||||||
|
intersectionPoint = s1.intersect(b3);
|
||||||
|
assertEquals("Lines s3 and b3 do not intersect", null, intersectionPoint);
|
||||||
|
intersectionPoint = s1.intersect(b4);
|
||||||
|
assertEquals("Lines s4 and b4 do not intersect", null, intersectionPoint);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+3
-3
@@ -14,10 +14,10 @@ import org.junit.Before;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||||
|
import com.sap.sailing.domain.common.dto.FleetDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
|
||||||
import com.sap.sailing.gwt.ui.server.SailingServiceImpl;
|
import com.sap.sailing.gwt.ui.server.SailingServiceImpl;
|
||||||
import com.sap.sailing.gwt.ui.shared.FleetDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.LeaderboardDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceColumnDTO;
|
|
||||||
|
|
||||||
public class TestColumnSwapping {
|
public class TestColumnSwapping {
|
||||||
|
|
||||||
|
|||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
package com.sap.sailing.gwt.ui.test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import com.sap.sailing.gwt.ui.simulator.util.*;
|
||||||
|
|
||||||
|
public class WindGridColorPaletteTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
int min = 10;
|
||||||
|
int max = 100;
|
||||||
|
WindGridColorPalette cp = new WindGridColorPalette(min,max);
|
||||||
|
|
||||||
|
//assertEquals("Lightest color", "#FFFFFF", cp.getColor(min));
|
||||||
|
//assertEquals("Darkest color", "#0000FF", cp.getColor(max));
|
||||||
|
|
||||||
|
//assertEquals("In between color", "#7F7FFF", cp.getColor((max+min)/2));
|
||||||
|
|
||||||
|
assertEquals("Lightest color", "#FFFFFF", cp.getColor(min));
|
||||||
|
assertEquals("Darkest color", "#4B7FBB", cp.getColor(max));
|
||||||
|
|
||||||
|
assertEquals("In between color", "#A5BFDD", cp.getColor((max+min)/2));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,42 +1,43 @@
|
|||||||
Manifest-Version: 1.0
|
Manifest-Version: 1.0
|
||||||
Bundle-ManifestVersion: 2
|
Bundle-ManifestVersion: 2
|
||||||
Bundle-Name: Sailing App GWT UI
|
Bundle-Name: Sailing App GWT UI
|
||||||
Bundle-SymbolicName: com.sap.sailing.gwt.ui
|
Bundle-SymbolicName: com.sap.sailing.gwt.ui
|
||||||
Bundle-Version: 1.0.0.qualifier
|
Bundle-Version: 1.0.0.qualifier
|
||||||
Bundle-Vendor: SAP
|
Bundle-Vendor: SAP
|
||||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
|
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
|
||||||
Require-Bundle: com.sap.sailing.domain,
|
Require-Bundle: com.sap.sailing.domain,
|
||||||
com.sap.sailing.domain.shared.android;bundle-version="1.0.0",
|
com.sap.sailing.domain.shared.android;bundle-version="1.0.0",
|
||||||
com.sap.sailing.server.gateway,
|
com.sap.sailing.server.gateway,
|
||||||
com.sap.sailing.server,
|
com.sap.sailing.server,
|
||||||
com.sap.sailing.domain.tractracadapter,
|
com.sap.sailing.domain.tractracadapter,
|
||||||
com.sap.sailing.mongodb,
|
com.sap.sailing.mongodb,
|
||||||
com.mongodb.driver;bundle-version="2.6.2",
|
com.mongodb.driver;bundle-version="2.6.2",
|
||||||
com.sap.sailing.domain.swisstimingadapter,
|
com.sap.sailing.domain.swisstimingadapter,
|
||||||
com.sap.sailing.domain.persistence,
|
com.sap.sailing.domain.persistence,
|
||||||
com.sap.sailing.domain.swisstimingadapter.persistence,
|
com.sap.sailing.domain.swisstimingadapter.persistence,
|
||||||
com.sap.sailing.domain.tractracadapter.persistence,
|
com.sap.sailing.domain.tractracadapter.persistence,
|
||||||
com.google.gwt.osgi;bundle-version="2.4.0",
|
com.google.gwt.osgi;bundle-version="2.4.0",
|
||||||
com.sap.sailing.domain.common,
|
com.sap.sailing.domain.common,
|
||||||
com.sap.sailing.resultimport,
|
com.sap.sailing.resultimport,
|
||||||
org.moxieapps.gwt.highcharts;bundle-version="1.5.0",
|
org.moxieapps.gwt.highcharts;bundle-version="1.5.0",
|
||||||
com.sap.sailing.geocoding,
|
com.sap.sailing.geocoding,
|
||||||
com.sap.sailing.server.replication,
|
com.sap.sailing.server.replication,
|
||||||
com.googlecode.java-diff-utils;bundle-version="1.3.0",
|
com.googlecode.java-diff-utils;bundle-version="1.3.0",
|
||||||
com.sap.sailing.freg.resultimport,
|
com.sap.sailing.freg.resultimport,
|
||||||
com.sap.sailing.domain.swisstimingreplayadapter
|
com.sap.sailing.domain.swisstimingreplayadapter,
|
||||||
Bundle-Activator: com.sap.sailing.gwt.ui.server.Activator
|
com.sap.sailing.simulator;bundle-version="1.0.0"
|
||||||
Bundle-ActivationPolicy: lazy
|
Bundle-Activator: com.sap.sailing.gwt.ui.server.Activator
|
||||||
Export-Package: com.sap.sailing.gwt.ui.client.shared.media
|
Bundle-ActivationPolicy: lazy
|
||||||
Import-Package: javax.jms;version="1.1.0",
|
Export-Package: com.sap.sailing.gwt.ui.client.shared.media
|
||||||
javax.servlet;version="2.5.0",
|
Import-Package: javax.jms;version="1.1.0",
|
||||||
javax.servlet.http;version="2.5.0",
|
javax.servlet;version="2.5.0",
|
||||||
org.json.simple,
|
javax.servlet.http;version="2.5.0",
|
||||||
org.json.simple.parser,
|
org.json.simple,
|
||||||
org.osgi.framework,
|
org.json.simple.parser,
|
||||||
org.osgi.util.tracker
|
org.osgi.framework,
|
||||||
Web-ContextPath: /gwt
|
org.osgi.util.tracker
|
||||||
Bundle-ClassPath: WEB-INF/classes/,
|
Web-ContextPath: /gwt
|
||||||
WEB-INF/lib/gwt-maps.jar,
|
Bundle-ClassPath: WEB-INF/classes/,
|
||||||
WEB-INF/lib/gwt-servlet.jar
|
WEB-INF/lib/gwt-maps.jar,
|
||||||
TrackLifecycle: true
|
WEB-INF/lib/gwt-servlet.jar
|
||||||
|
TrackLifecycle: true
|
||||||
|
|||||||
@@ -1,53 +1,54 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<launchConfiguration type="com.google.gdt.eclipse.suite.webapp">
|
<launchConfiguration type="com.google.gdt.eclipse.suite.webapp">
|
||||||
<booleanAttribute key="com.google.gdt.eclipse.core.RUN_SERVER" value="false"/>
|
<booleanAttribute key="com.google.gdt.eclipse.core.RUN_SERVER" value="false"/>
|
||||||
<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/>
|
<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/>
|
||||||
<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/>
|
<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/>
|
||||||
<listAttribute key="com.google.gwt.eclipse.core.ENTRY_POINT_MODULES">
|
<listAttribute key="com.google.gwt.eclipse.core.ENTRY_POINT_MODULES">
|
||||||
<listEntry value="com.sap.sailing.gwt.ui.RegattaOverview"/>
|
<listEntry value="com.sap.sailing.gwt.ui.RegattaOverview"/>
|
||||||
</listAttribute>
|
<listEntry value="com.sap.sailing.gwt.ui.Simulator"/>
|
||||||
<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/gwt/AdminConsole.html"/>
|
</listAttribute>
|
||||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/gwt/AdminConsole.html"/>
|
||||||
<listEntry value="/com.sap.sailing.gwt.ui"/>
|
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
||||||
</listAttribute>
|
<listEntry value="/com.sap.sailing.gwt.ui"/>
|
||||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
</listAttribute>
|
||||||
<listEntry value="4"/>
|
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||||
</listAttribute>
|
<listEntry value="4"/>
|
||||||
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
</listAttribute>
|
||||||
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
|
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
||||||
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
|
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
|
||||||
</listAttribute>
|
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
|
||||||
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
|
</listAttribute>
|
||||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6" javaProject="com.sap.sailing.gwt.ui" path="1" type="4"/> "/>
|
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
|
||||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.gwt.ui/src/main/resources" path="3" type="2"/> "/>
|
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6" javaProject="com.sap.sailing.gwt.ui" path="1" type="4"/> "/>
|
||||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.gwt.ui/src/main/java" path="3" type="2"/> "/>
|
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.gwt.ui/src/main/resources" path="3" type="2"/> "/>
|
||||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain/src" path="3" type="2"/> "/>
|
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.gwt.ui/src/main/java" path="3" type="2"/> "/>
|
||||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.googlecode.java-diff-utils/src" path="3" type="2"/> "/>
|
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain/src" path="3" type="2"/> "/>
|
||||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.common/src" path="3" type="2"/> "/>
|
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.googlecode.java-diff-utils/src" path="3" type="2"/> "/>
|
||||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/org.json.simple/src" path="3" type="2"/> "/>
|
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.common/src" path="3" type="2"/> "/>
|
||||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.server/src" path="3" type="2"/> "/>
|
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/org.json.simple/src" path="3" type="2"/> "/>
|
||||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.tractracadapter/src" path="3" type="2"/> "/>
|
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.server/src" path="3" type="2"/> "/>
|
||||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.tractrac.clientmodule/src" path="3" type="2"/> "/>
|
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.tractracadapter/src" path="3" type="2"/> "/>
|
||||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.expeditionconnector/src" path="3" type="2"/> "/>
|
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.tractrac.clientmodule/src" path="3" type="2"/> "/>
|
||||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.declination/src" path="3" type="2"/> "/>
|
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.expeditionconnector/src" path="3" type="2"/> "/>
|
||||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.declination/resources" path="3" type="2"/> "/>
|
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.declination/src" path="3" type="2"/> "/>
|
||||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.udpconnector/src" path="3" type="2"/> "/>
|
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.declination/resources" path="3" type="2"/> "/>
|
||||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.mongodb/src" path="3" type="2"/> "/>
|
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.udpconnector/src" path="3" type="2"/> "/>
|
||||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.swisstimingadapter/src" path="3" type="2"/> "/>
|
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.mongodb/src" path="3" type="2"/> "/>
|
||||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.persistence/src" path="3" type="2"/> "/>
|
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.swisstimingadapter/src" path="3" type="2"/> "/>
|
||||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.swisstimingadapter.persistence/src" path="3" type="2"/> "/>
|
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.persistence/src" path="3" type="2"/> "/>
|
||||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.operationaltransformation/src" path="3" type="2"/> "/>
|
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.swisstimingadapter.persistence/src" path="3" type="2"/> "/>
|
||||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.tractracadapter.persistence/src" path="3" type="2"/> "/>
|
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.operationaltransformation/src" path="3" type="2"/> "/>
|
||||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/org.moxieapps.gwt.highcharts/src" path="3" type="2"/> "/>
|
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.tractracadapter.persistence/src" path="3" type="2"/> "/>
|
||||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.geocoding/src" path="3" type="2"/> "/>
|
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/org.moxieapps.gwt.highcharts/src" path="3" type="2"/> "/>
|
||||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.server.replication/src" path="3" type="2"/> "/>
|
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.geocoding/src" path="3" type="2"/> "/>
|
||||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.google.gwt.osgi/lib/gwt-user.jar" path="3" type="2"/> "/>
|
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.server.replication/src" path="3" type="2"/> "/>
|
||||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="com.sap.sailing.gwt.ui"/> </runtimeClasspathEntry> "/>
|
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.google.gwt.osgi/lib/gwt-user.jar" path="3" type="2"/> "/>
|
||||||
</listAttribute>
|
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="com.sap.sailing.gwt.ui"/> </runtimeClasspathEntry> "/>
|
||||||
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.google.gwt.eclipse.core.moduleClasspathProvider"/>
|
</listAttribute>
|
||||||
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
|
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.google.gwt.eclipse.core.moduleClasspathProvider"/>
|
||||||
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
|
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
|
||||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-war "${project_loc:com.sap.sailing.gwt.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9997 -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/UserManagement.html com.sap.sailing.gwt.ui.UserManagement -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/TvView.html com.sap.sailing.gwt.ui.TvView -startupUrl /gwt/PolarSheets.html com.sap.sailing.gwt.ui.PolarSheets -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.ui.RegattaOverview"/>
|
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
|
||||||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/>
|
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-war "${project_loc:com.sap.sailing.gwt.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9997 -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/UserManagement.html com.sap.sailing.gwt.ui.UserManagement -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/TvView.html com.sap.sailing.gwt.ui.TvView -startupUrl /gwt/PolarSheets.html com.sap.sailing.gwt.ui.PolarSheets -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.ui.RegattaOverview -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.RegattaOverview"/>
|
||||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx2048m -XX:MaxPermSize=512m"/>
|
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/>
|
||||||
</launchConfiguration>
|
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx2048m -XX:MaxPermSize=512m"/>
|
||||||
|
</launchConfiguration>
|
||||||
|
|||||||
@@ -0,0 +1,385 @@
|
|||||||
|
@import url(fontface.css);
|
||||||
|
//@import url(CommonControls.css);
|
||||||
|
|
||||||
|
/** Add css rules here for your application. */
|
||||||
|
/*
|
||||||
|
body #calendar:after
|
||||||
|
content: " ";
|
||||||
|
display: block;
|
||||||
|
height: 0;
|
||||||
|
clear: both;
|
||||||
|
visibility: hidden;
|
||||||
|
*/
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.titleLabelWrapper {
|
||||||
|
position: relative;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.titleLabel {
|
||||||
|
text-align: center;
|
||||||
|
font-family: 'UbuntuMedium', Arial, Verdana, sans-serif;
|
||||||
|
font-size: 18px;
|
||||||
|
color: #fff;
|
||||||
|
margin: 23px 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: #ebebeb;
|
||||||
|
font-family: 'UbuntuRegular', Arial, Verdana, sans-serif;
|
||||||
|
line-height: 1;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 400;
|
||||||
|
padding: 80px 0 160px 0;
|
||||||
|
margin: 0;
|
||||||
|
color: #7c7c7c;
|
||||||
|
}
|
||||||
|
|
||||||
|
table td,select,button {
|
||||||
|
font-family: 'UbuntuLight', Arial, Verdana, sans-serif;
|
||||||
|
line-height: 1;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contentOuterPanel {
|
||||||
|
background: #dddcdc;
|
||||||
|
margin: 0 12px 0 12px;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Example rules used by the template application (remove for your app) */
|
||||||
|
h1 {
|
||||||
|
font-size: 2em;
|
||||||
|
font-family: 'UbuntuBold', Arial, Verdana, sans-serif;
|
||||||
|
color: #777777;
|
||||||
|
margin: 40px 0px 70px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: separate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*.RaceBoardHeaderPanel {
|
||||||
|
margin: 0 12px 14px 12px;
|
||||||
|
}*/
|
||||||
|
.sapLogo {
|
||||||
|
float: left;
|
||||||
|
margin: 13px 0 0 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pioLogo {
|
||||||
|
float: right;
|
||||||
|
margin: 11px 20px 0 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sailingAnalyticsLabelPanel {
|
||||||
|
margin: 10px 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sailingAnalyticsLabel {
|
||||||
|
float: left;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 15px 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timePanelSettings {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*.leaderboardLabel {
|
||||||
|
border-bottom: 2px solid #007dc0;
|
||||||
|
padding: 0 0 6px 0;
|
||||||
|
font-family: 'UbuntuBold', Arial, Verdana, sans-serif;
|
||||||
|
}*/
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.race-name {
|
||||||
|
line-height: 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.magnifier {
|
||||||
|
display: block;
|
||||||
|
margin: 3px auto 0 auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumbPanel {
|
||||||
|
height: 30px;
|
||||||
|
margin: 0 12px 13px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mainPanel {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*.raceBoardNavigation {
|
||||||
|
float: right;
|
||||||
|
margin: 26px 0 0 0;
|
||||||
|
font-family: 'UbuntuLight', Arial, Verdana, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.raceBoardNavigation-navigationitem {
|
||||||
|
color: #dddcdc;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: 500;
|
||||||
|
margin: 0 12px 0 0;
|
||||||
|
padding: 0 0 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.raceBoardNavigation-navigationitem:hover {
|
||||||
|
border-bottom: 4px solid #f0ab00;
|
||||||
|
color: #dddcdc;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.raceBoardNavigation-navigationitem:active {
|
||||||
|
border-bottom: 4px solid #f0ab00;
|
||||||
|
color: #dddcdc;
|
||||||
|
text-decoration: none;
|
||||||
|
}*/
|
||||||
|
.abstractChartPanel-importantMessageOfChart {
|
||||||
|
font-family: 'UbuntuBold', Arial, Verdana, sans-serif;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*.breadcrumbPanel-NextArrow {
|
||||||
|
display: none;
|
||||||
|
}*/
|
||||||
|
.replayPanel {
|
||||||
|
position: relative;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.innerHeadline {
|
||||||
|
font-family: UbuntuMedium, Arial, Verdana, sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #7c7c7c;
|
||||||
|
margin: 15px 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.sectorHeadline {
|
||||||
|
font-family: UbuntuLight, Arial, Verdana, sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controlPanelInnerWrapper {
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.windPanel {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.choosePattern {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 0 15px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.choosePattern td:last-child {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.optionsPanel {
|
||||||
|
background: url(images/simulator/panel_bg.png) 0 0 repeat-x;
|
||||||
|
border-bottom: 4px solid #7c7b7c;
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mapOptions {
|
||||||
|
background: url(images/simulator/panel_bg.png) 0 0 repeat-x;
|
||||||
|
border-bottom: 4px solid #7c7b7c;
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timePanelButton {
|
||||||
|
float: left;
|
||||||
|
margin: 0 0 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.playPauseButton {
|
||||||
|
padding: 0;
|
||||||
|
width: 28px;
|
||||||
|
height: 24px;
|
||||||
|
background: url(images/timeslider-play-active-icon.png) 0 0 no-repeat;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.playPauseButton:hover{
|
||||||
|
background: url(images/playbutton-hover.png) 0 0 no-repeat !important;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.playPauseButtonPause {
|
||||||
|
background: url(images/timeslider-pause-icon.png) 0 0 no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.playPauseButtonPause:hover {
|
||||||
|
background: url(images/playbuttonPause-hover.png) 0 0 no-repeat !important;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.backToLivePlayButton {
|
||||||
|
float: left;
|
||||||
|
padding: 3px 10px 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.sliderWrapper {
|
||||||
|
float: left;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 0 7px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sliderLabel {
|
||||||
|
width: 200px;
|
||||||
|
padding: 12px 0 14px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* styles for the masterPanel */
|
||||||
|
#masterPanelLeft .gwt-SliderBar-shell {
|
||||||
|
background: url(images/simulator/slider_bg.png) 0 0 repeat-x;
|
||||||
|
border-radius: 3px;
|
||||||
|
-moz-border-radius: 3px;
|
||||||
|
-webkit-border-radius: 3px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#masterPanelLeft .gwt-SliderBar-shell .gwt-SliderBar-line {
|
||||||
|
border: 1px solid #919191;
|
||||||
|
background-color: #818181;
|
||||||
|
height: 4px;
|
||||||
|
width: 90%;
|
||||||
|
top: 23px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#masterPanelLeft .gwt-SliderBar-shell .gwt-SliderBar-line-disabled {
|
||||||
|
border: 1px solid gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*#masterPanelLeft .gwt-SliderBar-shell .gwt-SliderBar-knob {
|
||||||
|
top: 14px;
|
||||||
|
width: 11px;
|
||||||
|
height: 21px;
|
||||||
|
z-index: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
#masterPanelLeft .gwt-SliderBar-shell .gwt-SliderBar-tick {
|
||||||
|
top: 18px;
|
||||||
|
width: 1px;
|
||||||
|
height: 6pt;
|
||||||
|
background: #919191;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#masterPanelLeft .gwt-SliderBar-shell .gwt-SliderBar-mark {
|
||||||
|
top: 21pt;
|
||||||
|
width: 6px;
|
||||||
|
height: 6pt;
|
||||||
|
background: #f0ab00;
|
||||||
|
overflow: hidden;
|
||||||
|
border-left: 4px solid #fff;
|
||||||
|
border-right: 4px solid #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#masterPanelLeft .gwt-SliderBar-shell .gwt-SliderBar-tick-disabled {
|
||||||
|
background: gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
#masterPanelLeft .gwt-SliderBar-shell .gwt-SliderBar-ticklabel {
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: default;
|
||||||
|
font-family: 'UbuntuBold',Arial,Verdana,sans-serif;
|
||||||
|
top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#masterPanelLeft .gwt-SliderBar-shell .gwt-SliderBar-markerlabel {
|
||||||
|
top: 30pt;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #bc9434;
|
||||||
|
cursor: default;
|
||||||
|
font-family: 'UbuntuBold',Arial,Verdana,sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
#masterPanelLeft .gwt-SliderBar-shell-focused {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#masterPanelLeft .gwt-SliderBar-shell .gwt-SliderBar-line-sliding {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.boatClassLabel {
|
||||||
|
width: 235px;
|
||||||
|
margin: 0 0 15px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sailingPanel {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dockLayoutPanel div[style="position: absolute; overflow: hidden; left: 0px; right: 0px; bottom: 0px; height: 90px;"] {
|
||||||
|
box-shadow: 0 0 8px #424242;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MapDisplayOptions {
|
||||||
|
margin: 0 15px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MapDisplayOptions label,.gwt-RadioButton label {
|
||||||
|
margin: 0 0 0 5px;
|
||||||
|
}
|
||||||
|
.MapDisplayOptions {
|
||||||
|
margin: 0 0 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeSliderWrapperPanel{
|
||||||
|
-webkit-box-shadow: inset 0px 5px 10px 0px rgba(0, 0, 0, 0.15); /* WebKit */
|
||||||
|
-moz-box-shadow: inset 0px 5px 10px 0px rgba(0, 0, 0, 0.15); /* Firefox */
|
||||||
|
box-shadow: inset 0px 5px 10px 0px rgba(0, 0, 0, 0.15); /* Standard */
|
||||||
|
}
|
||||||
|
.polarDiv
|
||||||
|
{background-color: white;width:100%;height:100px;border-radius: 5px; -moz-border-radius: 5px;
|
||||||
|
-webkit-border-radius: 5px; border: 1px solid #177980;}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<!doctype html>
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||||
|
<title>SAP Sailing Analytics Race Simulator</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 href="CommonControls.css" rel="stylesheet" type="text/css">
|
||||||
|
<!--<link href='http://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700,300italic,400italic,500italic,700italic' rel='stylesheet' type='text/css'>-->
|
||||||
|
<!-- <link href='http://fonts.googleapis.com/css?family=Open+Sans+Condensed:700,300,300italic' rel='stylesheet' type='text/css'>-->
|
||||||
|
|
||||||
|
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="highcharts/js/highcharts2_3.js"></script>
|
||||||
|
<script type="text/javascript" src="highcharts/js/highcharts-more.js"></script>
|
||||||
|
<script type="text/javascript" src="highcharts/js/exporting.js"></script>
|
||||||
|
<!-- <script type="text/javascript" src="highcharts/js/highcharts.js"></script>-->
|
||||||
|
|
||||||
|
<!-- Optionally, add a highcharts theme file -->
|
||||||
|
<script type="text/javascript" src="highcharts/js/themes/grid.js"></script>
|
||||||
|
<script type="text/javascript" language="javascript" src="com.sap.sailing.gwt.ui.Simulator/com.sap.sailing.gwt.ui.Simulator.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>
|
||||||
@@ -33,6 +33,16 @@
|
|||||||
<url-pattern>/media</url-pattern>
|
<url-pattern>/media</url-pattern>
|
||||||
</servlet-mapping>
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<servlet>
|
||||||
|
<display-name>Simulator Service</display-name>
|
||||||
|
<servlet-name>SimulatorService</servlet-name>
|
||||||
|
<servlet-class>com.sap.sailing.gwt.ui.server.SimulatorServiceImpl</servlet-class>
|
||||||
|
</servlet>
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>SimulatorService</servlet-name>
|
||||||
|
<url-pattern>com.sap.sailing.gwt.ui.Simulator/simulator</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
<servlet>
|
<servlet>
|
||||||
<display-name>User Management Service</display-name>
|
<display-name>User Management Service</display-name>
|
||||||
<servlet-name>UserManagementService</servlet-name>
|
<servlet-name>UserManagementService</servlet-name>
|
||||||
@@ -52,6 +62,7 @@
|
|||||||
<servlet-mapping>
|
<servlet-mapping>
|
||||||
<servlet-name>remoteLoggingServlet</servlet-name>
|
<servlet-name>remoteLoggingServlet</servlet-name>
|
||||||
<url-pattern>/com.sap.sailing.gwt.ui.AdminConsole/remote_logging</url-pattern>
|
<url-pattern>/com.sap.sailing.gwt.ui.AdminConsole/remote_logging</url-pattern>
|
||||||
|
<url-pattern>/com.sap.sailing.gwt.ui.Simulator/remote_logging</url-pattern>
|
||||||
</servlet-mapping>
|
</servlet-mapping>
|
||||||
|
|
||||||
<security-constraint>
|
<security-constraint>
|
||||||
|
|||||||
@@ -28,8 +28,11 @@ bin.includes = META-INF/,\
|
|||||||
com.sap.sailing.gwt.ui.RaceBoard/,\
|
com.sap.sailing.gwt.ui.RaceBoard/,\
|
||||||
highcharts/,\
|
highcharts/,\
|
||||||
Spectator.css,\
|
Spectator.css,\
|
||||||
fontface.css,\
|
fontface.css,\
|
||||||
webfonts/,\
|
webfonts/,\
|
||||||
|
com.sap.sailing.gwt.ui.Simulator/,\
|
||||||
|
Simulator.html,\
|
||||||
|
Simulator.css,\
|
||||||
RegattaOverview.css,\
|
RegattaOverview.css,\
|
||||||
RegattaOverview.html,\
|
RegattaOverview.html,\
|
||||||
com.sap.sailing.gwt.ui.RegattaOverview/,\
|
com.sap.sailing.gwt.ui.RegattaOverview/,\
|
||||||
|
|||||||
@@ -0,0 +1,737 @@
|
|||||||
|
/**
|
||||||
|
* @license @product.name@ JS v@product.version@ (@product.date@)
|
||||||
|
* Exporting module
|
||||||
|
*
|
||||||
|
* (c) 2010-2011 Torstein Hønsi
|
||||||
|
*
|
||||||
|
* License: www.highcharts.com/license
|
||||||
|
*/
|
||||||
|
|
||||||
|
// JSLint options:
|
||||||
|
/*global Highcharts, document, window, Math, setTimeout */
|
||||||
|
|
||||||
|
(function () { // encapsulate
|
||||||
|
|
||||||
|
// create shortcuts
|
||||||
|
var HC = Highcharts,
|
||||||
|
Chart = HC.Chart,
|
||||||
|
addEvent = HC.addEvent,
|
||||||
|
removeEvent = HC.removeEvent,
|
||||||
|
createElement = HC.createElement,
|
||||||
|
discardElement = HC.discardElement,
|
||||||
|
css = HC.css,
|
||||||
|
merge = HC.merge,
|
||||||
|
each = HC.each,
|
||||||
|
extend = HC.extend,
|
||||||
|
math = Math,
|
||||||
|
mathMax = math.max,
|
||||||
|
doc = document,
|
||||||
|
win = window,
|
||||||
|
hasTouch = doc.documentElement.ontouchstart !== undefined,
|
||||||
|
M = 'M',
|
||||||
|
L = 'L',
|
||||||
|
DIV = 'div',
|
||||||
|
HIDDEN = 'hidden',
|
||||||
|
NONE = 'none',
|
||||||
|
PREFIX = 'highcharts-',
|
||||||
|
ABSOLUTE = 'absolute',
|
||||||
|
PX = 'px',
|
||||||
|
UNDEFINED,
|
||||||
|
defaultOptions = HC.getOptions();
|
||||||
|
|
||||||
|
// Add language
|
||||||
|
extend(defaultOptions.lang, {
|
||||||
|
downloadPNG: 'Download PNG image',
|
||||||
|
downloadJPEG: 'Download JPEG image',
|
||||||
|
downloadPDF: 'Download PDF document',
|
||||||
|
downloadSVG: 'Download SVG vector image',
|
||||||
|
exportButtonTitle: 'Export to raster or vector image',
|
||||||
|
printButtonTitle: 'Print the chart'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Buttons and menus are collected in a separate config option set called 'navigation'.
|
||||||
|
// This can be extended later to add control buttons like zoom and pan right click menus.
|
||||||
|
defaultOptions.navigation = {
|
||||||
|
menuStyle: {
|
||||||
|
border: '1px solid #A0A0A0',
|
||||||
|
background: '#FFFFFF'
|
||||||
|
},
|
||||||
|
menuItemStyle: {
|
||||||
|
padding: '0 5px',
|
||||||
|
background: NONE,
|
||||||
|
color: '#303030',
|
||||||
|
fontSize: hasTouch ? '14px' : '11px'
|
||||||
|
},
|
||||||
|
menuItemHoverStyle: {
|
||||||
|
background: '#4572A5',
|
||||||
|
color: '#FFFFFF'
|
||||||
|
},
|
||||||
|
|
||||||
|
buttonOptions: {
|
||||||
|
align: 'right',
|
||||||
|
backgroundColor: {
|
||||||
|
linearGradient: [0, 0, 0, 20],
|
||||||
|
stops: [
|
||||||
|
[0.4, '#F7F7F7'],
|
||||||
|
[0.6, '#E3E3E3']
|
||||||
|
]
|
||||||
|
},
|
||||||
|
borderColor: '#B0B0B0',
|
||||||
|
borderRadius: 3,
|
||||||
|
borderWidth: 1,
|
||||||
|
//enabled: true,
|
||||||
|
height: 20,
|
||||||
|
hoverBorderColor: '#909090',
|
||||||
|
hoverSymbolFill: '#81A7CF',
|
||||||
|
hoverSymbolStroke: '#4572A5',
|
||||||
|
symbolFill: '#E0E0E0',
|
||||||
|
//symbolSize: 12,
|
||||||
|
symbolStroke: '#A0A0A0',
|
||||||
|
//symbolStrokeWidth: 1,
|
||||||
|
symbolX: 11.5,
|
||||||
|
symbolY: 10.5,
|
||||||
|
verticalAlign: 'top',
|
||||||
|
width: 24,
|
||||||
|
y: 10
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Add the export related options
|
||||||
|
defaultOptions.exporting = {
|
||||||
|
//enabled: true,
|
||||||
|
//filename: 'chart',
|
||||||
|
type: 'image/png',
|
||||||
|
url: 'http://export.highcharts.com/',
|
||||||
|
width: 800,
|
||||||
|
buttons: {
|
||||||
|
exportButton: {
|
||||||
|
//enabled: true,
|
||||||
|
symbol: 'exportIcon',
|
||||||
|
x: -10,
|
||||||
|
symbolFill: '#A8BF77',
|
||||||
|
hoverSymbolFill: '#768F3E',
|
||||||
|
_id: 'exportButton',
|
||||||
|
_titleKey: 'exportButtonTitle',
|
||||||
|
menuItems: [{
|
||||||
|
textKey: 'downloadPNG',
|
||||||
|
onclick: function () {
|
||||||
|
this.exportChart();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
textKey: 'downloadJPEG',
|
||||||
|
onclick: function () {
|
||||||
|
this.exportChart({
|
||||||
|
type: 'image/jpeg'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
textKey: 'downloadPDF',
|
||||||
|
onclick: function () {
|
||||||
|
this.exportChart({
|
||||||
|
type: 'application/pdf'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
textKey: 'downloadSVG',
|
||||||
|
onclick: function () {
|
||||||
|
this.exportChart({
|
||||||
|
type: 'image/svg+xml'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Enable this block to add "View SVG" to the dropdown menu
|
||||||
|
/*
|
||||||
|
,{
|
||||||
|
|
||||||
|
text: 'View SVG',
|
||||||
|
onclick: function () {
|
||||||
|
var svg = this.getSVG()
|
||||||
|
.replace(/</g, '\n<')
|
||||||
|
.replace(/>/g, '>');
|
||||||
|
|
||||||
|
doc.body.innerHTML = '<pre>' + svg + '</pre>';
|
||||||
|
}
|
||||||
|
} // */
|
||||||
|
]
|
||||||
|
|
||||||
|
},
|
||||||
|
printButton: {
|
||||||
|
//enabled: true,
|
||||||
|
symbol: 'printIcon',
|
||||||
|
x: -36,
|
||||||
|
symbolFill: '#B5C9DF',
|
||||||
|
hoverSymbolFill: '#779ABF',
|
||||||
|
_id: 'printButton',
|
||||||
|
_titleKey: 'printButtonTitle',
|
||||||
|
onclick: function () {
|
||||||
|
this.print();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extend(Chart.prototype, {
|
||||||
|
/**
|
||||||
|
* Return an SVG representation of the chart
|
||||||
|
*
|
||||||
|
* @param additionalOptions {Object} Additional chart options for the generated SVG representation
|
||||||
|
*/
|
||||||
|
getSVG: function (additionalOptions) {
|
||||||
|
var chart = this,
|
||||||
|
chartCopy,
|
||||||
|
sandbox,
|
||||||
|
svg,
|
||||||
|
seriesOptions,
|
||||||
|
options = merge(chart.options, additionalOptions); // copy the options and add extra options
|
||||||
|
|
||||||
|
// IE compatibility hack for generating SVG content that it doesn't really understand
|
||||||
|
if (!doc.createElementNS) {
|
||||||
|
/*jslint unparam: true*//* allow unused parameter ns in function below */
|
||||||
|
doc.createElementNS = function (ns, tagName) {
|
||||||
|
return doc.createElement(tagName);
|
||||||
|
};
|
||||||
|
/*jslint unparam: false*/
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a sandbox where a new chart will be generated
|
||||||
|
sandbox = createElement(DIV, null, {
|
||||||
|
position: ABSOLUTE,
|
||||||
|
top: '-9999em',
|
||||||
|
width: chart.chartWidth + PX,
|
||||||
|
height: chart.chartHeight + PX
|
||||||
|
}, doc.body);
|
||||||
|
|
||||||
|
// override some options
|
||||||
|
extend(options.chart, {
|
||||||
|
renderTo: sandbox,
|
||||||
|
forExport: true
|
||||||
|
});
|
||||||
|
options.exporting.enabled = false; // hide buttons in print
|
||||||
|
options.chart.plotBackgroundImage = null; // the converter doesn't handle images
|
||||||
|
|
||||||
|
// prepare for replicating the chart
|
||||||
|
options.series = [];
|
||||||
|
each(chart.series, function (serie) {
|
||||||
|
seriesOptions = merge(serie.options, {
|
||||||
|
animation: false, // turn off animation
|
||||||
|
showCheckbox: false,
|
||||||
|
visible: serie.visible
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!seriesOptions.isInternal) { // used for the navigator series that has its own option set
|
||||||
|
|
||||||
|
// remove image markers
|
||||||
|
if (seriesOptions && seriesOptions.marker && /^url\(/.test(seriesOptions.marker.symbol)) {
|
||||||
|
seriesOptions.marker.symbol = 'circle';
|
||||||
|
}
|
||||||
|
|
||||||
|
options.series.push(seriesOptions);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// generate the chart copy
|
||||||
|
chartCopy = new Highcharts.Chart(options);
|
||||||
|
|
||||||
|
// reflect axis extremes in the export
|
||||||
|
each(['xAxis', 'yAxis'], function (axisType) {
|
||||||
|
each(chart[axisType], function (axis, i) {
|
||||||
|
var axisCopy = chartCopy[axisType][i],
|
||||||
|
extremes = axis.getExtremes(),
|
||||||
|
userMin = extremes.userMin,
|
||||||
|
userMax = extremes.userMax;
|
||||||
|
|
||||||
|
if (userMin !== UNDEFINED || userMax !== UNDEFINED) {
|
||||||
|
axisCopy.setExtremes(userMin, userMax, true, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// get the SVG from the container's innerHTML
|
||||||
|
svg = chartCopy.container.innerHTML;
|
||||||
|
|
||||||
|
// free up memory
|
||||||
|
options = null;
|
||||||
|
chartCopy.destroy();
|
||||||
|
discardElement(sandbox);
|
||||||
|
|
||||||
|
// sanitize
|
||||||
|
svg = svg
|
||||||
|
.replace(/zIndex="[^"]+"/g, '')
|
||||||
|
.replace(/isShadow="[^"]+"/g, '')
|
||||||
|
.replace(/symbolName="[^"]+"/g, '')
|
||||||
|
.replace(/jQuery[0-9]+="[^"]+"/g, '')
|
||||||
|
.replace(/isTracker="[^"]+"/g, '')
|
||||||
|
.replace(/url\([^#]+#/g, 'url(#')
|
||||||
|
.replace(/<svg /, '<svg xmlns:xlink="http://www.w3.org/1999/xlink" ')
|
||||||
|
.replace(/ href=/g, ' xlink:href=')
|
||||||
|
.replace(/\n/, ' ')
|
||||||
|
.replace(/<\/svg>.*?$/, '</svg>') // any HTML added to the container after the SVG (#894)
|
||||||
|
/* This fails in IE < 8
|
||||||
|
.replace(/([0-9]+)\.([0-9]+)/g, function(s1, s2, s3) { // round off to save weight
|
||||||
|
return s2 +'.'+ s3[0];
|
||||||
|
})*/
|
||||||
|
|
||||||
|
// Replace HTML entities, issue #347
|
||||||
|
.replace(/ /g, '\u00A0') // no-break space
|
||||||
|
.replace(/­/g, '\u00AD') // soft hyphen
|
||||||
|
|
||||||
|
// IE specific
|
||||||
|
.replace(/<IMG /g, '<image ')
|
||||||
|
.replace(/height=([^" ]+)/g, 'height="$1"')
|
||||||
|
.replace(/width=([^" ]+)/g, 'width="$1"')
|
||||||
|
.replace(/hc-svg-href="([^"]+)">/g, 'xlink:href="$1"/>')
|
||||||
|
.replace(/id=([^" >]+)/g, 'id="$1"')
|
||||||
|
.replace(/class=([^" ]+)/g, 'class="$1"')
|
||||||
|
.replace(/ transform /g, ' ')
|
||||||
|
.replace(/:(path|rect)/g, '$1')
|
||||||
|
.replace(/style="([^"]+)"/g, function (s) {
|
||||||
|
return s.toLowerCase();
|
||||||
|
});
|
||||||
|
|
||||||
|
// IE9 beta bugs with innerHTML. Test again with final IE9.
|
||||||
|
svg = svg.replace(/(url\(#highcharts-[0-9]+)"/g, '$1')
|
||||||
|
.replace(/"/g, "'");
|
||||||
|
if (svg.match(/ xmlns="/g).length === 2) {
|
||||||
|
svg = svg.replace(/xmlns="[^"]+"/, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
return svg;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submit the SVG representation of the chart to the server
|
||||||
|
* @param {Object} options Exporting options. Possible members are url, type and width.
|
||||||
|
* @param {Object} chartOptions Additional chart options for the SVG representation of the chart
|
||||||
|
*/
|
||||||
|
exportChart: function (options, chartOptions) {
|
||||||
|
var form,
|
||||||
|
chart = this,
|
||||||
|
svg = chart.getSVG(merge(chart.options.exporting.chartOptions, chartOptions)); // docs
|
||||||
|
|
||||||
|
// merge the options
|
||||||
|
options = merge(chart.options.exporting, options);
|
||||||
|
|
||||||
|
// create the form
|
||||||
|
form = createElement('form', {
|
||||||
|
method: 'post',
|
||||||
|
action: options.url,
|
||||||
|
enctype: 'multipart/form-data'
|
||||||
|
}, {
|
||||||
|
display: NONE
|
||||||
|
}, doc.body);
|
||||||
|
|
||||||
|
// add the values
|
||||||
|
each(['filename', 'type', 'width', 'svg'], function (name) {
|
||||||
|
createElement('input', {
|
||||||
|
type: HIDDEN,
|
||||||
|
name: name,
|
||||||
|
value: {
|
||||||
|
filename: options.filename || 'chart',
|
||||||
|
type: options.type,
|
||||||
|
width: options.width,
|
||||||
|
svg: svg
|
||||||
|
}[name]
|
||||||
|
}, null, form);
|
||||||
|
});
|
||||||
|
|
||||||
|
// submit
|
||||||
|
form.submit();
|
||||||
|
|
||||||
|
// clean up
|
||||||
|
discardElement(form);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print the chart
|
||||||
|
*/
|
||||||
|
print: function () {
|
||||||
|
|
||||||
|
var chart = this,
|
||||||
|
container = chart.container,
|
||||||
|
origDisplay = [],
|
||||||
|
origParent = container.parentNode,
|
||||||
|
body = doc.body,
|
||||||
|
childNodes = body.childNodes;
|
||||||
|
|
||||||
|
if (chart.isPrinting) { // block the button while in printing mode
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
chart.isPrinting = true;
|
||||||
|
|
||||||
|
// hide all body content
|
||||||
|
each(childNodes, function (node, i) {
|
||||||
|
if (node.nodeType === 1) {
|
||||||
|
origDisplay[i] = node.style.display;
|
||||||
|
node.style.display = NONE;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// pull out the chart
|
||||||
|
body.appendChild(container);
|
||||||
|
|
||||||
|
// print
|
||||||
|
win.print();
|
||||||
|
|
||||||
|
// allow the browser to prepare before reverting
|
||||||
|
setTimeout(function () {
|
||||||
|
|
||||||
|
// put the chart back in
|
||||||
|
origParent.appendChild(container);
|
||||||
|
|
||||||
|
// restore all body content
|
||||||
|
each(childNodes, function (node, i) {
|
||||||
|
if (node.nodeType === 1) {
|
||||||
|
node.style.display = origDisplay[i];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
chart.isPrinting = false;
|
||||||
|
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display a popup menu for choosing the export type
|
||||||
|
*
|
||||||
|
* @param {String} name An identifier for the menu
|
||||||
|
* @param {Array} items A collection with text and onclicks for the items
|
||||||
|
* @param {Number} x The x position of the opener button
|
||||||
|
* @param {Number} y The y position of the opener button
|
||||||
|
* @param {Number} width The width of the opener button
|
||||||
|
* @param {Number} height The height of the opener button
|
||||||
|
*/
|
||||||
|
contextMenu: function (name, items, x, y, width, height) {
|
||||||
|
var chart = this,
|
||||||
|
navOptions = chart.options.navigation,
|
||||||
|
menuItemStyle = navOptions.menuItemStyle,
|
||||||
|
chartWidth = chart.chartWidth,
|
||||||
|
chartHeight = chart.chartHeight,
|
||||||
|
cacheName = 'cache-' + name,
|
||||||
|
menu = chart[cacheName],
|
||||||
|
menuPadding = mathMax(width, height), // for mouse leave detection
|
||||||
|
boxShadow = '3px 3px 10px #888',
|
||||||
|
innerMenu,
|
||||||
|
hide,
|
||||||
|
menuStyle;
|
||||||
|
|
||||||
|
// create the menu only the first time
|
||||||
|
if (!menu) {
|
||||||
|
|
||||||
|
// create a HTML element above the SVG
|
||||||
|
chart[cacheName] = menu = createElement(DIV, {
|
||||||
|
className: PREFIX + name
|
||||||
|
}, {
|
||||||
|
position: ABSOLUTE,
|
||||||
|
zIndex: 1000,
|
||||||
|
padding: menuPadding + PX
|
||||||
|
}, chart.container);
|
||||||
|
|
||||||
|
innerMenu = createElement(DIV, null,
|
||||||
|
extend({
|
||||||
|
MozBoxShadow: boxShadow,
|
||||||
|
WebkitBoxShadow: boxShadow,
|
||||||
|
boxShadow: boxShadow
|
||||||
|
}, navOptions.menuStyle), menu);
|
||||||
|
|
||||||
|
// hide on mouse out
|
||||||
|
hide = function () {
|
||||||
|
css(menu, { display: NONE });
|
||||||
|
};
|
||||||
|
|
||||||
|
addEvent(menu, 'mouseleave', hide);
|
||||||
|
|
||||||
|
|
||||||
|
// create the items
|
||||||
|
each(items, function (item) {
|
||||||
|
if (item) {
|
||||||
|
var div = createElement(DIV, {
|
||||||
|
onmouseover: function () {
|
||||||
|
css(this, navOptions.menuItemHoverStyle);
|
||||||
|
},
|
||||||
|
onmouseout: function () {
|
||||||
|
css(this, menuItemStyle);
|
||||||
|
},
|
||||||
|
innerHTML: item.text || chart.options.lang[item.textKey]
|
||||||
|
}, extend({
|
||||||
|
cursor: 'pointer'
|
||||||
|
}, menuItemStyle), innerMenu);
|
||||||
|
|
||||||
|
div[hasTouch ? 'ontouchstart' : 'onclick'] = function () {
|
||||||
|
hide();
|
||||||
|
item.onclick.apply(chart, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Keep references to menu divs to be able to destroy them
|
||||||
|
chart.exportDivElements.push(div);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Keep references to menu and innerMenu div to be able to destroy them
|
||||||
|
chart.exportDivElements.push(innerMenu, menu);
|
||||||
|
|
||||||
|
chart.exportMenuWidth = menu.offsetWidth;
|
||||||
|
chart.exportMenuHeight = menu.offsetHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
menuStyle = { display: 'block' };
|
||||||
|
|
||||||
|
// if outside right, right align it
|
||||||
|
if (x + chart.exportMenuWidth > chartWidth) {
|
||||||
|
menuStyle.right = (chartWidth - x - width - menuPadding) + PX;
|
||||||
|
} else {
|
||||||
|
menuStyle.left = (x - menuPadding) + PX;
|
||||||
|
}
|
||||||
|
// if outside bottom, bottom align it
|
||||||
|
if (y + height + chart.exportMenuHeight > chartHeight) {
|
||||||
|
menuStyle.bottom = (chartHeight - y - menuPadding) + PX;
|
||||||
|
} else {
|
||||||
|
menuStyle.top = (y + height - menuPadding) + PX;
|
||||||
|
}
|
||||||
|
|
||||||
|
css(menu, menuStyle);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the export button to the chart
|
||||||
|
*/
|
||||||
|
addButton: function (options) {
|
||||||
|
var chart = this,
|
||||||
|
renderer = chart.renderer,
|
||||||
|
btnOptions = merge(chart.options.navigation.buttonOptions, options),
|
||||||
|
onclick = btnOptions.onclick,
|
||||||
|
menuItems = btnOptions.menuItems,
|
||||||
|
buttonWidth = btnOptions.width,
|
||||||
|
buttonHeight = btnOptions.height,
|
||||||
|
box,
|
||||||
|
symbol,
|
||||||
|
button,
|
||||||
|
borderWidth = btnOptions.borderWidth,
|
||||||
|
boxAttr = {
|
||||||
|
stroke: btnOptions.borderColor
|
||||||
|
|
||||||
|
},
|
||||||
|
symbolAttr = {
|
||||||
|
stroke: btnOptions.symbolStroke,
|
||||||
|
fill: btnOptions.symbolFill
|
||||||
|
},
|
||||||
|
symbolSize = btnOptions.symbolSize || 12;
|
||||||
|
|
||||||
|
// Keeps references to the button elements
|
||||||
|
if (!chart.exportDivElements) {
|
||||||
|
chart.exportDivElements = [];
|
||||||
|
chart.exportSVGElements = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (btnOptions.enabled === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// element to capture the click
|
||||||
|
function revert() {
|
||||||
|
symbol.attr(symbolAttr);
|
||||||
|
box.attr(boxAttr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// the box border
|
||||||
|
box = renderer.rect(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
buttonWidth,
|
||||||
|
buttonHeight,
|
||||||
|
btnOptions.borderRadius,
|
||||||
|
borderWidth
|
||||||
|
)
|
||||||
|
//.translate(buttonLeft, buttonTop) // to allow gradients
|
||||||
|
.align(btnOptions, true)
|
||||||
|
.attr(extend({
|
||||||
|
fill: btnOptions.backgroundColor,
|
||||||
|
'stroke-width': borderWidth,
|
||||||
|
zIndex: 19
|
||||||
|
}, boxAttr)).add();
|
||||||
|
|
||||||
|
// the invisible element to track the clicks
|
||||||
|
button = renderer.rect(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
buttonWidth,
|
||||||
|
buttonHeight,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
.align(btnOptions)
|
||||||
|
.attr({
|
||||||
|
id: btnOptions._id,
|
||||||
|
fill: 'rgba(255, 255, 255, 0.001)',
|
||||||
|
title: chart.options.lang[btnOptions._titleKey],
|
||||||
|
zIndex: 21
|
||||||
|
}).css({
|
||||||
|
cursor: 'pointer'
|
||||||
|
})
|
||||||
|
.on('mouseover', function () {
|
||||||
|
symbol.attr({
|
||||||
|
stroke: btnOptions.hoverSymbolStroke,
|
||||||
|
fill: btnOptions.hoverSymbolFill
|
||||||
|
});
|
||||||
|
box.attr({
|
||||||
|
stroke: btnOptions.hoverBorderColor
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.on('mouseout', revert)
|
||||||
|
.on('click', revert)
|
||||||
|
.add();
|
||||||
|
|
||||||
|
// add the click event
|
||||||
|
if (menuItems) {
|
||||||
|
onclick = function () {
|
||||||
|
revert();
|
||||||
|
var bBox = button.getBBox();
|
||||||
|
chart.contextMenu('export-menu', menuItems, bBox.x, bBox.y, buttonWidth, buttonHeight);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/*addEvent(button.element, 'click', function() {
|
||||||
|
onclick.apply(chart, arguments);
|
||||||
|
});*/
|
||||||
|
button.on('click', function () {
|
||||||
|
onclick.apply(chart, arguments);
|
||||||
|
});
|
||||||
|
|
||||||
|
// the icon
|
||||||
|
symbol = renderer.symbol(
|
||||||
|
btnOptions.symbol,
|
||||||
|
btnOptions.symbolX - (symbolSize / 2),
|
||||||
|
btnOptions.symbolY - (symbolSize / 2),
|
||||||
|
symbolSize,
|
||||||
|
symbolSize
|
||||||
|
)
|
||||||
|
.align(btnOptions, true)
|
||||||
|
.attr(extend(symbolAttr, {
|
||||||
|
'stroke-width': btnOptions.symbolStrokeWidth || 1,
|
||||||
|
zIndex: 20
|
||||||
|
})).add();
|
||||||
|
|
||||||
|
// Keep references to the renderer element so to be able to destroy them later.
|
||||||
|
chart.exportSVGElements.push(box, button, symbol);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy the buttons.
|
||||||
|
*/
|
||||||
|
destroyExport: function () {
|
||||||
|
var i,
|
||||||
|
chart = this,
|
||||||
|
elem;
|
||||||
|
|
||||||
|
// Destroy the extra buttons added
|
||||||
|
for (i = 0; i < chart.exportSVGElements.length; i++) {
|
||||||
|
elem = chart.exportSVGElements[i];
|
||||||
|
// Destroy and null the svg/vml elements
|
||||||
|
elem.onclick = elem.ontouchstart = null;
|
||||||
|
chart.exportSVGElements[i] = elem.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy the divs for the menu
|
||||||
|
for (i = 0; i < chart.exportDivElements.length; i++) {
|
||||||
|
elem = chart.exportDivElements[i];
|
||||||
|
|
||||||
|
// Remove the event handler
|
||||||
|
removeEvent(elem, 'mouseleave');
|
||||||
|
|
||||||
|
// Remove inline events
|
||||||
|
chart.exportDivElements[i] = elem.onmouseout = elem.onmouseover = elem.ontouchstart = elem.onclick = null;
|
||||||
|
|
||||||
|
// Destroy the div by moving to garbage bin
|
||||||
|
discardElement(elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crisp for 1px stroke width, which is default. In the future, consider a smarter,
|
||||||
|
* global function.
|
||||||
|
*/
|
||||||
|
function crisp(arr) {
|
||||||
|
var i = arr.length;
|
||||||
|
while (i--) {
|
||||||
|
if (typeof arr[i] === 'number') {
|
||||||
|
arr[i] = Math.round(arr[i]) - 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the export icon
|
||||||
|
HC.Renderer.prototype.symbols.exportIcon = function (x, y, width, height) {
|
||||||
|
return crisp([
|
||||||
|
M, // the disk
|
||||||
|
x, y + width,
|
||||||
|
L,
|
||||||
|
x + width, y + height,
|
||||||
|
x + width, y + height * 0.8,
|
||||||
|
x, y + height * 0.8,
|
||||||
|
'Z',
|
||||||
|
M, // the arrow
|
||||||
|
x + width * 0.5, y + height * 0.8,
|
||||||
|
L,
|
||||||
|
x + width * 0.8, y + height * 0.4,
|
||||||
|
x + width * 0.4, y + height * 0.4,
|
||||||
|
x + width * 0.4, y,
|
||||||
|
x + width * 0.6, y,
|
||||||
|
x + width * 0.6, y + height * 0.4,
|
||||||
|
x + width * 0.2, y + height * 0.4,
|
||||||
|
'Z'
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
// Create the print icon
|
||||||
|
HC.Renderer.prototype.symbols.printIcon = function (x, y, width, height) {
|
||||||
|
return crisp([
|
||||||
|
M, // the printer
|
||||||
|
x, y + height * 0.7,
|
||||||
|
L,
|
||||||
|
x + width, y + height * 0.7,
|
||||||
|
x + width, y + height * 0.4,
|
||||||
|
x, y + height * 0.4,
|
||||||
|
'Z',
|
||||||
|
M, // the upper sheet
|
||||||
|
x + width * 0.2, y + height * 0.4,
|
||||||
|
L,
|
||||||
|
x + width * 0.2, y,
|
||||||
|
x + width * 0.8, y,
|
||||||
|
x + width * 0.8, y + height * 0.4,
|
||||||
|
'Z',
|
||||||
|
M, // the lower sheet
|
||||||
|
x + width * 0.2, y + height * 0.7,
|
||||||
|
L,
|
||||||
|
x, y + height,
|
||||||
|
x + width, y + height,
|
||||||
|
x + width * 0.8, y + height * 0.7,
|
||||||
|
'Z'
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Add the buttons on chart load
|
||||||
|
Chart.prototype.callbacks.push(function (chart) {
|
||||||
|
var n,
|
||||||
|
exportingOptions = chart.options.exporting,
|
||||||
|
buttons = exportingOptions.buttons;
|
||||||
|
|
||||||
|
if (exportingOptions.enabled !== false) {
|
||||||
|
|
||||||
|
for (n in buttons) {
|
||||||
|
chart.addButton(buttons[n]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy the export elements at chart destroy
|
||||||
|
addEvent(chart, 'destroy', chart.destroyExport);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}());
|
||||||
|
window.console && console.log('--- Running modules/exporting.src.js from GitHub ---');
|
||||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1015 B |
@@ -53,6 +53,7 @@
|
|||||||
<module>com.sap.sailing.gwt.ui.UserManagement</module>
|
<module>com.sap.sailing.gwt.ui.UserManagement</module>
|
||||||
<module>com.sap.sailing.gwt.ui.VideoPopup</module>
|
<module>com.sap.sailing.gwt.ui.VideoPopup</module>
|
||||||
<module>com.sap.sailing.gwt.ui.YoutubePopup</module>
|
<module>com.sap.sailing.gwt.ui.YoutubePopup</module>
|
||||||
|
<module>com.sap.sailing.gwt.ui.Simulator</module>
|
||||||
<module>com.sap.sailing.gwt.ui.RegattaOverview</module>
|
<module>com.sap.sailing.gwt.ui.RegattaOverview</module>
|
||||||
<module>com.sap.sailing.gwt.ui.PolarSheets</module>
|
<module>com.sap.sailing.gwt.ui.PolarSheets</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|||||||
+1
-1
@@ -6,8 +6,8 @@ import java.util.List;
|
|||||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||||
import com.sap.sailing.domain.common.DetailType;
|
import com.sap.sailing.domain.common.DetailType;
|
||||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||||
|
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||||
import com.sap.sailing.gwt.ui.shared.CompetitorDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.CompetitorsRaceDataDTO;
|
import com.sap.sailing.gwt.ui.shared.CompetitorsRaceDataDTO;
|
||||||
|
|
||||||
public class GetCompetitorsRaceDataAction extends DefaultAsyncAction<CompetitorsRaceDataDTO> {
|
public class GetCompetitorsRaceDataAction extends DefaultAsyncAction<CompetitorsRaceDataDTO> {
|
||||||
|
|||||||
+1
-1
@@ -4,8 +4,8 @@ import java.util.Collection;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||||
|
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
|
||||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||||
import com.sap.sailing.gwt.ui.shared.LeaderboardDTO;
|
|
||||||
|
|
||||||
public class GetLeaderboardByNameAction extends DefaultAsyncAction<LeaderboardDTO> {
|
public class GetLeaderboardByNameAction extends DefaultAsyncAction<LeaderboardDTO> {
|
||||||
private final SailingServiceAsync sailingService;
|
private final SailingServiceAsync sailingService;
|
||||||
|
|||||||
+1
-1
@@ -6,9 +6,9 @@ import java.util.Map;
|
|||||||
|
|
||||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||||
|
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||||
import com.sap.sailing.gwt.ui.shared.CompactRaceMapDataDTO;
|
import com.sap.sailing.gwt.ui.shared.CompactRaceMapDataDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.CompetitorDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceMapDataDTO;
|
import com.sap.sailing.gwt.ui.shared.RaceMapDataDTO;
|
||||||
|
|
||||||
public class GetRaceMapDataAction extends DefaultAsyncAction<RaceMapDataDTO> {
|
public class GetRaceMapDataAction extends DefaultAsyncAction<RaceMapDataDTO> {
|
||||||
|
|||||||
+1
-1
@@ -5,13 +5,13 @@ import java.util.List;
|
|||||||
import com.google.gwt.user.client.ui.CaptionPanel;
|
import com.google.gwt.user.client.ui.CaptionPanel;
|
||||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||||
|
import com.sap.sailing.domain.common.dto.RaceDTO;
|
||||||
import com.sap.sailing.gwt.ui.client.ErrorReporter;
|
import com.sap.sailing.gwt.ui.client.ErrorReporter;
|
||||||
import com.sap.sailing.gwt.ui.client.RaceSelectionChangeListener;
|
import com.sap.sailing.gwt.ui.client.RaceSelectionChangeListener;
|
||||||
import com.sap.sailing.gwt.ui.client.RaceSelectionModel;
|
import com.sap.sailing.gwt.ui.client.RaceSelectionModel;
|
||||||
import com.sap.sailing.gwt.ui.client.RegattaRefresher;
|
import com.sap.sailing.gwt.ui.client.RegattaRefresher;
|
||||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
||||||
|
|
||||||
public abstract class AbstractRaceManagementPanel extends AbstractEventManagementPanel implements RaceSelectionChangeListener {
|
public abstract class AbstractRaceManagementPanel extends AbstractEventManagementPanel implements RaceSelectionChangeListener {
|
||||||
|
|||||||
+1
-1
@@ -41,6 +41,7 @@ import com.google.gwt.view.client.SingleSelectionModel;
|
|||||||
import com.sap.sailing.domain.common.RaceIdentifier;
|
import com.sap.sailing.domain.common.RaceIdentifier;
|
||||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||||
import com.sap.sailing.domain.common.TrackedRaceStatusEnum;
|
import com.sap.sailing.domain.common.TrackedRaceStatusEnum;
|
||||||
|
import com.sap.sailing.domain.common.dto.RaceDTO;
|
||||||
import com.sap.sailing.gwt.ui.client.ErrorReporter;
|
import com.sap.sailing.gwt.ui.client.ErrorReporter;
|
||||||
import com.sap.sailing.gwt.ui.client.RaceSelectionChangeListener;
|
import com.sap.sailing.gwt.ui.client.RaceSelectionChangeListener;
|
||||||
import com.sap.sailing.gwt.ui.client.RaceSelectionProvider;
|
import com.sap.sailing.gwt.ui.client.RaceSelectionProvider;
|
||||||
@@ -50,7 +51,6 @@ import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
|||||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||||
import com.sap.sailing.gwt.ui.client.shared.components.Component;
|
import com.sap.sailing.gwt.ui.client.shared.components.Component;
|
||||||
import com.sap.sailing.gwt.ui.client.shared.components.SettingsDialogComponent;
|
import com.sap.sailing.gwt.ui.client.shared.components.SettingsDialogComponent;
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
||||||
|
|
||||||
public abstract class AbstractTrackedRacesListComposite extends SimplePanel implements Component<TrackedRacesSettings>,
|
public abstract class AbstractTrackedRacesListComposite extends SimplePanel implements Component<TrackedRacesSettings>,
|
||||||
|
|||||||
+2
-2
@@ -8,11 +8,11 @@ import com.google.gwt.user.client.ui.Label;
|
|||||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||||
import com.google.gwt.user.client.ui.Widget;
|
import com.google.gwt.user.client.ui.Widget;
|
||||||
import com.google.gwt.user.datepicker.client.DateBox;
|
import com.google.gwt.user.datepicker.client.DateBox;
|
||||||
|
import com.sap.sailing.domain.common.dto.PositionDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.RaceDTO;
|
||||||
import com.sap.sailing.gwt.ui.client.DataEntryDialog;
|
import com.sap.sailing.gwt.ui.client.DataEntryDialog;
|
||||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||||
import com.sap.sailing.gwt.ui.shared.CoursePositionsDTO;
|
import com.sap.sailing.gwt.ui.shared.CoursePositionsDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.PositionDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.WindDTO;
|
import com.sap.sailing.gwt.ui.shared.WindDTO;
|
||||||
|
|
||||||
public class AddWindFixDialog extends DataEntryDialog<WindDTO> {
|
public class AddWindFixDialog extends DataEntryDialog<WindDTO> {
|
||||||
|
|||||||
+3
-3
@@ -47,6 +47,9 @@ import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
|||||||
import com.sap.sailing.domain.common.RegattaIdentifier;
|
import com.sap.sailing.domain.common.RegattaIdentifier;
|
||||||
import com.sap.sailing.domain.common.RegattaName;
|
import com.sap.sailing.domain.common.RegattaName;
|
||||||
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
||||||
|
import com.sap.sailing.domain.common.dto.AbstractLeaderboardDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.FleetDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
|
||||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||||
import com.sap.sailing.gwt.ui.adminconsole.DisablableCheckboxCell.IsEnabled;
|
import com.sap.sailing.gwt.ui.adminconsole.DisablableCheckboxCell.IsEnabled;
|
||||||
import com.sap.sailing.gwt.ui.adminconsole.RaceColumnInLeaderboardDialog.RaceColumnDescriptor;
|
import com.sap.sailing.gwt.ui.adminconsole.RaceColumnInLeaderboardDialog.RaceColumnDescriptor;
|
||||||
@@ -65,10 +68,7 @@ import com.sap.sailing.gwt.ui.client.URLEncoder;
|
|||||||
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardEntryPoint;
|
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardEntryPoint;
|
||||||
import com.sap.sailing.gwt.ui.leaderboard.ScoringSchemeTypeFormatter;
|
import com.sap.sailing.gwt.ui.leaderboard.ScoringSchemeTypeFormatter;
|
||||||
import com.sap.sailing.gwt.ui.raceboard.RaceBoardViewConfiguration;
|
import com.sap.sailing.gwt.ui.raceboard.RaceBoardViewConfiguration;
|
||||||
import com.sap.sailing.gwt.ui.shared.AbstractLeaderboardDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.EventDTO;
|
import com.sap.sailing.gwt.ui.shared.EventDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.FleetDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceColumnDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
|
import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -35,6 +35,7 @@ import com.google.gwt.view.client.ListDataProvider;
|
|||||||
import com.google.gwt.view.client.MultiSelectionModel;
|
import com.google.gwt.view.client.MultiSelectionModel;
|
||||||
import com.google.gwt.view.client.SelectionChangeEvent;
|
import com.google.gwt.view.client.SelectionChangeEvent;
|
||||||
import com.google.gwt.view.client.SingleSelectionModel;
|
import com.google.gwt.view.client.SingleSelectionModel;
|
||||||
|
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
|
||||||
import com.sap.sailing.gwt.ui.adminconsole.LeaderboardConfigPanel.AnchorCell;
|
import com.sap.sailing.gwt.ui.adminconsole.LeaderboardConfigPanel.AnchorCell;
|
||||||
import com.sap.sailing.gwt.ui.adminconsole.LeaderboardGroupDialog.LeaderboardGroupDescriptor;
|
import com.sap.sailing.gwt.ui.adminconsole.LeaderboardGroupDialog.LeaderboardGroupDescriptor;
|
||||||
import com.sap.sailing.gwt.ui.client.AbstractRegattaPanel;
|
import com.sap.sailing.gwt.ui.client.AbstractRegattaPanel;
|
||||||
@@ -47,7 +48,6 @@ import com.sap.sailing.gwt.ui.client.URLEncoder;
|
|||||||
import com.sap.sailing.gwt.ui.leaderboard.ScoringSchemeTypeFormatter;
|
import com.sap.sailing.gwt.ui.leaderboard.ScoringSchemeTypeFormatter;
|
||||||
import com.sap.sailing.gwt.ui.raceboard.RaceBoardViewConfiguration;
|
import com.sap.sailing.gwt.ui.raceboard.RaceBoardViewConfiguration;
|
||||||
import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO;
|
import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceColumnDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
|
import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -8,9 +8,9 @@ import com.google.gwt.user.client.ui.Label;
|
|||||||
import com.google.gwt.user.client.ui.TextBox;
|
import com.google.gwt.user.client.ui.TextBox;
|
||||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||||
import com.google.gwt.user.client.ui.Widget;
|
import com.google.gwt.user.client.ui.Widget;
|
||||||
|
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
|
||||||
import com.sap.sailing.gwt.ui.client.DataEntryDialog;
|
import com.sap.sailing.gwt.ui.client.DataEntryDialog;
|
||||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceColumnDTO;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fills a {@link RaceColumnDTO} object by setting its {@link RaceColumnDTO#setMedalRace(boolean) medal race} property,
|
* Fills a {@link RaceColumnDTO} object by setting its {@link RaceColumnDTO#setMedalRace(boolean) medal race} property,
|
||||||
|
|||||||
+1
-1
@@ -16,10 +16,10 @@ import com.google.gwt.user.client.ui.ListBox;
|
|||||||
import com.google.gwt.user.client.ui.TextBox;
|
import com.google.gwt.user.client.ui.TextBox;
|
||||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||||
import com.google.gwt.user.client.ui.Widget;
|
import com.google.gwt.user.client.ui.Widget;
|
||||||
|
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
|
||||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||||
import com.sap.sailing.gwt.ui.client.DataEntryDialog;
|
import com.sap.sailing.gwt.ui.client.DataEntryDialog;
|
||||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceColumnDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.SeriesDTO;
|
import com.sap.sailing.gwt.ui.shared.SeriesDTO;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -16,9 +16,9 @@ import com.google.gwt.user.client.ui.ListBox;
|
|||||||
import com.google.gwt.user.client.ui.TextBox;
|
import com.google.gwt.user.client.ui.TextBox;
|
||||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||||
import com.google.gwt.user.client.ui.Widget;
|
import com.google.gwt.user.client.ui.Widget;
|
||||||
|
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
|
||||||
import com.sap.sailing.gwt.ui.client.DataEntryDialog;
|
import com.sap.sailing.gwt.ui.client.DataEntryDialog;
|
||||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceColumnDTO;
|
|
||||||
|
|
||||||
public class RaceColumnsInLeaderboardDialog extends DataEntryDialog<List<RaceColumnDTO>> {
|
public class RaceColumnsInLeaderboardDialog extends DataEntryDialog<List<RaceColumnDTO>> {
|
||||||
private final ListBox addRacesListBox;
|
private final ListBox addRacesListBox;
|
||||||
|
|||||||
+3
-1
@@ -14,6 +14,7 @@ import com.google.gwt.core.client.GWT;
|
|||||||
import com.google.gwt.dom.client.Style.FontWeight;
|
import com.google.gwt.dom.client.Style.FontWeight;
|
||||||
import com.google.gwt.event.dom.client.ClickEvent;
|
import com.google.gwt.event.dom.client.ClickEvent;
|
||||||
import com.google.gwt.event.dom.client.ClickHandler;
|
import com.google.gwt.event.dom.client.ClickHandler;
|
||||||
|
import com.google.gwt.i18n.client.NumberFormat;
|
||||||
import com.google.gwt.safehtml.shared.SafeHtml;
|
import com.google.gwt.safehtml.shared.SafeHtml;
|
||||||
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
|
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
|
||||||
import com.google.gwt.user.cellview.client.CellTable;
|
import com.google.gwt.user.cellview.client.CellTable;
|
||||||
@@ -416,7 +417,8 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
|
|||||||
public SafeHtml getValue(MarkDTO mark) {
|
public SafeHtml getValue(MarkDTO mark) {
|
||||||
SafeHtmlBuilder builder = new SafeHtmlBuilder();
|
SafeHtmlBuilder builder = new SafeHtmlBuilder();
|
||||||
if(mark.position != null) {
|
if(mark.position != null) {
|
||||||
builder.appendEscaped(mark.position.toFormattedString());
|
NumberFormat fmt = NumberFormat.getFormat("#.###");
|
||||||
|
builder.appendEscaped(fmt.format(mark.position.latDeg)+", "+fmt.format(mark.position.lngDeg));
|
||||||
}
|
}
|
||||||
return builder.toSafeHtml();
|
return builder.toSafeHtml();
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -17,12 +17,12 @@ import com.google.gwt.user.client.ui.ListBox;
|
|||||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||||
import com.sap.sailing.domain.common.RaceIdentifier;
|
import com.sap.sailing.domain.common.RaceIdentifier;
|
||||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||||
|
import com.sap.sailing.domain.common.dto.RaceDTO;
|
||||||
import com.sap.sailing.gwt.ui.client.RaceSelectionChangeListener;
|
import com.sap.sailing.gwt.ui.client.RaceSelectionChangeListener;
|
||||||
import com.sap.sailing.gwt.ui.client.RaceSelectionProvider;
|
import com.sap.sailing.gwt.ui.client.RaceSelectionProvider;
|
||||||
import com.sap.sailing.gwt.ui.client.RegattaDisplayer;
|
import com.sap.sailing.gwt.ui.client.RegattaDisplayer;
|
||||||
import com.sap.sailing.gwt.ui.client.RegattaRefresher;
|
import com.sap.sailing.gwt.ui.client.RegattaRefresher;
|
||||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
||||||
|
|
||||||
public class RacesListBoxPanel extends FormPanel implements RegattaDisplayer, RaceSelectionChangeListener {
|
public class RacesListBoxPanel extends FormPanel implements RegattaDisplayer, RaceSelectionChangeListener {
|
||||||
|
|||||||
+3
-3
@@ -21,6 +21,9 @@ import com.google.gwt.view.client.SingleSelectionModel;
|
|||||||
import com.sap.sailing.domain.common.RegattaIdentifier;
|
import com.sap.sailing.domain.common.RegattaIdentifier;
|
||||||
import com.sap.sailing.domain.common.RegattaName;
|
import com.sap.sailing.domain.common.RegattaName;
|
||||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||||
|
import com.sap.sailing.domain.common.dto.FleetDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.RaceColumnInSeriesDTO;
|
||||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||||
import com.sap.sailing.gwt.ui.client.ErrorReporter;
|
import com.sap.sailing.gwt.ui.client.ErrorReporter;
|
||||||
import com.sap.sailing.gwt.ui.client.RegattaRefresher;
|
import com.sap.sailing.gwt.ui.client.RegattaRefresher;
|
||||||
@@ -28,9 +31,6 @@ import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
|||||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||||
import com.sap.sailing.gwt.ui.client.DataEntryDialog.DialogCallback;
|
import com.sap.sailing.gwt.ui.client.DataEntryDialog.DialogCallback;
|
||||||
import com.sap.sailing.gwt.ui.leaderboard.ScoringSchemeTypeFormatter;
|
import com.sap.sailing.gwt.ui.leaderboard.ScoringSchemeTypeFormatter;
|
||||||
import com.sap.sailing.gwt.ui.shared.FleetDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceColumnDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceColumnInSeriesDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.SeriesDTO;
|
import com.sap.sailing.gwt.ui.shared.SeriesDTO;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -17,6 +17,7 @@ import com.google.gwt.user.client.ui.SimplePanel;
|
|||||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||||
import com.sap.sailing.domain.common.Color;
|
import com.sap.sailing.domain.common.Color;
|
||||||
import com.sap.sailing.domain.common.RegattaIdentifier;
|
import com.sap.sailing.domain.common.RegattaIdentifier;
|
||||||
|
import com.sap.sailing.domain.common.dto.FleetDTO;
|
||||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||||
import com.sap.sailing.domain.common.impl.Util.Triple;
|
import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||||
import com.sap.sailing.gwt.ui.client.DataEntryDialog.DialogCallback;
|
import com.sap.sailing.gwt.ui.client.DataEntryDialog.DialogCallback;
|
||||||
@@ -29,7 +30,6 @@ import com.sap.sailing.gwt.ui.client.RegattaSelectionProvider;
|
|||||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||||
import com.sap.sailing.gwt.ui.shared.EventDTO;
|
import com.sap.sailing.gwt.ui.shared.EventDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.FleetDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.SeriesDTO;
|
import com.sap.sailing.gwt.ui.shared.SeriesDTO;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -19,10 +19,10 @@ import com.google.gwt.user.client.ui.TextBox;
|
|||||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||||
import com.google.gwt.user.client.ui.Widget;
|
import com.google.gwt.user.client.ui.Widget;
|
||||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||||
|
import com.sap.sailing.domain.common.dto.BoatClassDTO;
|
||||||
import com.sap.sailing.gwt.ui.client.DataEntryDialog;
|
import com.sap.sailing.gwt.ui.client.DataEntryDialog;
|
||||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||||
import com.sap.sailing.gwt.ui.leaderboard.ScoringSchemeTypeFormatter;
|
import com.sap.sailing.gwt.ui.leaderboard.ScoringSchemeTypeFormatter;
|
||||||
import com.sap.sailing.gwt.ui.shared.BoatClassDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.CourseAreaDTO;
|
import com.sap.sailing.gwt.ui.shared.CourseAreaDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.EventDTO;
|
import com.sap.sailing.gwt.ui.shared.EventDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
||||||
|
|||||||
+1
-1
@@ -19,9 +19,9 @@ import com.google.gwt.user.client.ui.TextBox;
|
|||||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||||
import com.google.gwt.user.client.ui.Widget;
|
import com.google.gwt.user.client.ui.Widget;
|
||||||
import com.sap.sailing.domain.common.Color;
|
import com.sap.sailing.domain.common.Color;
|
||||||
|
import com.sap.sailing.domain.common.dto.FleetDTO;
|
||||||
import com.sap.sailing.gwt.ui.client.DataEntryDialog;
|
import com.sap.sailing.gwt.ui.client.DataEntryDialog;
|
||||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||||
import com.sap.sailing.gwt.ui.shared.FleetDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.SeriesDTO;
|
import com.sap.sailing.gwt.ui.shared.SeriesDTO;
|
||||||
|
|
||||||
public class SeriesWithFleetsCreateDialog extends DataEntryDialog<SeriesDTO> {
|
public class SeriesWithFleetsCreateDialog extends DataEntryDialog<SeriesDTO> {
|
||||||
|
|||||||
+1
-1
@@ -12,6 +12,7 @@ import com.google.gwt.user.client.ui.Button;
|
|||||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||||
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
||||||
|
import com.sap.sailing.domain.common.dto.RaceDTO;
|
||||||
import com.sap.sailing.gwt.ui.client.ErrorReporter;
|
import com.sap.sailing.gwt.ui.client.ErrorReporter;
|
||||||
import com.sap.sailing.gwt.ui.client.RaceSelectionProvider;
|
import com.sap.sailing.gwt.ui.client.RaceSelectionProvider;
|
||||||
import com.sap.sailing.gwt.ui.client.RegattaDisplayer;
|
import com.sap.sailing.gwt.ui.client.RegattaDisplayer;
|
||||||
@@ -19,7 +20,6 @@ import com.sap.sailing.gwt.ui.client.RegattaRefresher;
|
|||||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||||
import com.sap.sailing.gwt.ui.client.shared.components.SettingsDialog;
|
import com.sap.sailing.gwt.ui.client.shared.components.SettingsDialog;
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+1
-1
@@ -34,6 +34,7 @@ import com.google.gwt.view.client.ListDataProvider;
|
|||||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||||
import com.sap.sailing.domain.common.WindSource;
|
import com.sap.sailing.domain.common.WindSource;
|
||||||
import com.sap.sailing.domain.common.WindSourceType;
|
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.domain.common.impl.WindSourceImpl;
|
||||||
import com.sap.sailing.gwt.ui.actions.AsyncActionsExecutor;
|
import com.sap.sailing.gwt.ui.actions.AsyncActionsExecutor;
|
||||||
import com.sap.sailing.gwt.ui.client.DataEntryDialog.DialogCallback;
|
import com.sap.sailing.gwt.ui.client.DataEntryDialog.DialogCallback;
|
||||||
@@ -46,7 +47,6 @@ import com.sap.sailing.gwt.ui.client.RegattaRefresher;
|
|||||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||||
import com.sap.sailing.gwt.ui.shared.CoursePositionsDTO;
|
import com.sap.sailing.gwt.ui.shared.CoursePositionsDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.WindDTO;
|
import com.sap.sailing.gwt.ui.shared.WindDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
|
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
|
||||||
|
|||||||
+2
-4
@@ -62,7 +62,7 @@ public abstract class AbstractEntryPoint implements EntryPoint, ErrorReporter, W
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void onModuleLoad() {
|
public final void onModuleLoad() {
|
||||||
if(DebugInfo.isDebugIdEnabled()) {
|
if (DebugInfo.isDebugIdEnabled()) {
|
||||||
PendingAjaxCallBundle bundle = GWT.create(PendingAjaxCallBundle.class);
|
PendingAjaxCallBundle bundle = GWT.create(PendingAjaxCallBundle.class);
|
||||||
TextResource script = bundle.ajaxSemaphoreJS();
|
TextResource script = bundle.ajaxSemaphoreJS();
|
||||||
JavaScriptInjector.inject(script.getText());
|
JavaScriptInjector.inject(script.getText());
|
||||||
@@ -70,10 +70,8 @@ public abstract class AbstractEntryPoint implements EntryPoint, ErrorReporter, W
|
|||||||
DebugInfo.setDebugIdAttribute(DEBUG_ID_ATTRIBUTE, false);
|
DebugInfo.setDebugIdAttribute(DEBUG_ID_ATTRIBUTE, false);
|
||||||
DebugInfo.setDebugIdPrefix(DEBUG_ID_PREFIX);
|
DebugInfo.setDebugIdPrefix(DEBUG_ID_PREFIX);
|
||||||
}
|
}
|
||||||
|
|
||||||
doOnModuleLoad();
|
doOnModuleLoad();
|
||||||
|
if (DebugInfo.isDebugIdEnabled()) {
|
||||||
if(DebugInfo.isDebugIdEnabled()) {
|
|
||||||
PendingAjaxCallMarker.decrementPendingAjaxCalls(MarkedAsyncCallback.CATEGORY_GLOBAL);
|
PendingAjaxCallMarker.decrementPendingAjaxCalls(MarkedAsyncCallback.CATEGORY_GLOBAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
package com.sap.sailing.gwt.ui.client;
|
package com.sap.sailing.gwt.ui.client;
|
||||||
|
|
||||||
import com.sap.sailing.gwt.ui.shared.CompetitorDTO;
|
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@ import java.util.Set;
|
|||||||
|
|
||||||
import com.sap.sailing.domain.common.filter.Filter;
|
import com.sap.sailing.domain.common.filter.Filter;
|
||||||
import com.sap.sailing.domain.common.filter.FilterSet;
|
import com.sap.sailing.domain.common.filter.FilterSet;
|
||||||
import com.sap.sailing.gwt.ui.shared.CompetitorDTO;
|
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||||
|
|
||||||
public class CompetitorSelectionModel implements CompetitorSelectionProvider {
|
public class CompetitorSelectionModel implements CompetitorSelectionProvider {
|
||||||
private final Set<CompetitorDTO> allCompetitors;
|
private final Set<CompetitorDTO> allCompetitors;
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@ package com.sap.sailing.gwt.ui.client;
|
|||||||
|
|
||||||
import com.sap.sailing.domain.common.filter.Filter;
|
import com.sap.sailing.domain.common.filter.Filter;
|
||||||
import com.sap.sailing.domain.common.filter.FilterSet;
|
import com.sap.sailing.domain.common.filter.FilterSet;
|
||||||
import com.sap.sailing.gwt.ui.shared.CompetitorDTO;
|
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||||
|
|
||||||
public interface CompetitorSelectionProvider {
|
public interface CompetitorSelectionProvider {
|
||||||
|
|
||||||
|
|||||||
Executable → Regular
+3
-3
@@ -13,9 +13,9 @@ import com.google.gwt.core.client.Scheduler.RepeatingCommand;
|
|||||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||||
import com.sap.sailing.domain.common.RaceIdentifier;
|
import com.sap.sailing.domain.common.RaceIdentifier;
|
||||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||||
import com.sap.sailing.gwt.ui.shared.FleetDTO;
|
import com.sap.sailing.domain.common.dto.FleetDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.LeaderboardDTO;
|
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceColumnDTO;
|
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO;
|
import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO;
|
||||||
|
|
||||||
public class RaceTimesInfoProvider {
|
public class RaceTimesInfoProvider {
|
||||||
|
|||||||
+4
-4
@@ -22,23 +22,23 @@ import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
|||||||
import com.sap.sailing.domain.common.RegattaIdentifier;
|
import com.sap.sailing.domain.common.RegattaIdentifier;
|
||||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||||
import com.sap.sailing.domain.common.WindSource;
|
import com.sap.sailing.domain.common.WindSource;
|
||||||
|
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.RaceColumnInSeriesDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.RaceDTO;
|
||||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||||
import com.sap.sailing.domain.common.impl.Util.Triple;
|
import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||||
import com.sap.sailing.gwt.ui.shared.BulkScoreCorrectionDTO;
|
import com.sap.sailing.gwt.ui.shared.BulkScoreCorrectionDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.CompactRaceMapDataDTO;
|
import com.sap.sailing.gwt.ui.shared.CompactRaceMapDataDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.CompetitorDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.CompetitorsRaceDataDTO;
|
import com.sap.sailing.gwt.ui.shared.CompetitorsRaceDataDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.ControlPointDTO;
|
import com.sap.sailing.gwt.ui.shared.ControlPointDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.CourseAreaDTO;
|
import com.sap.sailing.gwt.ui.shared.CourseAreaDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.CoursePositionsDTO;
|
import com.sap.sailing.gwt.ui.shared.CoursePositionsDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.EventDTO;
|
import com.sap.sailing.gwt.ui.shared.EventDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.GPSFixDTO;
|
import com.sap.sailing.gwt.ui.shared.GPSFixDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.LeaderboardDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO;
|
import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.ManeuverDTO;
|
import com.sap.sailing.gwt.ui.shared.ManeuverDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceColumnInSeriesDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceCourseDTO;
|
import com.sap.sailing.gwt.ui.shared.RaceCourseDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO;
|
import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.RegattaOverviewEntryDTO;
|
import com.sap.sailing.gwt.ui.shared.RegattaOverviewEntryDTO;
|
||||||
|
|||||||
+5
-5
@@ -22,24 +22,24 @@ import com.sap.sailing.domain.common.RegattaIdentifier;
|
|||||||
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
||||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||||
import com.sap.sailing.domain.common.WindSource;
|
import com.sap.sailing.domain.common.WindSource;
|
||||||
|
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.LeaderboardEntryDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.RaceColumnInSeriesDTO;
|
||||||
|
import com.sap.sailing.domain.common.dto.RaceDTO;
|
||||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||||
import com.sap.sailing.domain.common.impl.Util.Triple;
|
import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||||
import com.sap.sailing.gwt.ui.shared.BulkScoreCorrectionDTO;
|
import com.sap.sailing.gwt.ui.shared.BulkScoreCorrectionDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.CompactRaceMapDataDTO;
|
import com.sap.sailing.gwt.ui.shared.CompactRaceMapDataDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.CompetitorDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.CompetitorsRaceDataDTO;
|
import com.sap.sailing.gwt.ui.shared.CompetitorsRaceDataDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.ControlPointDTO;
|
import com.sap.sailing.gwt.ui.shared.ControlPointDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.CourseAreaDTO;
|
import com.sap.sailing.gwt.ui.shared.CourseAreaDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.CoursePositionsDTO;
|
import com.sap.sailing.gwt.ui.shared.CoursePositionsDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.EventDTO;
|
import com.sap.sailing.gwt.ui.shared.EventDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.GPSFixDTO;
|
import com.sap.sailing.gwt.ui.shared.GPSFixDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.LeaderboardDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.LeaderboardEntryDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO;
|
import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.ManeuverDTO;
|
import com.sap.sailing.gwt.ui.shared.ManeuverDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceColumnInSeriesDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceCourseDTO;
|
import com.sap.sailing.gwt.ui.shared.RaceCourseDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO;
|
import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.RegattaOverviewEntryDTO;
|
import com.sap.sailing.gwt.ui.shared.RegattaOverviewEntryDTO;
|
||||||
|
|||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
package com.sap.sailing.gwt.ui.client;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.google.gwt.user.client.rpc.RemoteService;
|
||||||
|
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
|
||||||
|
import com.sap.sailing.domain.common.dto.PositionDTO;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.BoatClassDTOsAndNotificationMessage;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.ConfigurationException;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.PolarDiagramDTOAndNotificationMessage;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.Request1TurnerDTO;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.RequestTotalTimeDTO;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.Response1TurnerDTO;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.ResponseTotalTimeDTO;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.SimulatorResultsDTO;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.SimulatorUISelectionDTO;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.WindFieldDTO;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.WindFieldGenParamsDTO;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.WindLatticeDTO;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.WindLatticeGenParamsDTO;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.WindPatternDTO;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.windpattern.WindPatternDisplay;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.windpattern.WindPatternNotFoundException;
|
||||||
|
|
||||||
|
@RemoteServiceRelativePath("simulator")
|
||||||
|
public interface SimulatorService extends RemoteService {
|
||||||
|
|
||||||
|
PositionDTO[] getRaceLocations();
|
||||||
|
|
||||||
|
WindLatticeDTO getWindLatice(WindLatticeGenParamsDTO params);
|
||||||
|
|
||||||
|
WindFieldDTO getWindField(WindFieldGenParamsDTO params, WindPatternDisplay pattern) throws WindPatternNotFoundException;
|
||||||
|
|
||||||
|
List<WindPatternDTO> getWindPatterns();
|
||||||
|
|
||||||
|
WindPatternDisplay getWindPatternDisplay(WindPatternDTO pattern);
|
||||||
|
|
||||||
|
SimulatorResultsDTO getSimulatorResults(char mode, WindFieldGenParamsDTO params, WindPatternDisplay pattern, boolean withWindField,
|
||||||
|
SimulatorUISelectionDTO selection) throws WindPatternNotFoundException, ConfigurationException;
|
||||||
|
|
||||||
|
BoatClassDTOsAndNotificationMessage getBoatClasses() throws ConfigurationException;
|
||||||
|
|
||||||
|
PolarDiagramDTOAndNotificationMessage getPolarDiagram(Double bearingStep, int boatClassIndex) throws ConfigurationException;
|
||||||
|
|
||||||
|
ResponseTotalTimeDTO getTotalTime(RequestTotalTimeDTO requestData) throws ConfigurationException;
|
||||||
|
|
||||||
|
Response1TurnerDTO get1Turner(Request1TurnerDTO requestData) throws ConfigurationException;
|
||||||
|
|
||||||
|
List<String> getLegsNames(int selectedRaceIndex);
|
||||||
|
|
||||||
|
List<String> getRacesNames();
|
||||||
|
|
||||||
|
List<String> getCompetitorsNames(int selectedRaceIndex);
|
||||||
|
}
|
||||||
+50
@@ -0,0 +1,50 @@
|
|||||||
|
package com.sap.sailing.gwt.ui.client;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||||
|
import com.sap.sailing.domain.common.dto.PositionDTO;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.BoatClassDTOsAndNotificationMessage;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.PolarDiagramDTOAndNotificationMessage;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.Request1TurnerDTO;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.RequestTotalTimeDTO;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.Response1TurnerDTO;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.ResponseTotalTimeDTO;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.SimulatorResultsDTO;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.SimulatorUISelectionDTO;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.WindFieldDTO;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.WindFieldGenParamsDTO;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.WindLatticeDTO;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.WindLatticeGenParamsDTO;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.WindPatternDTO;
|
||||||
|
import com.sap.sailing.gwt.ui.shared.windpattern.WindPatternDisplay;
|
||||||
|
|
||||||
|
public interface SimulatorServiceAsync {
|
||||||
|
|
||||||
|
void getRaceLocations(AsyncCallback<PositionDTO[]> callback);
|
||||||
|
|
||||||
|
void getWindLatice(WindLatticeGenParamsDTO params, AsyncCallback<WindLatticeDTO> callback);
|
||||||
|
|
||||||
|
void getWindField(WindFieldGenParamsDTO params, WindPatternDisplay display, AsyncCallback<WindFieldDTO> callback);
|
||||||
|
|
||||||
|
void getWindPatterns(AsyncCallback<List<WindPatternDTO>> callback);
|
||||||
|
|
||||||
|
void getWindPatternDisplay(WindPatternDTO pattern, AsyncCallback<WindPatternDisplay> callback);
|
||||||
|
|
||||||
|
void getBoatClasses(AsyncCallback<BoatClassDTOsAndNotificationMessage> callback);
|
||||||
|
|
||||||
|
void getPolarDiagram(Double bearingStep, int boatClassIndex, AsyncCallback<PolarDiagramDTOAndNotificationMessage> callback);
|
||||||
|
|
||||||
|
void getTotalTime(RequestTotalTimeDTO requestData, AsyncCallback<ResponseTotalTimeDTO> asyncCallback);
|
||||||
|
|
||||||
|
void get1Turner(final Request1TurnerDTO requestData, AsyncCallback<Response1TurnerDTO> asyncCallback);
|
||||||
|
|
||||||
|
void getLegsNames(int selectedRaceIndex, AsyncCallback<List<String>> asyncCallback);
|
||||||
|
|
||||||
|
void getRacesNames(AsyncCallback<List<String>> asyncCallback);
|
||||||
|
|
||||||
|
void getSimulatorResults(char mode, WindFieldGenParamsDTO params, WindPatternDisplay pattern, boolean withWindField, SimulatorUISelectionDTO selection,
|
||||||
|
AsyncCallback<SimulatorResultsDTO> callback);
|
||||||
|
|
||||||
|
void getCompetitorsNames(int selectedRaceIndex, AsyncCallback<List<String>> asyncCallback);
|
||||||
|
}
|
||||||
+1
-1
@@ -13,7 +13,7 @@ import com.google.gwt.user.client.ui.VerticalPanel;
|
|||||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||||
import com.sap.sailing.domain.common.WindSource;
|
import com.sap.sailing.domain.common.WindSource;
|
||||||
import com.sap.sailing.domain.common.WindSourceType;
|
import com.sap.sailing.domain.common.WindSourceType;
|
||||||
import com.sap.sailing.gwt.ui.shared.PositionDTO;
|
import com.sap.sailing.domain.common.dto.PositionDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.WindDTO;
|
import com.sap.sailing.gwt.ui.shared.WindDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
|
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.WindTrackInfoDTO;
|
import com.sap.sailing.gwt.ui.shared.WindTrackInfoDTO;
|
||||||
|
|||||||
+47
@@ -588,4 +588,51 @@ public interface StringMessages extends Messages {
|
|||||||
String filterNothing();
|
String filterNothing();
|
||||||
String topNCompetitorsByRaceRank(int n);
|
String topNCompetitorsByRaceRank(int n);
|
||||||
String topNCompetitorsByTotalRank(int n);
|
String topNCompetitorsByTotalRank(int n);
|
||||||
|
|
||||||
|
/*Start of simulator related messages*/
|
||||||
|
String simulator();
|
||||||
|
String optionsBar();
|
||||||
|
String update();
|
||||||
|
|
||||||
|
String setup();
|
||||||
|
String strength();
|
||||||
|
String oscillation();
|
||||||
|
String oscillating();
|
||||||
|
String amplitude();
|
||||||
|
String frequency();
|
||||||
|
String noise();
|
||||||
|
|
||||||
|
String sailing();
|
||||||
|
String optimality();
|
||||||
|
String maximumTurns();
|
||||||
|
String raceDirection();
|
||||||
|
String upWind();
|
||||||
|
String downWind();
|
||||||
|
String strategies();
|
||||||
|
String omniscient();
|
||||||
|
String opportunistic();
|
||||||
|
String mixed();
|
||||||
|
String maps();
|
||||||
|
String startEnd();
|
||||||
|
String racecourse();
|
||||||
|
String summary();
|
||||||
|
String replay();
|
||||||
|
String display();
|
||||||
|
|
||||||
|
String simulatorPolarHeader();
|
||||||
|
String show();
|
||||||
|
String hide();
|
||||||
|
|
||||||
|
String leftWind();
|
||||||
|
String rightWind();
|
||||||
|
String strategyOption1();
|
||||||
|
String strategyOption2();
|
||||||
|
String strategyOption3();
|
||||||
|
String legLabel();
|
||||||
|
String raceLabel();
|
||||||
|
String competitorLabel();
|
||||||
|
|
||||||
|
String freemode();
|
||||||
|
String whatIfCourse();
|
||||||
|
/*End of simulator related messages*/
|
||||||
}
|
}
|
||||||
|
|||||||
+40
-1
@@ -583,7 +583,7 @@ nationalityMustBeISOorIOCcode=The nationality must be a two letter ISO code or a
|
|||||||
raceRank=Race rank
|
raceRank=Race rank
|
||||||
waypoints=Waypoints
|
waypoints=Waypoints
|
||||||
disableRaceFilter=Disable filter
|
disableRaceFilter=Disable filter
|
||||||
enableRaceFilter=Enable filter
|
enableRaceFilter=Enable filter
|
||||||
raceStatusColumn=Race Status
|
raceStatusColumn=Race Status
|
||||||
loading=Loading (on a slow internet connection this can take some minutes)...
|
loading=Loading (on a slow internet connection this can take some minutes)...
|
||||||
showHiddenRaces=Show HIDDEN races
|
showHiddenRaces=Show HIDDEN races
|
||||||
@@ -591,3 +591,42 @@ selectedCompetitors=Selected competitors
|
|||||||
filterNothing=Filter nothing
|
filterNothing=Filter nothing
|
||||||
topNCompetitorsByRaceRank=Race Top {0}
|
topNCompetitorsByRaceRank=Race Top {0}
|
||||||
topNCompetitorsByTotalRank=Total Top {0}
|
topNCompetitorsByTotalRank=Total Top {0}
|
||||||
|
simulator=Simulator
|
||||||
|
optionsBar=Optionsbar
|
||||||
|
update=Update
|
||||||
|
setup=Setup
|
||||||
|
strength=Strength (in kn)
|
||||||
|
oscillation=Oscillation
|
||||||
|
oscillating=Oscillating
|
||||||
|
amplitude=Amplitude(in Grad)
|
||||||
|
frequency=Frequency(in 1/h)
|
||||||
|
noise=Noise
|
||||||
|
sailing=Sailing
|
||||||
|
optimality=Optimality
|
||||||
|
maximumTurns=Maximum Turns
|
||||||
|
raceDirection=Race Direction
|
||||||
|
upWind=Upwind
|
||||||
|
downWind=Downwind
|
||||||
|
strategies=Strategies
|
||||||
|
omniscient=Omniscient
|
||||||
|
opportunistic=Opportunistic
|
||||||
|
mixed=Mixed
|
||||||
|
maps=Maps
|
||||||
|
startEnd=Start-End
|
||||||
|
racecourse=Course
|
||||||
|
summary=Summary
|
||||||
|
replay=Replay
|
||||||
|
display=Display
|
||||||
|
simulatorPolarHeader = Polar diagram
|
||||||
|
show = Show
|
||||||
|
hide = hide
|
||||||
|
leftWind=Left wind
|
||||||
|
rightWind=Right wind
|
||||||
|
strategyOption1=strategyOption1
|
||||||
|
strategyOption2=strategyOption2
|
||||||
|
strategyOption3=strategyOption3
|
||||||
|
legLabel=Leg
|
||||||
|
raceLabel=Race
|
||||||
|
competitorLabel=Competitor
|
||||||
|
freemode=Keep Bearings
|
||||||
|
whatIfCourse=What-If Course
|
||||||
|
|||||||
+41
-1
@@ -581,7 +581,7 @@ nationalityMustBeISOorIOCcode=Die Nationaltät muß als ISO-Code (2 Zeichen) ode
|
|||||||
raceRank=Wettfahrtrang
|
raceRank=Wettfahrtrang
|
||||||
waypoints=Wegpunkte
|
waypoints=Wegpunkte
|
||||||
disableRaceFilter=Deaktiviere Filter
|
disableRaceFilter=Deaktiviere Filter
|
||||||
enableRaceFilter=Aktiviere Filter
|
enableRaceFilter=Aktiviere Filter
|
||||||
raceStatusColumn=Renn-Status
|
raceStatusColumn=Renn-Status
|
||||||
loading=Lade...
|
loading=Lade...
|
||||||
showHiddenRaces=Rennen im Status HIDDEN anzeigen
|
showHiddenRaces=Rennen im Status HIDDEN anzeigen
|
||||||
@@ -589,3 +589,43 @@ selectedCompetitors=Ausgewählte Teilnehmer
|
|||||||
filterNothing=Nichts filtern
|
filterNothing=Nichts filtern
|
||||||
topNCompetitorsByRaceRank=Wettfahrt Top {0}
|
topNCompetitorsByRaceRank=Wettfahrt Top {0}
|
||||||
topNCompetitorsByTotalRank=Gesamt Top {0}
|
topNCompetitorsByTotalRank=Gesamt Top {0}
|
||||||
|
showHiddenRaces=Rennen im Status HIDDEN anzeigen
|
||||||
|
simulator=Simulator
|
||||||
|
optionsBar=Optionsbar
|
||||||
|
update=Update
|
||||||
|
setup=Setup
|
||||||
|
strength=Strength(in kn)
|
||||||
|
oscillation=Oscillation
|
||||||
|
oscillating=Oscillating
|
||||||
|
amplitude=Amplitude(in Grad)
|
||||||
|
frequency=Frequency(in 1/h)
|
||||||
|
noise=Noise
|
||||||
|
sailing=Sailing
|
||||||
|
optimality=Optimality
|
||||||
|
maximumTurns=Maximum Turns
|
||||||
|
raceDirection=Race Direction
|
||||||
|
upWind=Upwind
|
||||||
|
downWind=Downwind
|
||||||
|
strategies=Strategies
|
||||||
|
omniscient=Omniscient
|
||||||
|
opportunistic=Opportunistic
|
||||||
|
mixed=Mixed
|
||||||
|
maps=Maps
|
||||||
|
startEnd=Start-End
|
||||||
|
racecourse=Course
|
||||||
|
summary=Summary
|
||||||
|
replay=Replay
|
||||||
|
display=Display
|
||||||
|
simulatorPolarHeader = Polardiagramm
|
||||||
|
show = zeigen
|
||||||
|
hide = verbergen
|
||||||
|
leftWind=Left wind
|
||||||
|
rightWind=Right wind
|
||||||
|
strategyOption1=strategyOption1
|
||||||
|
strategyOption2=strategyOption2
|
||||||
|
strategyOption3=strategyOption3
|
||||||
|
legLabel=Leg
|
||||||
|
raceLabel=Race
|
||||||
|
competitorLabel=Competitor
|
||||||
|
freemode=Winkel erhalten
|
||||||
|
whatIfCourse=What-If Course
|
||||||
|
|||||||
+6
-4
@@ -211,7 +211,7 @@ public class TimePanel<T extends TimePanelSettings> extends SimplePanel implemen
|
|||||||
playSpeedBox.setVisibleLength(3);
|
playSpeedBox.setVisibleLength(3);
|
||||||
playSpeedBox.setWidth("25px");
|
playSpeedBox.setWidth("25px");
|
||||||
playSpeedBox.setHeight("14px");
|
playSpeedBox.setHeight("14px");
|
||||||
playSpeedBox.setValue(1);
|
playSpeedBox.setValue((int)timer.getPlaySpeedFactor()); // Christopher: initialize play speed box according to play speed factor
|
||||||
playSpeedBox.setTitle(stringMessages.playSpeedHelp());
|
playSpeedBox.setTitle(stringMessages.playSpeedHelp());
|
||||||
playSpeedBox.addValueChangeHandler(new ValueChangeHandler<Integer>() {
|
playSpeedBox.addValueChangeHandler(new ValueChangeHandler<Integer>() {
|
||||||
@Override
|
@Override
|
||||||
@@ -338,9 +338,6 @@ public class TimePanel<T extends TimePanelSettings> extends SimplePanel implemen
|
|||||||
if (!min.equals(timeRangeProvider.getFromTime())) {
|
if (!min.equals(timeRangeProvider.getFromTime())) {
|
||||||
changed = true;
|
changed = true;
|
||||||
timeSlider.setMinValue(new Double(min.getTime()), fireEvent);
|
timeSlider.setMinValue(new Double(min.getTime()), fireEvent);
|
||||||
if (timeSlider.getCurrentValue() == null) {
|
|
||||||
timeSlider.setCurrentValue(new Double(min.getTime()), fireEvent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (changed) {
|
if (changed) {
|
||||||
if(!timeRangeProvider.isZoomed()) {
|
if(!timeRangeProvider.isZoomed()) {
|
||||||
@@ -353,6 +350,11 @@ public class TimePanel<T extends TimePanelSettings> extends SimplePanel implemen
|
|||||||
} else {
|
} else {
|
||||||
timeSlider.setStepSize(1000, fireEvent);
|
timeSlider.setStepSize(1000, fireEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Christopher: following setCurrentValue requires stepsize to be set <> 0 (otherwise division by zero; NaN)
|
||||||
|
if (timeSlider.getCurrentValue() == null) {
|
||||||
|
timeSlider.setCurrentValue(new Double(min.getTime()), fireEvent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -155,6 +155,10 @@ public class Timer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double getPlaySpeedFactor() {
|
||||||
|
return playSpeedFactor;
|
||||||
|
}
|
||||||
|
|
||||||
public void setRefreshInterval(long refreshIntervalInMillis) {
|
public void setRefreshInterval(long refreshIntervalInMillis) {
|
||||||
this.refreshInterval = refreshIntervalInMillis;
|
this.refreshInterval = refreshIntervalInMillis;
|
||||||
if (playState == PlayStates.Playing) {
|
if (playState == PlayStates.Playing) {
|
||||||
|
|||||||
+1
-1
@@ -37,6 +37,7 @@ import com.google.gwt.user.client.ui.Widget;
|
|||||||
import com.sap.sailing.domain.common.DetailType;
|
import com.sap.sailing.domain.common.DetailType;
|
||||||
import com.sap.sailing.domain.common.RaceIdentifier;
|
import com.sap.sailing.domain.common.RaceIdentifier;
|
||||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||||
|
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||||
import com.sap.sailing.domain.common.impl.Util;
|
import com.sap.sailing.domain.common.impl.Util;
|
||||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||||
import com.sap.sailing.domain.common.impl.Util.Triple;
|
import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||||
@@ -53,7 +54,6 @@ import com.sap.sailing.gwt.ui.client.TimeRangeWithZoomProvider;
|
|||||||
import com.sap.sailing.gwt.ui.client.Timer;
|
import com.sap.sailing.gwt.ui.client.Timer;
|
||||||
import com.sap.sailing.gwt.ui.client.Timer.PlayModes;
|
import com.sap.sailing.gwt.ui.client.Timer.PlayModes;
|
||||||
import com.sap.sailing.gwt.ui.client.shared.components.Component;
|
import com.sap.sailing.gwt.ui.client.shared.components.Component;
|
||||||
import com.sap.sailing.gwt.ui.shared.CompetitorDTO;
|
|
||||||
import com.sap.sailing.gwt.ui.shared.CompetitorRaceDataDTO;
|
import com.sap.sailing.gwt.ui.shared.CompetitorRaceDataDTO;
|
||||||
import com.sap.sailing.gwt.ui.shared.CompetitorsRaceDataDTO;
|
import com.sap.sailing.gwt.ui.shared.CompetitorsRaceDataDTO;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -29,6 +29,7 @@ import org.moxieapps.gwt.highcharts.client.plotOptions.Marker.Symbol;
|
|||||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||||
import com.google.gwt.user.client.ui.RequiresResize;
|
import com.google.gwt.user.client.ui.RequiresResize;
|
||||||
import com.google.gwt.user.client.ui.SimplePanel;
|
import com.google.gwt.user.client.ui.SimplePanel;
|
||||||
|
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||||
import com.sap.sailing.domain.common.impl.Util;
|
import com.sap.sailing.domain.common.impl.Util;
|
||||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||||
import com.sap.sailing.gwt.ui.client.CompetitorSelectionProvider;
|
import com.sap.sailing.gwt.ui.client.CompetitorSelectionProvider;
|
||||||
@@ -38,7 +39,6 @@ import com.sap.sailing.gwt.ui.client.StringMessages;
|
|||||||
import com.sap.sailing.gwt.ui.client.TimeListener;
|
import com.sap.sailing.gwt.ui.client.TimeListener;
|
||||||
import com.sap.sailing.gwt.ui.client.Timer;
|
import com.sap.sailing.gwt.ui.client.Timer;
|
||||||
import com.sap.sailing.gwt.ui.client.Timer.PlayModes;
|
import com.sap.sailing.gwt.ui.client.Timer.PlayModes;
|
||||||
import com.sap.sailing.gwt.ui.shared.CompetitorDTO;
|
|
||||||
|
|
||||||
public class LeaderboardRankChart extends SimplePanel implements RequiresResize, TimeListener {
|
public class LeaderboardRankChart extends SimplePanel implements RequiresResize, TimeListener {
|
||||||
private static final int LINE_WIDTH = 1;
|
private static final int LINE_WIDTH = 1;
|
||||||
|
|||||||
+218
-218
@@ -1,218 +1,218 @@
|
|||||||
package com.sap.sailing.gwt.ui.client.shared.controls.slider;
|
package com.sap.sailing.gwt.ui.client.shared.controls.slider;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.google.gwt.user.client.DOM;
|
import com.google.gwt.user.client.DOM;
|
||||||
import com.google.gwt.user.client.Element;
|
import com.google.gwt.user.client.Element;
|
||||||
import com.sap.sailing.gwt.ui.client.shared.controls.slider.TimeTicksCalculator.NormalizedInterval;
|
import com.sap.sailing.gwt.ui.client.shared.controls.slider.TimeTicksCalculator.NormalizedInterval;
|
||||||
import com.sap.sailing.gwt.ui.client.shared.controls.slider.TimeTicksCalculator.TickPosition;
|
import com.sap.sailing.gwt.ui.client.shared.controls.slider.TimeTicksCalculator.TickPosition;
|
||||||
|
|
||||||
public class TimeSlider extends SliderBar {
|
public class TimeSlider extends SliderBar {
|
||||||
|
|
||||||
private final TimeTicksCalculator calc = new TimeTicksCalculator();
|
private final TimeTicksCalculator calc = new TimeTicksCalculator();
|
||||||
|
|
||||||
private List<TickPosition> calculatedTimeTicks;
|
private List<TickPosition> calculatedTimeTicks;
|
||||||
|
|
||||||
private boolean isZoomed;
|
private boolean isZoomed;
|
||||||
|
|
||||||
private final int TICKCOUNT = 10;
|
private final int TICKCOUNT = 10;
|
||||||
|
|
||||||
public TimeSlider() {
|
public TimeSlider() {
|
||||||
calculatedTimeTicks = new ArrayList<TickPosition>();
|
calculatedTimeTicks = new ArrayList<TickPosition>();
|
||||||
isZoomed = false;
|
isZoomed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void calculateTicks() {
|
private void calculateTicks() {
|
||||||
if (!isMinMaxInitialized())
|
if (!isMinMaxInitialized())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
calculatedTimeTicks.clear();
|
calculatedTimeTicks.clear();
|
||||||
|
|
||||||
long minMaxDiffInMs = maxValue.longValue() - minValue.longValue();
|
long minMaxDiffInMs = maxValue.longValue() - minValue.longValue();
|
||||||
long tickInterval = minMaxDiffInMs / TICKCOUNT;
|
long tickInterval = minMaxDiffInMs / TICKCOUNT;
|
||||||
NormalizedInterval normalizedTimeTickInterval = calc.normalizeTimeTickInterval(tickInterval);
|
NormalizedInterval normalizedTimeTickInterval = calc.normalizeTimeTickInterval(tickInterval);
|
||||||
calculatedTimeTicks = calc.calculateTimeTicks(normalizedTimeTickInterval, minValue.longValue(), maxValue.longValue(), 1);
|
calculatedTimeTicks = calc.calculateTimeTicks(normalizedTimeTickInterval, minValue.longValue(), maxValue.longValue(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw the ticks along the line.
|
* Draw the ticks along the line.
|
||||||
*/
|
*/
|
||||||
protected void drawTicks() {
|
protected void drawTicks() {
|
||||||
if (!isAttached() || !isMinMaxInitialized())
|
if (!isAttached() || !isMinMaxInitialized())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Draw the ticks
|
// Draw the ticks
|
||||||
int lineWidth = lineElement.getOffsetWidth();
|
int lineWidth = lineElement.getOffsetWidth();
|
||||||
// Create the ticks or make them visible
|
// Create the ticks or make them visible
|
||||||
for (int i = 0; i < calculatedTimeTicks.size(); i++) {
|
for (int i = 0; i < calculatedTimeTicks.size(); i++) {
|
||||||
TickPosition tickPosition = calculatedTimeTicks.get(i);
|
TickPosition tickPosition = calculatedTimeTicks.get(i);
|
||||||
|
|
||||||
Element tick = null;
|
Element tick = null;
|
||||||
if (i < tickElements.size()) {
|
if (i < tickElements.size()) {
|
||||||
tick = tickElements.get(i);
|
tick = tickElements.get(i);
|
||||||
} else { // Create the new tick
|
} else { // Create the new tick
|
||||||
tick = DOM.createDiv();
|
tick = DOM.createDiv();
|
||||||
DOM.setStyleAttribute(tick, "position", "absolute");
|
DOM.setStyleAttribute(tick, "position", "absolute");
|
||||||
DOM.setStyleAttribute(tick, "display", "none");
|
DOM.setStyleAttribute(tick, "display", "none");
|
||||||
DOM.appendChild(getElement(), tick);
|
DOM.appendChild(getElement(), tick);
|
||||||
tickElements.add(tick);
|
tickElements.add(tick);
|
||||||
}
|
}
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
DOM.setElementProperty(tick, "className", "gwt-SliderBar-tick");
|
DOM.setElementProperty(tick, "className", "gwt-SliderBar-tick");
|
||||||
} else {
|
} else {
|
||||||
DOM.setElementProperty(tick, "className", "gwt-SliderBar-tick gwt-SliderBar-tick-disabled");
|
DOM.setElementProperty(tick, "className", "gwt-SliderBar-tick gwt-SliderBar-tick-disabled");
|
||||||
}
|
}
|
||||||
// Position the tick and make it visible
|
// Position the tick and make it visible
|
||||||
DOM.setStyleAttribute(tick, "visibility", "hidden");
|
DOM.setStyleAttribute(tick, "visibility", "hidden");
|
||||||
DOM.setStyleAttribute(tick, "display", "");
|
DOM.setStyleAttribute(tick, "display", "");
|
||||||
int tickWidth = tick.getOffsetWidth();
|
int tickWidth = tick.getOffsetWidth();
|
||||||
long pos = (tickPosition.getPosition().getTime() - minValue.longValue()) * lineWidth / (maxValue.longValue() - minValue.longValue());
|
long pos = (tickPosition.getPosition().getTime() - minValue.longValue()) * lineWidth / (maxValue.longValue() - minValue.longValue());
|
||||||
int tickLeftOffset = lineLeftOffset + (int) pos - (tickWidth / 2);
|
int tickLeftOffset = lineLeftOffset + (int) pos - (tickWidth / 2);
|
||||||
tickLeftOffset = Math.min(tickLeftOffset, lineLeftOffset + lineWidth - tickWidth);
|
tickLeftOffset = Math.min(tickLeftOffset, lineLeftOffset + lineWidth - tickWidth);
|
||||||
DOM.setStyleAttribute(tick, "left", tickLeftOffset + "px");
|
DOM.setStyleAttribute(tick, "left", tickLeftOffset + "px");
|
||||||
DOM.setStyleAttribute(tick, "visibility", "visible");
|
DOM.setStyleAttribute(tick, "visibility", "visible");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hide unused ticks
|
// Hide unused ticks
|
||||||
for (int i = (calculatedTimeTicks.size() + 1); i < tickElements.size(); i++) {
|
for (int i = (calculatedTimeTicks.size() + 1); i < tickElements.size(); i++) {
|
||||||
DOM.setStyleAttribute(tickElements.get(i), "display", "none");
|
DOM.setStyleAttribute(tickElements.get(i), "display", "none");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw the labels along the line.
|
* Draw the labels along the line.
|
||||||
*/
|
*/
|
||||||
protected void drawTickLabels() {
|
protected void drawTickLabels() {
|
||||||
if (!isAttached() || !isMinMaxInitialized())
|
if (!isAttached() || !isMinMaxInitialized())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Draw the tick labels
|
// Draw the tick labels
|
||||||
int lineWidth = lineElement.getOffsetWidth();
|
int lineWidth = lineElement.getOffsetWidth();
|
||||||
// Create the labels or make them visible
|
// Create the labels or make them visible
|
||||||
Double previousValue = null;
|
Double previousValue = null;
|
||||||
for (int i = 0; i < calculatedTimeTicks.size(); i++) {
|
for (int i = 0; i < calculatedTimeTicks.size(); i++) {
|
||||||
TickPosition tickPosition = calculatedTimeTicks.get(i);
|
TickPosition tickPosition = calculatedTimeTicks.get(i);
|
||||||
Element label = null;
|
Element label = null;
|
||||||
if (i < tickLabelElements.size()) {
|
if (i < tickLabelElements.size()) {
|
||||||
label = tickLabelElements.get(i);
|
label = tickLabelElements.get(i);
|
||||||
} else { // Create the new label
|
} else { // Create the new label
|
||||||
label = DOM.createDiv();
|
label = DOM.createDiv();
|
||||||
DOM.setStyleAttribute(label, "position", "absolute");
|
DOM.setStyleAttribute(label, "position", "absolute");
|
||||||
DOM.setStyleAttribute(label, "display", "none");
|
DOM.setStyleAttribute(label, "display", "none");
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
DOM.setElementProperty(label, "className", "gwt-SliderBar-ticklabel");
|
DOM.setElementProperty(label, "className", "gwt-SliderBar-ticklabel");
|
||||||
} else {
|
} else {
|
||||||
DOM.setElementProperty(label, "className", "gwt-SliderBar-ticklabel-disabled");
|
DOM.setElementProperty(label, "className", "gwt-SliderBar-ticklabel-disabled");
|
||||||
}
|
}
|
||||||
DOM.appendChild(getElement(), label);
|
DOM.appendChild(getElement(), label);
|
||||||
tickLabelElements.add(label);
|
tickLabelElements.add(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the label text
|
// Set the label text
|
||||||
double value = tickPosition.getPosition().getTime();
|
double value = tickPosition.getPosition().getTime();
|
||||||
DOM.setStyleAttribute(label, "visibility", "hidden");
|
DOM.setStyleAttribute(label, "visibility", "hidden");
|
||||||
DOM.setStyleAttribute(label, "display", "");
|
DOM.setStyleAttribute(label, "display", "");
|
||||||
DOM.setElementProperty(label, "innerHTML", formatTickLabel(value, previousValue));
|
DOM.setElementProperty(label, "innerHTML", formatTickLabel(value, previousValue));
|
||||||
|
|
||||||
// Move to the left so the label width is not clipped by the
|
// Move to the left so the label width is not clipped by the
|
||||||
// shell
|
// shell
|
||||||
DOM.setStyleAttribute(label, "left", "0px");
|
DOM.setStyleAttribute(label, "left", "0px");
|
||||||
|
|
||||||
// Position the label and make it visible
|
// Position the label and make it visible
|
||||||
int labelWidth = label.getOffsetWidth();
|
int labelWidth = label.getOffsetWidth();
|
||||||
long pos = (tickPosition.getPosition().getTime() - minValue.longValue()) * lineWidth / (maxValue.longValue() - minValue.longValue());
|
long pos = (tickPosition.getPosition().getTime() - minValue.longValue()) * lineWidth / (maxValue.longValue() - minValue.longValue());
|
||||||
int labelLeftOffset = lineLeftOffset + (int) pos - (labelWidth / 2);
|
int labelLeftOffset = lineLeftOffset + (int) pos - (labelWidth / 2);
|
||||||
labelLeftOffset = Math.min(labelLeftOffset, lineLeftOffset + lineWidth - labelWidth);
|
labelLeftOffset = Math.min(labelLeftOffset, lineLeftOffset + lineWidth - labelWidth);
|
||||||
labelLeftOffset = Math.max(labelLeftOffset, lineLeftOffset);
|
labelLeftOffset = Math.max(labelLeftOffset, lineLeftOffset);
|
||||||
DOM.setStyleAttribute(label, "left", labelLeftOffset + "px");
|
DOM.setStyleAttribute(label, "left", labelLeftOffset + "px");
|
||||||
DOM.setStyleAttribute(label, "visibility", "visible");
|
DOM.setStyleAttribute(label, "visibility", "visible");
|
||||||
|
|
||||||
previousValue = value;
|
previousValue = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hide unused labels
|
// Hide unused labels
|
||||||
for (int i = (calculatedTimeTicks.size() + 1); i < tickLabelElements.size(); i++) {
|
for (int i = (calculatedTimeTicks.size() + 1); i < tickLabelElements.size(); i++) {
|
||||||
DOM.setStyleAttribute(tickLabelElements.get(i), "display", "none");
|
DOM.setStyleAttribute(tickLabelElements.get(i), "display", "none");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearMarkersAndLabelsAndTicks() {
|
public void clearMarkersAndLabelsAndTicks() {
|
||||||
clearMarkers();
|
clearMarkers();
|
||||||
for (Element elem : tickLabelElements) {
|
for (Element elem : tickLabelElements) {
|
||||||
DOM.setStyleAttribute(elem, "display", "none");
|
DOM.setStyleAttribute(elem, "display", "none");
|
||||||
DOM.setStyleAttribute(elem, "visibility", "hidden");
|
DOM.setStyleAttribute(elem, "visibility", "hidden");
|
||||||
}
|
}
|
||||||
for (Element elem : tickElements) {
|
for (Element elem : tickElements) {
|
||||||
DOM.setStyleAttribute(elem, "display", "none");
|
DOM.setStyleAttribute(elem, "display", "none");
|
||||||
DOM.setStyleAttribute(elem, "visibility", "hidden");
|
DOM.setStyleAttribute(elem, "visibility", "hidden");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Element elem : markerLabelElements) {
|
for (Element elem : markerLabelElements) {
|
||||||
DOM.setStyleAttribute(elem, "display", "none");
|
DOM.setStyleAttribute(elem, "display", "none");
|
||||||
DOM.setStyleAttribute(elem, "visibility", "hidden");
|
DOM.setStyleAttribute(elem, "visibility", "hidden");
|
||||||
}
|
}
|
||||||
for (Element elem : markerElements) {
|
for (Element elem : markerElements) {
|
||||||
DOM.setStyleAttribute(elem, "display", "none");
|
DOM.setStyleAttribute(elem, "display", "none");
|
||||||
DOM.setStyleAttribute(elem, "visibility", "hidden");
|
DOM.setStyleAttribute(elem, "visibility", "hidden");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw the knob where it is supposed to be relative to the line.
|
* Draw the knob where it is supposed to be relative to the line.
|
||||||
*/
|
*/
|
||||||
protected void drawKnob() {
|
protected void drawKnob() {
|
||||||
if (!isAttached() || !isMinMaxInitialized())
|
if (!isAttached() || !isMinMaxInitialized())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Element knobElement = knobImage.getElement();
|
Element knobElement = knobImage.getElement();
|
||||||
if(curValue >= minValue && curValue <= maxValue) {
|
if(curValue >= minValue && curValue <= maxValue) {
|
||||||
// Move the knob to the correct position
|
// Move the knob to the correct position
|
||||||
int lineWidth = lineElement.getOffsetWidth();
|
int lineWidth = lineElement.getOffsetWidth();
|
||||||
int knobWidth = knobElement.getOffsetWidth();
|
int knobWidth = knobElement.getOffsetWidth();
|
||||||
int knobLeftOffset = (int) (lineLeftOffset + (getKnobPercent() * lineWidth) - (knobWidth / 2));
|
int knobLeftOffset = (int) (lineLeftOffset + (getKnobPercent() * lineWidth) - (knobWidth / 2));
|
||||||
knobLeftOffset = Math.min(knobLeftOffset, lineLeftOffset + lineWidth - (knobWidth / 2) - 1);
|
knobLeftOffset = Math.min(knobLeftOffset, lineLeftOffset + lineWidth - (knobWidth / 2) - 1);
|
||||||
DOM.setStyleAttribute(knobElement, "left", knobLeftOffset + "px");
|
DOM.setStyleAttribute(knobElement, "left", knobLeftOffset + "px");
|
||||||
DOM.setStyleAttribute(knobElement, "visibility", "visible");
|
DOM.setStyleAttribute(knobElement, "visibility", "visible");
|
||||||
DOM.setStyleAttribute(knobElement, "display", "");
|
DOM.setStyleAttribute(knobElement, "display", "");
|
||||||
} else {
|
} else {
|
||||||
DOM.setStyleAttribute(knobElement, "display", "none");
|
DOM.setStyleAttribute(knobElement, "display", "none");
|
||||||
DOM.setStyleAttribute(knobElement, "visibility", "hidden");
|
DOM.setStyleAttribute(knobElement, "visibility", "hidden");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMaxValue(Double maxValue, boolean fireEvent) {
|
public void setMaxValue(Double maxValue, boolean fireEvent) {
|
||||||
if(!isZoomed) {
|
if(!isZoomed) {
|
||||||
super.setMaxValue(maxValue, fireEvent);
|
super.setMaxValue(maxValue, fireEvent);
|
||||||
} else {
|
} else {
|
||||||
this.maxValue = maxValue;
|
this.maxValue = maxValue;
|
||||||
}
|
}
|
||||||
calculateTicks();
|
calculateTicks();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMinValue(Double minValue, boolean fireEvent) {
|
public void setMinValue(Double minValue, boolean fireEvent) {
|
||||||
if(!isZoomed) {
|
if(!isZoomed) {
|
||||||
super.setMinValue(minValue, fireEvent);
|
super.setMinValue(minValue, fireEvent);
|
||||||
} else {
|
} else {
|
||||||
this.minValue = minValue;
|
this.minValue = minValue;
|
||||||
}
|
}
|
||||||
calculateTicks();
|
calculateTicks();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStepSize(double stepSize, boolean fireEvent) {
|
public void setStepSize(double stepSize, boolean fireEvent) {
|
||||||
if(!isZoomed) {
|
if(!isZoomed) {
|
||||||
super.setStepSize(stepSize, fireEvent);
|
super.setStepSize(stepSize, fireEvent);
|
||||||
} else {
|
} else {
|
||||||
this.stepSize = stepSize;
|
this.stepSize = stepSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isZoomed() {
|
public boolean isZoomed() {
|
||||||
return isZoomed;
|
return isZoomed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setZoomed(boolean isZoomed) {
|
public void setZoomed(boolean isZoomed) {
|
||||||
this.isZoomed = isZoomed;
|
this.isZoomed = isZoomed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -4,10 +4,10 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.google.gwt.user.client.ui.ListBox;
|
import com.google.gwt.user.client.ui.ListBox;
|
||||||
|
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||||
import com.sap.sailing.domain.common.filter.BinaryOperator;
|
import com.sap.sailing.domain.common.filter.BinaryOperator;
|
||||||
import com.sap.sailing.domain.common.filter.NumberFilter;
|
import com.sap.sailing.domain.common.filter.NumberFilter;
|
||||||
import com.sap.sailing.gwt.ui.client.DataEntryDialog;
|
import com.sap.sailing.gwt.ui.client.DataEntryDialog;
|
||||||
import com.sap.sailing.gwt.ui.shared.CompetitorDTO;
|
|
||||||
|
|
||||||
public abstract class AbstractCompetitorNumberFilterUIFactory<T extends Number> implements FilterUIFactory<CompetitorDTO> {
|
public abstract class AbstractCompetitorNumberFilterUIFactory<T extends Number> implements FilterUIFactory<CompetitorDTO> {
|
||||||
protected List<BinaryOperator.Operators> supportedOperators;
|
protected List<BinaryOperator.Operators> supportedOperators;
|
||||||
|
|||||||
+1
-1
@@ -4,10 +4,10 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.google.gwt.user.client.ui.ListBox;
|
import com.google.gwt.user.client.ui.ListBox;
|
||||||
|
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||||
import com.sap.sailing.domain.common.filter.TextFilter;
|
import com.sap.sailing.domain.common.filter.TextFilter;
|
||||||
import com.sap.sailing.domain.common.filter.TextOperator;
|
import com.sap.sailing.domain.common.filter.TextOperator;
|
||||||
import com.sap.sailing.gwt.ui.client.DataEntryDialog;
|
import com.sap.sailing.gwt.ui.client.DataEntryDialog;
|
||||||
import com.sap.sailing.gwt.ui.shared.CompetitorDTO;
|
|
||||||
|
|
||||||
public abstract class AbstractCompetitorTextFilterUIFactory implements FilterUIFactory<CompetitorDTO> {
|
public abstract class AbstractCompetitorTextFilterUIFactory implements FilterUIFactory<CompetitorDTO> {
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -16,11 +16,11 @@ import com.google.gwt.user.client.ui.ListBox;
|
|||||||
import com.google.gwt.user.client.ui.TextBox;
|
import com.google.gwt.user.client.ui.TextBox;
|
||||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||||
import com.google.gwt.user.client.ui.Widget;
|
import com.google.gwt.user.client.ui.Widget;
|
||||||
|
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||||
import com.sap.sailing.domain.common.filter.Filter;
|
import com.sap.sailing.domain.common.filter.Filter;
|
||||||
import com.sap.sailing.domain.common.filter.FilterSet;
|
import com.sap.sailing.domain.common.filter.FilterSet;
|
||||||
import com.sap.sailing.gwt.ui.client.DataEntryDialog;
|
import com.sap.sailing.gwt.ui.client.DataEntryDialog;
|
||||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||||
import com.sap.sailing.gwt.ui.shared.CompetitorDTO;
|
|
||||||
|
|
||||||
public abstract class AbstractCompetitorsFilterSetDialog extends DataEntryDialog<FilterSet<CompetitorDTO, FilterWithUI<CompetitorDTO>>> {
|
public abstract class AbstractCompetitorsFilterSetDialog extends DataEntryDialog<FilterSet<CompetitorDTO, FilterWithUI<CompetitorDTO>>> {
|
||||||
private final FilterSet<CompetitorDTO, FilterWithUI<CompetitorDTO>> competitorsFilterSet;
|
private final FilterSet<CompetitorDTO, FilterWithUI<CompetitorDTO>> competitorsFilterSet;
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
package com.sap.sailing.gwt.ui.client.shared.filter;
|
package com.sap.sailing.gwt.ui.client.shared.filter;
|
||||||
|
|
||||||
import com.sap.sailing.gwt.ui.shared.CompetitorDTO;
|
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A factory for FilterWithUI<Competitor> instances
|
* A factory for FilterWithUI<Competitor> instances
|
||||||
|
|||||||
+1
-1
@@ -1,8 +1,8 @@
|
|||||||
package com.sap.sailing.gwt.ui.client.shared.filter;
|
package com.sap.sailing.gwt.ui.client.shared.filter;
|
||||||
|
|
||||||
|
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||||
import com.sap.sailing.domain.common.filter.AbstractTextFilter;
|
import com.sap.sailing.domain.common.filter.AbstractTextFilter;
|
||||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||||
import com.sap.sailing.gwt.ui.shared.CompetitorDTO;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A filter filtering competitors by their nationality
|
* A filter filtering competitors by their nationality
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user