Merge remote-tracking branch 'origin/master' into maneuver_refactoring

This commit is contained in:
Vladislav Chumak committed 2018-07-05 03:04:24 +02:00
commit 9015b5edc6
198 files changed
+3058 -1619

No files matched your search

Binary file not shown.
@@ -1,12 +1,9 @@
package com.sap.sailing.dashboards.gwt.client;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.sap.sailing.dashboards.gwt.shared.dispatch.DashboardDispatchSystem;
import com.sap.sailing.dashboards.gwt.shared.dispatch.impl.DashboardDispatchSystemImpl;
import com.sap.sailing.gwt.ui.client.SailingService;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sse.gwt.client.EntryPointHelper;
import com.sap.sailing.gwt.ui.client.SailingServiceHelper;
import com.sap.sse.gwt.client.player.Timer;
import com.sap.sse.gwt.client.player.Timer.PlayModes;
@@ -24,8 +21,7 @@ public class DashboardClientFactoryImpl implements DashboardClientFactory{
public DashboardClientFactoryImpl() {
dispatch = new DashboardDispatchSystemImpl();
sailingService = GWT.create(SailingService.class);
EntryPointHelper.registerASyncService((ServiceDefTarget) sailingService, RemoteServiceMappingConstants.WEB_CONTEXT_PATH, RemoteServiceMappingConstants.sailingServiceRemotePath);
sailingService = SailingServiceHelper.createSailingServiceInstance(false);
dashboardFiveSecondsTimer = new Timer(PlayModes.Live);
dashboardFiveSecondsTimer.setRefreshInterval(DASHBOARD_RERFRESH_INTERVAL);
@@ -17,6 +17,7 @@ Export-Package: com.sap.sailing.domain.common,
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.racelog,
com.sap.sailing.domain.common.sharding,
com.sap.sailing.domain.common.racelog.tracking,
com.sap.sailing.domain.common.racelog.utils,
com.sap.sailing.domain.common.scalablevalue.impl,
@@ -31,6 +31,7 @@ public enum BoatClassMasterdata {
CANOE_TAIFUN ("Canoe Taifun", true, 5.20, 1.32, BoatHullType.MONOHULL, false, "Taifun", "Taifun Kanu", "Kanu Taifun"),
CONTENDER ("Contender", true, 4.88, 1.42, BoatHullType.MONOHULL, false),
CC_30 ("C&C 30", true, 9.12, 3.25, BoatHullType.MONOHULL, true),
CLUB_SWAN_50 ("Club Swan 50", true, 16.74, 4.20, BoatHullType.MONOHULL, true, "ClubSwan50"),
D_ONE ("D-One", true, 4.23, 2.31, BoatHullType.MONOHULL, true, "Devoti D-One", "DOne", "D_One"),
DRAGON_INT ("Dragon Int.", true, 8.89, 1.96, BoatHullType.MONOHULL, true, "Drachen", "Dragon"),
DELPHIA_24 ("Delphia 24", true, 7.70, 2.50, BoatHullType.MONOHULL, true, "Delphia 24 One Design", "Delphia 24 OD"),
@@ -44,6 +45,7 @@ public enum BoatClassMasterdata {
FARR_280 ("Farr 280", true, 8.72, 2.87, BoatHullType.MONOHULL, true, "F280", "F-280", "Farr-280"),
FINN ("Finn", true, 4.50, 1.51, BoatHullType.MONOHULL, false),
FLYING_DUTCHMAN ("Flying Dutchman", true, 6.10, 1.80, BoatHullType.MONOHULL, true, "FD"),
FLYING_JUNIOR ("Flying Junior", true, 4.03, 1.50, BoatHullType.MONOHULL, true, "FJ"),
FLYING_PHANTOM ("Flying Phantom", true, 5.52, 3.00, BoatHullType.CATAMARAN, true),
FOLKBOAT ("Folkboat", true, 7.68, 2.20, BoatHullType.MONOHULL, false, "Folke", "Folkeboot"),
FUN ("FUN", true, 7.20, 2.45, BoatHullType.MONOHULL, true, "FUN O.D.", "FUN OD", "Open FUN"),
@@ -115,6 +117,7 @@ public enum BoatClassMasterdata {
TOM_28_MAX ("Tom 28 MAX", true, 8.48, 2.48, BoatHullType.MONOHULL, true, "Tom 28"),
TRIAS ("Trias", true, 9.20, 2.12, BoatHullType.MONOHULL, true),
TP52 ("TP52", true, 15.85, 4.35, BoatHullType.MONOHULL, true, "TP 52", "Transpac 52", "Transpac52"),
VAURIEN ("Vaurien", true, 4.08, 1.47, BoatHullType.MONOHULL, true),
VENT_D_OUEST ("Vent d'Ouest", true, 5.85, 1.75, BoatHullType.MONOHULL, true, "VENTDOUEST", "VENTD'OUEST"),
VIPER_640 ("Viper 640", true, 6.43, 2.49, BoatHullType.MONOHULL, true),
VO60 ("VO60", true, 19.5, 5.25, BoatHullType.MONOHULL, true, "Volvo Ocean 60", "VolvoOcean60", "W60", "Whitbread60", "Whitbread 60"),
@@ -5,10 +5,9 @@ import static com.sap.sailing.domain.common.SortingOrder.DESCENDING;
import static com.sap.sailing.domain.common.SortingOrder.NONE;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.LinkedHashSet;
/**
* Identifies details that can be requested from the racing service. Optionally, the details can specify a precision as
@@ -244,11 +243,11 @@ public enum DetailType implements Serializable {
}
/**
* Special List of DetailTypes, that allows operators to select for example the RideHeight, that is usually only
* selectable, if it already has data.
* Special collection of {@link DetailType}s, that allows operators to select for example the RideHeight, that is
* usually only selectable, if it already has data.
*/
public static List<DetailType> getAutoplayDetailTypesForChart() {
List<DetailType> availableDetailsTypes = new ArrayList<>();
public static Collection<DetailType> getAutoplayDetailTypesForChart() {
final Collection<DetailType> availableDetailsTypes = new LinkedHashSet<>();
availableDetailsTypes.add(DetailType.CHART_WINDWARD_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD);
availableDetailsTypes.add(DetailType.LEG_CURRENT_SPEED_OVER_GROUND_IN_KNOTS);
availableDetailsTypes.add(DetailType.LEG_DISTANCE_TRAVELED);
@@ -266,8 +265,8 @@ public enum DetailType implements Serializable {
return availableDetailsTypes;
}
public static List<DetailType> getRaceExpeditionDetailTypes() {
ArrayList<DetailType> allowed = new ArrayList<>();
public static Collection<DetailType> getRaceExpeditionDetailTypes() {
final Collection<DetailType> allowed = new LinkedHashSet<>();
allowed.add(EXPEDITION_RACE_AWA);
allowed.add(EXPEDITION_RACE_AWS);
allowed.add(EXPEDITION_RACE_TWA);
@@ -310,15 +309,8 @@ public enum DetailType implements Serializable {
return allowed;
}
public static List<DetailType> getLegExtendedBravoDetailTypes() {
ArrayList<DetailType> allowed = new ArrayList<>();
allowed.add(DetailType.BRAVOEXTENDED_LEG_CURRENT_DISTANCE_FOILED_IN_METERS);
allowed.add(DetailType.BRAVOEXTENDED_LEG_CURRENT_DURATION_FOILED_IN_SECONDS);
return allowed;
}
public static List<DetailType> getRaceExtendedBravoDetailTypes() {
ArrayList<DetailType> allowed = new ArrayList<>();
public static Collection<DetailType> getRaceExtendedBravoDetailTypes() {
final Collection<DetailType> allowed = new LinkedHashSet<>();
allowed.add(DetailType.BRAVOEXTENDED_RACE_CURRENT_PORT_DAGGERBOARD_RAKE);
allowed.add(DetailType.BRAVOEXTENDED_RACE_CURRENT_STBD_DAGGERBOARD_RAKE);
allowed.add(DetailType.BRAVOEXTENDED_RACE_CURRENT_PORT_RUDDER_RAKE);
@@ -340,24 +332,28 @@ public enum DetailType implements Serializable {
return allowed;
}
public static List<DetailType> getRaceBravoDetailTypes() {
ArrayList<DetailType> allowed = new ArrayList<>();
public static Collection<DetailType> getRaceBravoDetailTypes() {
final Collection<DetailType> allowed = new LinkedHashSet<>();
allowed.add(DetailType.BRAVO_RACE_HEEL_IN_DEGREES);
allowed.add(DetailType.BRAVO_RACE_PITCH_IN_DEGREES);
allowed.add(DetailType.BRAVO_RACE_CURRENT_RIDE_HEIGHT_IN_METERS);
allowed.add(DetailType.RACE_CURRENT_DISTANCE_FOILED_IN_METERS);
allowed.add(DetailType.RACE_CURRENT_DURATION_FOILED_IN_SECONDS);
return allowed;
}
public static List<DetailType> getLegBravoDetailTypes() {
ArrayList<DetailType> allowed = new ArrayList<>();
public static Collection<DetailType> getLegBravoDetailTypes() {
final Collection<DetailType> allowed = new LinkedHashSet<>();
allowed.add(DetailType.BRAVO_LEG_CURRENT_HEEL_IN_DEGREES);
allowed.add(DetailType.BRAVO_LEG_CURRENT_PITCH_IN_DEGREES);
allowed.add(DetailType.BRAVO_LEG_CURRENT_RIDE_HEIGHT_IN_METERS);
allowed.add(DetailType.BRAVOEXTENDED_LEG_CURRENT_DISTANCE_FOILED_IN_METERS);
allowed.add(DetailType.BRAVOEXTENDED_LEG_CURRENT_DURATION_FOILED_IN_SECONDS);
return allowed;
}
public static List<DetailType> getAllRaceDetailTypes() {
ArrayList<DetailType> allowed = new ArrayList<>();
public static Collection<DetailType> getAllRaceDetailTypes() {
final Collection<DetailType> allowed = new LinkedHashSet<>();
allowed.add(RACE_GAP_TO_LEADER_IN_SECONDS);
allowed.add(RACE_AVERAGE_SPEED_OVER_GROUND_IN_KNOTS);
allowed.add(RACE_DISTANCE_TRAVELED);
@@ -366,7 +362,6 @@ public enum DetailType implements Serializable {
allowed.add(RACE_CALCULATED_TIME_TRAVELED);
allowed.add(RACE_CALCULATED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD);
allowed.add(RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS);
allowed.add(BRAVO_RACE_CURRENT_RIDE_HEIGHT_IN_METERS);
allowed.add(RACE_CURRENT_DISTANCE_FOILED_IN_METERS);
allowed.add(RACE_CURRENT_DURATION_FOILED_IN_SECONDS);
allowed.add(RACE_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD_IN_METERS);
@@ -388,7 +383,7 @@ public enum DetailType implements Serializable {
* @return
*/
public static Collection<DetailType> getAllNonRestrictedDetailTypes() {
List<DetailType> all = new ArrayList<>(Arrays.asList(values()));
final Collection<DetailType> all = new LinkedHashSet<>(Arrays.asList(values()));
all.removeAll(getRaceBravoDetailTypes());
all.removeAll(getLegBravoDetailTypes());
all.removeAll(getRaceExtendedBravoDetailTypes());
@@ -398,83 +393,150 @@ public enum DetailType implements Serializable {
return all;
}
public static List<DetailType> getAvailableOverallDetailColumnTypes() {
return Arrays.asList(new DetailType[] { DetailType.REGATTA_RANK, DetailType.OVERALL_TOTAL_DISTANCE_TRAVELED,
DetailType.OVERALL_TOTAL_AVERAGE_SPEED_OVER_GROUND, DetailType.OVERALL_TOTAL_TIME_SAILED_IN_SECONDS,
DetailType.OVERALL_MAXIMUM_SPEED_OVER_GROUND_IN_KNOTS, DetailType.OVERALL_TIME_ON_TIME_FACTOR,
DetailType.OVERALL_TIME_ON_DISTANCE_ALLOWANCE_IN_SECONDS_PER_NAUTICAL_MILE,
DetailType.OVERALL_TOTAL_SCORED_RACE_COUNT, TOTAL_TIME_SAILED_UPWIND_IN_SECONDS,
TOTAL_TIME_SAILED_REACHING_IN_SECONDS, TOTAL_TIME_SAILED_DOWNWIND_IN_SECONDS });
public static Collection<DetailType> getAvailableOverallDetailColumnTypes() {
final Collection<DetailType> allowed = new LinkedHashSet<>();
allowed.add(REGATTA_RANK);
allowed.add(OVERALL_TOTAL_DISTANCE_TRAVELED);
allowed.add(OVERALL_TOTAL_AVERAGE_SPEED_OVER_GROUND);
allowed.add(OVERALL_TOTAL_TIME_SAILED_IN_SECONDS);
allowed.add(OVERALL_MAXIMUM_SPEED_OVER_GROUND_IN_KNOTS);
allowed.add(OVERALL_TIME_ON_TIME_FACTOR);
allowed.add(OVERALL_TIME_ON_DISTANCE_ALLOWANCE_IN_SECONDS_PER_NAUTICAL_MILE);
allowed.add(OVERALL_TOTAL_SCORED_RACE_COUNT);
allowed.add(TOTAL_TIME_SAILED_UPWIND_IN_SECONDS);
allowed.add(TOTAL_TIME_SAILED_REACHING_IN_SECONDS);
allowed.add(TOTAL_TIME_SAILED_DOWNWIND_IN_SECONDS);
return allowed;
}
public static List<DetailType> getOverallBravoDetailTypes() {
return Arrays.asList(new DetailType[] { DetailType.OVERALL_TOTAL_DISTANCE_FOILED_IN_METERS,
OVERALL_TOTAL_DURATION_FOILED_IN_SECONDS });
public static Collection<DetailType> getOverallBravoDetailTypes() {
final Collection<DetailType> allowed = new LinkedHashSet<>();
allowed.add(OVERALL_TOTAL_DISTANCE_FOILED_IN_METERS);
allowed.add(OVERALL_TOTAL_DURATION_FOILED_IN_SECONDS);
return allowed;
}
public static List<DetailType> getLegDetailColumnTypes() {
return Arrays.asList(new DetailType[] { DetailType.LEG_AVERAGE_SPEED_OVER_GROUND_IN_KNOTS,
DetailType.LEG_DISTANCE_TRAVELED, DetailType.LEG_DISTANCE_TRAVELED_INCLUDING_GATE_START,
DetailType.LEG_GAP_TO_LEADER_IN_SECONDS, DetailType.LEG_GAP_CHANGE_SINCE_LEG_START_IN_SECONDS,
DetailType.LEG_SIDE_TO_WHICH_MARK_AT_LEG_START_WAS_ROUNDED,
DetailType.LEG_CURRENT_SPEED_OVER_GROUND_IN_KNOTS, DetailType.LEG_WINDWARD_DISTANCE_TO_GO_IN_METERS,
DetailType.NUMBER_OF_MANEUVERS, DetailType.LEG_ESTIMATED_TIME_TO_NEXT_WAYPOINT_IN_SECONDS,
DetailType.LEG_VELOCITY_MADE_GOOD_IN_KNOTS, DetailType.LEG_TIME_TRAVELED,
DetailType.LEG_CORRECTED_TIME_TRAVELED, DetailType.LEG_AVERAGE_ABSOLUTE_CROSS_TRACK_ERROR_IN_METERS,
DetailType.LEG_AVERAGE_SIGNED_CROSS_TRACK_ERROR_IN_METERS, DetailType.LEG_RANK_GAIN });
public static Collection<DetailType> getLegDetailColumnTypes() {
final Collection<DetailType> allowed = new LinkedHashSet<>();
allowed.add(LEG_AVERAGE_SPEED_OVER_GROUND_IN_KNOTS);
allowed.add(LEG_DISTANCE_TRAVELED);
allowed.add(LEG_DISTANCE_TRAVELED_INCLUDING_GATE_START);
allowed.add(LEG_GAP_TO_LEADER_IN_SECONDS);
allowed.add(LEG_GAP_CHANGE_SINCE_LEG_START_IN_SECONDS);
allowed.add(LEG_SIDE_TO_WHICH_MARK_AT_LEG_START_WAS_ROUNDED);
allowed.add(LEG_CURRENT_SPEED_OVER_GROUND_IN_KNOTS);
allowed.add(LEG_WINDWARD_DISTANCE_TO_GO_IN_METERS);
allowed.add(NUMBER_OF_MANEUVERS);
allowed.add(LEG_ESTIMATED_TIME_TO_NEXT_WAYPOINT_IN_SECONDS);
allowed.add(LEG_VELOCITY_MADE_GOOD_IN_KNOTS);
allowed.add(LEG_TIME_TRAVELED);
allowed.add(LEG_CORRECTED_TIME_TRAVELED);
allowed.add(LEG_AVERAGE_ABSOLUTE_CROSS_TRACK_ERROR_IN_METERS);
allowed.add(LEG_AVERAGE_SIGNED_CROSS_TRACK_ERROR_IN_METERS);
allowed.add(LEG_RANK_GAIN);
return allowed;
}
public static List<DetailType> getRaceStartAnalysisColumnTypes() {
return Arrays.asList(new DetailType[] { DetailType.RACE_DISTANCE_TO_START_FIVE_SECONDS_BEFORE_RACE_START,
DetailType.RACE_SPEED_OVER_GROUND_FIVE_SECONDS_BEFORE_START, DetailType.DISTANCE_TO_START_AT_RACE_START,
DetailType.TIME_BETWEEN_RACE_START_AND_COMPETITOR_START, DetailType.SPEED_OVER_GROUND_AT_RACE_START,
DetailType.SPEED_OVER_GROUND_WHEN_PASSING_START,
DetailType.DISTANCE_TO_STARBOARD_END_OF_STARTLINE_WHEN_PASSING_START_IN_METERS,
DetailType.START_TACK });
public static Collection<DetailType> getRaceStartAnalysisColumnTypes() {
final Collection<DetailType> allowed = new LinkedHashSet<>();
allowed.add(RACE_DISTANCE_TO_START_FIVE_SECONDS_BEFORE_RACE_START);
allowed.add(RACE_SPEED_OVER_GROUND_FIVE_SECONDS_BEFORE_START);
allowed.add(DISTANCE_TO_START_AT_RACE_START);
allowed.add(TIME_BETWEEN_RACE_START_AND_COMPETITOR_START);
allowed.add(SPEED_OVER_GROUND_AT_RACE_START);
allowed.add(SPEED_OVER_GROUND_WHEN_PASSING_START);
allowed.add(DISTANCE_TO_STARBOARD_END_OF_STARTLINE_WHEN_PASSING_START_IN_METERS);
allowed.add(START_TACK);
return allowed;
}
public static List<DetailType> getLegExpeditionDetailColumnTypes() {
return Arrays.asList(new DetailType[] { EXPEDITION_LEG_AWA, EXPEDITION_LEG_AWS, EXPEDITION_LEG_TWA,
EXPEDITION_LEG_TWS, EXPEDITION_LEG_TWD, EXPEDITION_LEG_TARG_TWA, EXPEDITION_LEG_BOAT_SPEED,
EXPEDITION_LEG_TARG_BOAT_SPEED, EXPEDITION_LEG_SOG, EXPEDITION_LEG_COG, EXPEDITION_LEG_FORESTAY_LOAD,
EXPEDITION_LEG_RAKE, EXPEDITION_LEG_COURSE, EXPEDITION_LEG_HEADING, EXPEDITION_LEG_VMG,
EXPEDITION_LEG_VMG_TARG_VMG_DELTA, EXPEDITION_LEG_RATE_OF_TURN, EXPEDITION_LEG_RUDDER_ANGLE,
EXPEDITION_LEG_TARGET_HEEL, EXPEDITION_LEG_TIME_TO_PORT_LAYLINE,
EXPEDITION_LEG_TIME_TO_STB_LAYLINE, EXPEDITION_LEG_DIST_TO_PORT_LAYLINE,
EXPEDITION_LEG_DIST_TO_STB_LAYLINE, EXPEDITION_LEG_TIME_TO_GUN, EXPEDITION_LEG_TIME_TO_COMMITTEE_BOAT,
EXPEDITION_LEG_TIME_TO_PIN, EXPEDITION_LEG_TIME_TO_BURN_TO_LINE,
EXPEDITION_LEG_TIME_TO_BURN_TO_COMMITTEE_BOAT, EXPEDITION_LEG_TIME_TO_BURN_TO_PIN,
EXPEDITION_LEG_DISTANCE_TO_COMMITTEE_BOAT, EXPEDITION_LEG_DISTANCE_TO_PIN,
EXPEDITION_LEG_DISTANCE_BELOW_LINE, EXPEDITION_LEG_LINE_SQUARE_FOR_WIND_DIRECTION, EXPEDITION_LEG_BARO,
EXPEDITION_LEG_LOAD_S, EXPEDITION_LEG_LOAD_P, EXPEDITION_LEG_JIB_CAR_PORT, EXPEDITION_LEG_JIB_CAR_STBD,
EXPEDITION_LEG_MAST_BUTT });
public static Collection<DetailType> getLegExpeditionDetailColumnTypes() {
final Collection<DetailType> allowed = new LinkedHashSet<>();
allowed.add(EXPEDITION_LEG_AWA);
allowed.add(EXPEDITION_LEG_AWS);
allowed.add(EXPEDITION_LEG_TWA);
allowed.add(EXPEDITION_LEG_TWS);
allowed.add(EXPEDITION_LEG_TWD);
allowed.add(EXPEDITION_LEG_TARG_TWA);
allowed.add(EXPEDITION_LEG_BOAT_SPEED);
allowed.add(EXPEDITION_LEG_TARG_BOAT_SPEED);
allowed.add(EXPEDITION_LEG_SOG);
allowed.add(EXPEDITION_LEG_COG);
allowed.add(EXPEDITION_LEG_FORESTAY_LOAD);
allowed.add(EXPEDITION_LEG_RAKE);
allowed.add(EXPEDITION_LEG_COURSE);
allowed.add(EXPEDITION_LEG_HEADING);
allowed.add(EXPEDITION_LEG_VMG);
allowed.add(EXPEDITION_LEG_VMG_TARG_VMG_DELTA);
allowed.add(EXPEDITION_LEG_RATE_OF_TURN);
allowed.add(EXPEDITION_LEG_RUDDER_ANGLE);
allowed.add(EXPEDITION_LEG_TARGET_HEEL);
allowed.add(EXPEDITION_LEG_TIME_TO_PORT_LAYLINE);
allowed.add(EXPEDITION_LEG_TIME_TO_STB_LAYLINE);
allowed.add(EXPEDITION_LEG_DIST_TO_PORT_LAYLINE);
allowed.add(EXPEDITION_LEG_DIST_TO_STB_LAYLINE);
allowed.add(EXPEDITION_LEG_TIME_TO_GUN);
allowed.add(EXPEDITION_LEG_TIME_TO_COMMITTEE_BOAT);
allowed.add(EXPEDITION_LEG_TIME_TO_PIN);
allowed.add(EXPEDITION_LEG_TIME_TO_BURN_TO_LINE);
allowed.add(EXPEDITION_LEG_TIME_TO_BURN_TO_COMMITTEE_BOAT);
allowed.add(EXPEDITION_LEG_TIME_TO_BURN_TO_PIN);
allowed.add(EXPEDITION_LEG_DISTANCE_TO_COMMITTEE_BOAT);
allowed.add(EXPEDITION_LEG_DISTANCE_TO_PIN);
allowed.add(EXPEDITION_LEG_DISTANCE_BELOW_LINE);
allowed.add(EXPEDITION_LEG_LINE_SQUARE_FOR_WIND_DIRECTION);
allowed.add(EXPEDITION_LEG_BARO);
allowed.add(EXPEDITION_LEG_LOAD_S);
allowed.add(EXPEDITION_LEG_LOAD_P);
allowed.add(EXPEDITION_LEG_JIB_CAR_PORT);
allowed.add(EXPEDITION_LEG_JIB_CAR_STBD);
allowed.add(EXPEDITION_LEG_MAST_BUTT);
return allowed;
}
/**
* Not yet implemented types can be added here, they will be hidden from any user under all circumstances
*/
public static List<DetailType> getDisabledDetailColumTypes() {
return Arrays.asList(new DetailType[] { EXPEDITION_LEG_TARG_TWA, EXPEDITION_LEG_VMG,
EXPEDITION_LEG_VMG_TARG_VMG_DELTA, EXPEDITION_LEG_RATE_OF_TURN, EXPEDITION_LEG_RUDDER_ANGLE,
EXPEDITION_LEG_TIME_TO_PORT_LAYLINE, EXPEDITION_LEG_TIME_TO_STB_LAYLINE,
EXPEDITION_LEG_DIST_TO_PORT_LAYLINE, EXPEDITION_LEG_DIST_TO_STB_LAYLINE,
EXPEDITION_LEG_TIME_TO_COMMITTEE_BOAT, EXPEDITION_LEG_TIME_TO_PIN, EXPEDITION_LEG_TIME_TO_BURN_TO_COMMITTEE_BOAT,
EXPEDITION_LEG_TIME_TO_BURN_TO_PIN, EXPEDITION_LEG_DISTANCE_TO_COMMITTEE_BOAT,
EXPEDITION_LEG_DISTANCE_TO_PIN, EXPEDITION_LEG_LINE_SQUARE_FOR_WIND_DIRECTION, EXPEDITION_RACE_TARG_TWA,
EXPEDITION_RACE_VMG, EXPEDITION_RACE_VMG_TARG_VMG_DELTA,
EXPEDITION_RACE_RUDDER_ANGLE, EXPEDITION_RACE_TIME_TO_PORT_LAYLINE, EXPEDITION_RACE_TIME_TO_STB_LAYLINE,
EXPEDITION_RACE_DIST_TO_PORT_LAYLINE, EXPEDITION_RACE_DIST_TO_STB_LAYLINE,
EXPEDITION_RACE_TIME_TO_COMMITTEE_BOAT, EXPEDITION_RACE_TIME_TO_PIN,
EXPEDITION_RACE_TIME_TO_BURN_TO_PIN, EXPEDITION_RACE_TIME_TO_BURN_TO_COMMITTEE_BOAT,
EXPEDITION_RACE_DISTANCE_TO_COMMITTEE_BOAT, EXPEDITION_RACE_DISTANCE_TO_PIN,
EXPEDITION_RACE_LINE_SQUARE_FOR_WIND_DIRECTION });
public static Collection<DetailType> getDisabledDetailColumTypes() {
final Collection<DetailType> disabled = new LinkedHashSet<>();
disabled.add(EXPEDITION_LEG_TARG_TWA);
disabled.add(EXPEDITION_LEG_VMG);
disabled.add(EXPEDITION_LEG_VMG_TARG_VMG_DELTA);
disabled.add(EXPEDITION_LEG_RATE_OF_TURN);
disabled.add(EXPEDITION_LEG_RUDDER_ANGLE);
disabled.add(EXPEDITION_LEG_TIME_TO_PORT_LAYLINE);
disabled.add(EXPEDITION_LEG_TIME_TO_STB_LAYLINE);
disabled.add(EXPEDITION_LEG_DIST_TO_PORT_LAYLINE);
disabled.add(EXPEDITION_LEG_DIST_TO_STB_LAYLINE);
disabled.add(EXPEDITION_LEG_TIME_TO_COMMITTEE_BOAT);
disabled.add(EXPEDITION_LEG_TIME_TO_PIN);
disabled.add(EXPEDITION_LEG_TIME_TO_BURN_TO_COMMITTEE_BOAT);
disabled.add(EXPEDITION_LEG_TIME_TO_BURN_TO_PIN);
disabled.add(EXPEDITION_LEG_DISTANCE_TO_COMMITTEE_BOAT);
disabled.add(EXPEDITION_LEG_DISTANCE_TO_PIN);
disabled.add(EXPEDITION_LEG_LINE_SQUARE_FOR_WIND_DIRECTION);
disabled.add(EXPEDITION_RACE_TARG_TWA);
disabled.add(EXPEDITION_RACE_VMG);
disabled.add(EXPEDITION_RACE_VMG_TARG_VMG_DELTA);
disabled.add(EXPEDITION_RACE_RUDDER_ANGLE);
disabled.add(EXPEDITION_RACE_TIME_TO_PORT_LAYLINE);
disabled.add(EXPEDITION_RACE_TIME_TO_STB_LAYLINE);
disabled.add(EXPEDITION_RACE_DIST_TO_PORT_LAYLINE);
disabled.add(EXPEDITION_RACE_DIST_TO_STB_LAYLINE);
disabled.add(EXPEDITION_RACE_TIME_TO_COMMITTEE_BOAT);
disabled.add(EXPEDITION_RACE_TIME_TO_PIN);
disabled.add(EXPEDITION_RACE_TIME_TO_BURN_TO_PIN);
disabled.add(EXPEDITION_RACE_TIME_TO_BURN_TO_COMMITTEE_BOAT);
disabled.add(EXPEDITION_RACE_DISTANCE_TO_COMMITTEE_BOAT);
disabled.add(EXPEDITION_RACE_DISTANCE_TO_PIN);
disabled.add(EXPEDITION_RACE_LINE_SQUARE_FOR_WIND_DIRECTION);
return disabled;
}
public static List<DetailType> getAllLegDetailColumnTypes() {
ArrayList<DetailType> all = new ArrayList<>();
public static Collection<DetailType> getAllLegDetailColumnTypes() {
final Collection<DetailType> all = new LinkedHashSet<>();
all.addAll(getLegDetailColumnTypes());
all.addAll(getLegBravoDetailTypes());
all.addAll(getLegExtendedBravoDetailTypes());
all.addAll(getLegExpeditionDetailColumnTypes());
return all;
}
@@ -498,11 +560,10 @@ public enum DetailType implements Serializable {
return t;
}
}
}
}
}
throw new IllegalArgumentException("Could not restore " + value + " to an DetailType enum");
}
}
}
@@ -0,0 +1,61 @@
package com.sap.sailing.domain.common.sharding;
/**
* Enum that defines all sharding types known by the system.
*
* For a sharding to work, we need both client and backend properly identifying a shard.
*
* While the client has to properly deliver sharding information on each request, the server side
* infrastructure must be able to identify the information and properly route the requests.
*
* The current implementation uses a SUFFIX appended the GWT RPC URLs (allowing path based routing), so that each call to the server
* propagates the sharding information through the url.
*
* A load balancer can be used to properly route each request to the corresponding server node. The first
* sharding implemented is the sharding by leaderboard name.
*
* The suffix appended to the request URL consists of two parts: a prefix that is used to identify the type of shard
* and a payload that will be used to identify the shard.
*
*
*/
public enum ShardingType {
LEADERBOARDNAME("/leaderboard/");
private String prefix;
private ShardingType(String prefix) {
this.prefix = prefix;
}
public String encodeIfNeeded(String shardingInfo) {
if (shardingInfo.startsWith(prefix)) {
return shardingInfo;
}
return new StringBuilder().append(prefix)
.append(normalize(shardingInfo))
.toString();
}
private String normalize(String replace) {
char[] chars = replace.toCharArray();
StringBuilder answer = new StringBuilder();
for(int i = 0;i<chars.length;i++) {
char c = chars[i];
if (c > 47 && c < 58) { // digits
answer.append(c);
} else if (c > 64 && c < 91) { // uppercase letters
answer.append(c);
} else if (c > 69 && c < 123) { // lowercase letters
answer.append(c);
} else {
answer.append("_");
}
}
return answer.toString();
}
public String getPrefix() {
return prefix;
}
}
@@ -10,6 +10,7 @@ import com.sap.sailing.domain.base.configuration.procedures.RRS26Configuration;
import com.sap.sailing.domain.base.configuration.procedures.SWCStartConfiguration;
import com.sap.sailing.domain.common.CourseDesignerMode;
import com.sap.sailing.domain.common.racelog.RacingProcedureType;
import com.sap.sse.common.Duration;
/**
* Interface holding configuration options for a Regatta, including configurations for
@@ -26,6 +27,12 @@ public interface RegattaConfiguration extends Serializable, Cloneable {
* Gets the default {@link RacingProcedureType} for races configured.
*/
RacingProcedureType getDefaultRacingProcedureType();
/**
* Gets the default protest time duration. May be {@code null} in case no default is set for the
* regatta.
*/
Duration getDefaultProtestTimeDuration();
/**
* Gets the configuration for RRS26 races.
@@ -4,6 +4,7 @@ import com.sap.sailing.domain.base.configuration.ConfigurationLoader;
import com.sap.sailing.domain.base.configuration.RegattaConfiguration;
import com.sap.sailing.domain.common.CourseDesignerMode;
import com.sap.sailing.domain.common.racelog.RacingProcedureType;
import com.sap.sse.common.Duration;
/**
* Is empty, does nothing on store and load.
@@ -17,6 +18,7 @@ public class EmptyRegattaConfiguration extends RegattaConfigurationImpl implemen
public RegattaConfiguration load() {
setDefaultRacingProcedureType(RacingProcedureType.UNKNOWN);
setDefaultCourseDesignerMode(CourseDesignerMode.UNKNOWN);
setDefaultProtestTimeDuration(Duration.ONE_MINUTE.times(90));
setRRS26Configuration(new RRS26ConfigurationImpl());
setSWCStartConfiguration(new SWCStartConfigurationImpl());
setGateStartConfiguration(new GateStartConfigurationImpl());
@@ -9,6 +9,7 @@ import com.sap.sailing.domain.base.configuration.procedures.RRS26Configuration;
import com.sap.sailing.domain.base.configuration.procedures.SWCStartConfiguration;
import com.sap.sailing.domain.common.CourseDesignerMode;
import com.sap.sailing.domain.common.racelog.RacingProcedureType;
import com.sap.sse.common.Duration;
public class RegattaConfigurationImpl implements RegattaConfiguration {
@@ -16,6 +17,7 @@ public class RegattaConfigurationImpl implements RegattaConfiguration {
private RacingProcedureType defaultRacingProcedureType;
private CourseDesignerMode defaultCourseDesignerMode;
private Duration defaultProtestTimeDuration;
private RRS26Configuration rrs26Configuration;
private SWCStartConfiguration swcStartConfiguration;
@@ -42,6 +44,15 @@ public class RegattaConfigurationImpl implements RegattaConfiguration {
defaultCourseDesignerMode = mode;
}
@Override
public Duration getDefaultProtestTimeDuration() {
return defaultProtestTimeDuration;
}
public void setDefaultProtestTimeDuration(Duration defaultProtestTimeDuration) {
this.defaultProtestTimeDuration = defaultProtestTimeDuration;
}
@Override
public RRS26Configuration getRRS26Configuration() {
return rrs26Configuration;
@@ -101,6 +112,7 @@ public class RegattaConfigurationImpl implements RegattaConfiguration {
RegattaConfigurationImpl copy = new RegattaConfigurationImpl();
copy.setDefaultRacingProcedureType(defaultRacingProcedureType);
copy.setDefaultCourseDesignerMode(defaultCourseDesignerMode);
copy.setDefaultProtestTimeDuration(defaultProtestTimeDuration);
copy.setRRS26Configuration(rrs26Configuration);
copy.setSWCStartConfiguration(swcStartConfiguration);
copy.setGateStartConfiguration(gateStartConfiguration);
@@ -120,6 +132,9 @@ public class RegattaConfigurationImpl implements RegattaConfiguration {
if (update.getDefaultRacingProcedureType() != null) {
target.setDefaultRacingProcedureType(update.getDefaultRacingProcedureType());
}
if (update.getDefaultProtestTimeDuration() != null) {
target.setDefaultProtestTimeDuration(update.getDefaultProtestTimeDuration());
}
if (update.getRRS26Configuration() != null) {
target.setRRS26Configuration(
(RRS26Configuration) target.getRRS26Configuration().merge(update.getRRS26Configuration()));
@@ -31,6 +31,7 @@ Export-Package: com.sap.sailing.domain.base,
com.sap.sailing.domain.trackimport,
com.sap.sailing.domain.tracking,
com.sap.sailing.domain.tracking.impl,
com.sap.sailing.domain.sharding,
com.sap.sailing.domain.windfinder,
com.sap.sailing.util,
com.sap.sailing.util.impl;x-friends:="com.sap.sailing.server.replication,com.sap.sailing.domain.test"
@@ -12,7 +12,9 @@ import java.util.logging.Logger;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
import com.sap.sailing.domain.common.sharding.ShardingType;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.sharding.ShardingContext;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
@@ -274,6 +276,7 @@ public class LiveLeaderboardUpdater implements Runnable {
public void run() {
assert running;
try {
ShardingContext.setShardingConstraint(ShardingType.LEADERBOARDNAME, leaderboard.getName());
logger.info("Starting " + LiveLeaderboardUpdater.class.getSimpleName() + " thread for leaderboard "
+ leaderboard.getName());
// interrupt the current thread if not producing a single result within the overall timeout
@@ -326,6 +329,8 @@ public class LiveLeaderboardUpdater implements Runnable {
notifyAll();
}
logger.log(Level.SEVERE, "exception updating live leaderboard "+leaderboard.getName(), e);
} finally {
ShardingContext.clearShardingConstraint(ShardingType.LEADERBOARDNAME);
}
}
@@ -55,6 +55,7 @@ import com.sap.sailing.domain.common.dto.LegEntryDTO;
import com.sap.sailing.domain.common.dto.MetaLeaderboardRaceColumnDTO;
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
import com.sap.sailing.domain.common.dto.RaceDTO;
import com.sap.sailing.domain.common.sharding.ShardingType;
import com.sap.sailing.domain.common.tracking.BravoExtendedFix;
import com.sap.sailing.domain.common.tracking.BravoFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
@@ -68,6 +69,7 @@ import com.sap.sailing.domain.racelog.RaceLogIdentifier;
import com.sap.sailing.domain.ranking.RankingMetric.CompetitorRankingInfo;
import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo;
import com.sap.sailing.domain.regattalike.LeaderboardThatHasRegattaLike;
import com.sap.sailing.domain.sharding.ShardingContext;
import com.sap.sailing.domain.tracking.BravoFixTrack;
import com.sap.sailing.domain.tracking.GPSFixTrack;
import com.sap.sailing.domain.tracking.Maneuver;
@@ -355,6 +357,7 @@ public abstract class AbstractLeaderboardWithCache implements Leaderboard {
final boolean waitForLatestAnalyses, TrackedRegattaRegistry trackedRegattaRegistry, final DomainFactory baseDomainFactory,
final boolean fillTotalPointsUncorrected)
throws NoWindException {
ShardingContext.checkConstraint(ShardingType.LEADERBOARDNAME, getName());
long startOfRequestHandling = System.currentTimeMillis();
final LeaderboardDTOCalculationReuseCache cache = new LeaderboardDTOCalculationReuseCache(timePoint);
final BoatClass boatClass = getBoatClass();
@@ -52,16 +52,17 @@ import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
/**
* Base implementation for various types of leaderboards. The {@link RaceColumnListener} implementation forwards events
* received to all {@link RaceColumnListener} subscribed with this leaderboard. To which objects this leaderboard subscribes
* as {@link RaceColumnListener} is left to the concrete subclasses to implement, but the race columns seem like useful
* candidates.
* received to all {@link RaceColumnListener} subscribed with this leaderboard. To which objects this leaderboard
* subscribes as {@link RaceColumnListener} is left to the concrete subclasses to implement, but the race columns seem
* like useful candidates.
*
* @author Axel Uhl (d043530)
*
*/
public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardWithCache implements Leaderboard, RaceColumnListener {
public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardWithCache
implements Leaderboard, RaceColumnListener {
private static final long serialVersionUID = 330156778603279333L;
static final Double DOUBLE_0 = new Double(0);
private final SettableScoreCorrection scoreCorrection;
@@ -75,15 +76,15 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
private final Map<Competitor, String> displayNames;
/**
* Backs the {@link #getCarriedPoints(Competitor)} API with data. Can be used to prime this leaderboard
* with aggregated results of races not tracked / displayed by this leaderboard in detail. The points
* provided by this map are considered by {@link #getNetPoints(Competitor, TimePoint)}.
* Backs the {@link #getCarriedPoints(Competitor)} API with data. Can be used to prime this leaderboard with
* aggregated results of races not tracked / displayed by this leaderboard in detail. The points provided by this
* map are considered by {@link #getNetPoints(Competitor, TimePoint)}.
*/
private final Map<Competitor, Double> carriedPoints;
/**
* A set that manages the difference between {@link #getCompetitors()} and {@link #getAllCompetitors()}. Access
* is controlled by the {@link #suppressedCompetitorsLock} lock.
* A set that manages the difference between {@link #getCompetitors()} and {@link #getAllCompetitors()}. Access is
* controlled by the {@link #suppressedCompetitorsLock} lock.
*/
private final Set<Competitor> suppressedCompetitors;
private final NamedReentrantReadWriteLock suppressedCompetitorsLock;
@@ -107,8 +108,8 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
private final Fleet fleet;
private EntryImpl(Callable<Integer> trackedRankProvider, Double totalPoints,
Callable<Double> totalPointsUncorrectedProvider, boolean isTotalPointsCorrected,
Double netPoints, MaxPointsReason maxPointsReason, boolean discarded, Fleet fleet) {
Callable<Double> totalPointsUncorrectedProvider, boolean isTotalPointsCorrected, Double netPoints,
MaxPointsReason maxPointsReason, boolean discarded, Fleet fleet) {
super();
this.trackedRankProvider = trackedRankProvider;
this.totalPoints = totalPoints;
@@ -119,6 +120,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
this.discarded = discarded;
this.fleet = fleet;
}
@Override
public int getTrackedRank() {
try {
@@ -127,30 +129,37 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
throw new RuntimeException(e);
}
}
@Override
public Double getTotalPoints() {
return totalPoints;
}
@Override
public boolean isTotalPointsCorrected() {
return isTotalPointsCorrected;
}
@Override
public Double getNetPoints() {
return netPoints;
}
@Override
public MaxPointsReason getMaxPointsReason() {
return maxPointsReason;
}
@Override
public boolean isDiscarded() {
return discarded;
}
@Override
public Fleet getFleet() {
return fleet;
}
@Override
public Double getTotalPointsUncorrected() {
try {
@@ -160,7 +169,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
}
}
/**
* Computing the competitors can be a bit expensive, particularly if the fleet is large and there may be suppressed
* competitors, and the leaderboard may be a meta-leaderboard that refers to other leaderboards which each have
@@ -171,10 +180,10 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
*
* As it turns out, one of the most frequent uses of the {@link AbstractSimpleLeaderboardImpl#getCompetitors}
* competitors list is to determine their number which in turn is only required for high-point scoring systems and
* for computing the default score for penalties. Again, the most frequently used low-point family of scoring schemes
* does not require this number. Yet, the scoring scheme requires an argument for polymorphic use by those that
* need it. Instead of computing it for each call, this interface lets us defer the actual calculation until the
* point when it's really needed. Once asked, this object will cache the result. Therefore, a new one should be
* for computing the default score for penalties. Again, the most frequently used low-point family of scoring
* schemes does not require this number. Yet, the scoring scheme requires an argument for polymorphic use by those
* that need it. Instead of computing it for each call, this interface lets us defer the actual calculation until
* the point when it's really needed. Once asked, this object will cache the result. Therefore, a new one should be
* constructed each time the number shall be computed.
*
* @author Axel Uhl (D043530)
@@ -183,7 +192,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
public class NumberOfCompetitorsFetcherImpl implements NumberOfCompetitorsInLeaderboardFetcher {
private int numberOfCompetitors = -1;
private int numberOfCompetitorsWithoutMaxPointReason = -1;
@Override
public int getNumberOfCompetitorsInLeaderboard() {
if (numberOfCompetitors == -1) {
@@ -191,7 +200,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
return numberOfCompetitors;
}
@Override
public int getNumberOfCompetitorsWithoutMaxPointReason(RaceColumn column, TimePoint timePoint) {
if (numberOfCompetitorsWithoutMaxPointReason == -1) {
@@ -215,17 +224,17 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
this.suppressedCompetitors = new HashSet<Competitor>();
this.suppressedCompetitorsLock = new NamedReentrantReadWriteLock("suppressedCompetitorsLock", /* fair */ false);
}
protected RaceColumnListeners getRaceColumnListeners() {
return raceColumnListeners;
}
@Override
public void trackedRaceUnlinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
getRaceColumnListeners().notifyListenersAboutTrackedRaceUnlinked(raceColumn, fleet, trackedRace);
super.trackedRaceUnlinked(raceColumn, fleet, trackedRace);
}
@Override
public void trackedRaceLinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
getRaceColumnListeners().notifyListenersAboutTrackedRaceLinked(raceColumn, fleet, trackedRace);
@@ -235,10 +244,11 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
public void isMedalRaceChanged(RaceColumn raceColumn, boolean newIsMedalRace) {
getRaceColumnListeners().notifyListenersAboutIsMedalRaceChanged(raceColumn, newIsMedalRace);
}
@Override
public void isFleetsCanRunInParallelChanged(RaceColumn raceColumn, boolean newIsFleetsCanRunInParallel) {
getRaceColumnListeners().notifyListenersAboutIsFleetsCanRunInParallelChanged(raceColumn, newIsFleetsCanRunInParallel);
getRaceColumnListeners().notifyListenersAboutIsFleetsCanRunInParallelChanged(raceColumn,
newIsFleetsCanRunInParallel);
}
@Override
@@ -247,13 +257,16 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
@Override
public void isFirstColumnIsNonDiscardableCarryForwardChanged(RaceColumn raceColumn, boolean firstColumnIsNonDiscardableCarryForward) {
getRaceColumnListeners().notifyListenersAboutIsFirstColumnIsNonDiscardableCarryForwardChanged(raceColumn, firstColumnIsNonDiscardableCarryForward);
public void isFirstColumnIsNonDiscardableCarryForwardChanged(RaceColumn raceColumn,
boolean firstColumnIsNonDiscardableCarryForward) {
getRaceColumnListeners().notifyListenersAboutIsFirstColumnIsNonDiscardableCarryForwardChanged(raceColumn,
firstColumnIsNonDiscardableCarryForward);
}
@Override
public void hasSplitFleetContiguousScoringChanged(RaceColumn raceColumn, boolean hasSplitFleetContiguousScoring) {
getRaceColumnListeners().notifyListenersAboutHasSplitFleetContiguousScoringChanged(raceColumn, hasSplitFleetContiguousScoring);
getRaceColumnListeners().notifyListenersAboutHasSplitFleetContiguousScoringChanged(raceColumn,
hasSplitFleetContiguousScoring);
}
@Override
@@ -283,11 +296,13 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
@Override
public void competitorDisplayNameChanged(Competitor competitor, String oldDisplayName, String displayName) {
getRaceColumnListeners().notifyListenersAboutCompetitorDisplayNameChanged(competitor, oldDisplayName, displayName);
getRaceColumnListeners().notifyListenersAboutCompetitorDisplayNameChanged(competitor, oldDisplayName,
displayName);
}
@Override
public void resultDiscardingRuleChanged(ResultDiscardingRule oldDiscardingRule, ResultDiscardingRule newDiscardingRule) {
public void resultDiscardingRuleChanged(ResultDiscardingRule oldDiscardingRule,
ResultDiscardingRule newDiscardingRule) {
getRaceColumnListeners().notifyListenersAboutResultDiscardingRuleChanged(oldDiscardingRule, newDiscardingRule);
}
@@ -304,7 +319,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
protected SettableScoreCorrection createScoreCorrection() {
return new ScoreCorrectionImpl(this);
}
@Override
public SettableScoreCorrection getScoreCorrection() {
return scoreCorrection;
@@ -372,7 +387,8 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
String oldDisplayName = displayNames.get(competitor);
displayNames.put(competitor, displayName);
if (!Util.equalsWithNull(oldDisplayName, displayName)) {
getRaceColumnListeners().notifyListenersAboutCompetitorDisplayNameChanged(competitor, oldDisplayName, displayName);
getRaceColumnListeners().notifyListenersAboutCompetitorDisplayNameChanged(competitor, oldDisplayName,
displayName);
}
}
@@ -385,9 +401,9 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
@Override
public Double getTotalPoints(final Competitor competitor, final RaceColumn raceColumn, final TimePoint timePoint) {
return getScoreCorrection().getCorrectedScore(
()->getTrackedRank(competitor, raceColumn, timePoint), competitor,
raceColumn, this, timePoint, new NumberOfCompetitorsFetcherImpl(), getScoringScheme()).getCorrectedScore();
return getScoreCorrection().getCorrectedScore(() -> getTrackedRank(competitor, raceColumn, timePoint),
competitor, raceColumn, this, timePoint, new NumberOfCompetitorsFetcherImpl(), getScoringScheme())
.getCorrectedScore();
}
@Override
@@ -399,19 +415,19 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
public boolean isDiscarded(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint) {
return isDiscarded(competitor, raceColumn, getRaceColumns(), timePoint);
}
private boolean isDiscarded(Competitor competitor, RaceColumn raceColumn,
Iterable<RaceColumn> raceColumnsToConsider, TimePoint timePoint) {
final Set<RaceColumn> discardedRaceColumns = getResultDiscardingRule()
.getDiscardedRaceColumns(competitor, this, raceColumnsToConsider, timePoint);
final Set<RaceColumn> discardedRaceColumns = getResultDiscardingRule().getDiscardedRaceColumns(competitor, this,
raceColumnsToConsider, timePoint);
return isDiscarded(competitor, raceColumn, timePoint, discardedRaceColumns);
}
/**
* Same as {@link #isDiscarded(Competitor, RaceColumn, TimePoint)}, only that the set of discarded race columns can
* be specified which is useful when net points are to be computed for more than one column for the same
* competitor because then the calculation of discards (which requires looking at all columns) only needs to be done
* once and not again for each column (which would lead to quadratic effort).
* be specified which is useful when net points are to be computed for more than one column for the same competitor
* because then the calculation of discards (which requires looking at all columns) only needs to be done once and
* not again for each column (which would lead to quadratic effort).
*
* @param discardedRaceColumns
* expected to be the result of what we would get if we called {@link #getResultDiscardingRule()}.
@@ -420,8 +436,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
*/
private boolean isDiscarded(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint,
final Set<RaceColumn> discardedRaceColumns) {
return !raceColumn.isMedalRace()
&& getMaxPointsReason(competitor, raceColumn, timePoint).isDiscardable()
return !raceColumn.isMedalRace() && getMaxPointsReason(competitor, raceColumn, timePoint).isDiscardable()
&& discardedRaceColumns.contains(raceColumn);
}
@@ -431,16 +446,16 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
@Override
public Double getNetPoints(Competitor competitor, RaceColumn raceColumn,
Iterable<RaceColumn> raceColumnsToConsider, TimePoint timePoint) {
final Set<RaceColumn> discardedRaceColumns = getResultDiscardingRule()
.getDiscardedRaceColumns(competitor, this, raceColumnsToConsider, timePoint);
public Double getNetPoints(Competitor competitor, RaceColumn raceColumn, Iterable<RaceColumn> raceColumnsToConsider,
TimePoint timePoint) {
final Set<RaceColumn> discardedRaceColumns = getResultDiscardingRule().getDiscardedRaceColumns(competitor, this,
raceColumnsToConsider, timePoint);
return getNetPoints(competitor, raceColumn, timePoint, discardedRaceColumns);
}
/**
* Same as {@link #getNetPoints(Competitor, RaceColumn, Iterable, TimePoint)}, only that the set of discarded race columns can
* be specified which is useful when net points are to be computed for more than one column for the same
* Same as {@link #getNetPoints(Competitor, RaceColumn, Iterable, TimePoint)}, only that the set of discarded race
* columns can be specified which is useful when net points are to be computed for more than one column for the same
* competitor because then the calculation of discards (which requires looking at all columns) only needs to be done
* once and not again for each column (which would lead to quadratic effort).
*
@@ -450,7 +465,8 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
* getDiscardedRaceColumns(competitor, this, raceColumnsToConsider, timePoint)}.
*/
@Override
public Double getNetPoints(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint, Set<RaceColumn> discardedRaceColumns) {
public Double getNetPoints(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint,
Set<RaceColumn> discardedRaceColumns) {
Double result;
if (isDiscarded(competitor, raceColumn, timePoint, discardedRaceColumns)) {
result = 0.0;
@@ -473,11 +489,12 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
@Override
public Double getNetPoints(Competitor competitor, final Iterable<RaceColumn> raceColumnsToConsider,
TimePoint timePoint) {
// when a column with isStartsWithZeroScore() is found, only reset score if the competitor scored in any race from there on
// when a column with isStartsWithZeroScore() is found, only reset score if the competitor scored in any race
// from there on
boolean needToResetScoreUponNextNonEmptyEntry = false;
double result = getCarriedPoints(competitor);
final Set<RaceColumn> discardedRaceColumns = getResultDiscardingRule()
.getDiscardedRaceColumns(competitor, this, raceColumnsToConsider, timePoint);
final Set<RaceColumn> discardedRaceColumns = getResultDiscardingRule().getDiscardedRaceColumns(competitor, this,
raceColumnsToConsider, timePoint);
for (RaceColumn raceColumn : raceColumnsToConsider) {
if (raceColumn.isStartsWithZeroScore()) {
needToResetScoreUponNextNonEmptyEntry = true;
@@ -497,16 +514,19 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
/**
* All competitors with non-<code>null</code> total points are added to the result which is then sorted by total points in ascending
* order. The fleet, if ordered, is the primary ordering criterion, followed by the total points.
* All competitors with non-<code>null</code> total points are added to the result which is then sorted by total
* points in ascending order. The fleet, if ordered, is the primary ordering criterion, followed by the total
* points.
*/
@Override
public List<Competitor> getCompetitorsFromBestToWorst(final RaceColumn raceColumn, TimePoint timePoint) throws NoWindException {
public List<Competitor> getCompetitorsFromBestToWorst(final RaceColumn raceColumn, TimePoint timePoint)
throws NoWindException {
final Map<Competitor, com.sap.sse.common.Util.Pair<Double, Fleet>> totalPointsAndFleet = new HashMap<Competitor, com.sap.sse.common.Util.Pair<Double, Fleet>>();
for (Competitor competitor : getCompetitors()) {
Double totalPoints = getTotalPoints(competitor, raceColumn, timePoint);
if (totalPoints != null) {
totalPointsAndFleet.put(competitor, new com.sap.sse.common.Util.Pair<Double, Fleet>(totalPoints, raceColumn.getFleetOfCompetitor(competitor)));
totalPointsAndFleet.put(competitor, new com.sap.sse.common.Util.Pair<Double, Fleet>(totalPoints,
raceColumn.getFleetOfCompetitor(competitor)));
}
}
List<Competitor> result = new ArrayList<Competitor>(totalPointsAndFleet.keySet());
@@ -518,7 +538,8 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
comparisonResult = 0;
} else {
if (raceColumn.hasSplitFleets() && !raceColumn.hasSplitFleetContiguousScoring()) {
// only check fleets if there are more than one and the column is not to be contiguously scored even in case
// only check fleets if there are more than one and the column is not to be contiguously scored
// even in case
// of split fleets
final Fleet o1Fleet = totalPointsAndFleet.get(o1).getB();
final Fleet o2Fleet = totalPointsAndFleet.get(o2).getB();
@@ -537,13 +558,14 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
}
} else {
// either there are no split fleets or the split isn't relevant for scoring as for ordered fleets
// either there are no split fleets or the split isn't relevant for scoring as for ordered
// fleets
// the scoring runs contiguously from top to bottom
comparisonResult = 0;
}
if (comparisonResult == 0) {
comparisonResult = getScoringScheme().getScoreComparator(/* nullScoresAreBetter */ false).compare(
totalPointsAndFleet.get(o1).getA(), totalPointsAndFleet.get(o2).getA());
comparisonResult = getScoringScheme().getScoreComparator(/* nullScoresAreBetter */ false)
.compare(totalPointsAndFleet.get(o1).getA(), totalPointsAndFleet.get(o2).getA());
}
}
return comparisonResult;
@@ -559,11 +581,12 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
public List<Competitor> getCompetitorsFromBestToWorst(TimePoint timePoint) {
return getCompetitorsFromBestToWorst(getRaceColumns(), timePoint);
}
/**
* suppressed competitors are removed from the result
*/
private List<Competitor> getCompetitorsFromBestToWorst(Iterable<RaceColumn> raceColumnsToConsider, TimePoint timePoint) {
private List<Competitor> getCompetitorsFromBestToWorst(Iterable<RaceColumn> raceColumnsToConsider,
TimePoint timePoint) {
List<Competitor> result = new ArrayList<Competitor>();
for (Competitor competitor : getCompetitors()) {
result.add(competitor);
@@ -571,9 +594,11 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
Collections.sort(result, getTotalRankComparator(raceColumnsToConsider, timePoint));
return result;
}
protected Comparator<? super Competitor> getTotalRankComparator(Iterable<RaceColumn> raceColumnsToConsider, TimePoint timePoint) {
return new LeaderboardTotalRankComparator(this, timePoint, getScoringScheme(), /* nullScoresAreBetter */ false, raceColumnsToConsider);
protected Comparator<? super Competitor> getTotalRankComparator(Iterable<RaceColumn> raceColumnsToConsider,
TimePoint timePoint) {
return new LeaderboardTotalRankComparator(this, timePoint, getScoringScheme(), /* nullScoresAreBetter */ false,
raceColumnsToConsider);
}
@Override
@@ -599,15 +624,16 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
@Override
public boolean countRaceForComparisonWithDiscardingThresholds(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint) {
public boolean countRaceForComparisonWithDiscardingThresholds(Competitor competitor, RaceColumn raceColumn,
TimePoint timePoint) {
TrackedRace trackedRaceForCompetitorInColumn;
return getScoringScheme().isValidInNetScore(this, raceColumn, competitor, timePoint) &&
(getScoreCorrection().isScoreCorrected(competitor, raceColumn, timePoint) ||
((trackedRaceForCompetitorInColumn=raceColumn.getTrackedRace(competitor)) != null &&
trackedRaceForCompetitorInColumn.hasStarted(timePoint) &&
trackedRaceForCompetitorInColumn.getRank(competitor, timePoint) != 0));
return getScoringScheme().isValidInNetScore(this, raceColumn, competitor, timePoint)
&& (getScoreCorrection().isScoreCorrected(competitor, raceColumn, timePoint)
|| ((trackedRaceForCompetitorInColumn = raceColumn.getTrackedRace(competitor)) != null
&& trackedRaceForCompetitorInColumn.hasStarted(timePoint)
&& trackedRaceForCompetitorInColumn.getRank(competitor, timePoint) != 0));
}
@Override
public void addRaceColumnListener(RaceColumnListener listener) {
getRaceColumnListeners().addRaceColumnListener(listener);
@@ -619,27 +645,31 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
@Override
public Entry getEntry(final Competitor competitor, final RaceColumn race, final TimePoint timePoint) throws NoWindException {
final Set<RaceColumn> discardedRaceColumns = getResultDiscardingRule().getDiscardedRaceColumns(competitor, this, getRaceColumns(), timePoint);
public Entry getEntry(final Competitor competitor, final RaceColumn race, final TimePoint timePoint)
throws NoWindException {
final Set<RaceColumn> discardedRaceColumns = getResultDiscardingRule().getDiscardedRaceColumns(competitor, this,
getRaceColumns(), timePoint);
return getEntry(competitor, race, timePoint, discardedRaceColumns);
}
@Override
public Entry getEntry(final Competitor competitor, final RaceColumn race, final TimePoint timePoint,
Set<RaceColumn> discardedRaceColumns) throws NoWindException {
Callable<Integer> trackedRankProvider = ()->getTrackedRank(competitor, race, timePoint);
Callable<Integer> trackedRankProvider = () -> getTrackedRank(competitor, race, timePoint);
final Result correctedResults = getScoreCorrection().getCorrectedScore(trackedRankProvider, competitor, race,
this, timePoint, new NumberOfCompetitorsFetcherImpl(), getScoringScheme());
boolean discarded = isDiscarded(competitor, race, timePoint, discardedRaceColumns);
final Double correctedScore = correctedResults.getCorrectedScore();
return new EntryImpl(trackedRankProvider, correctedScore, ()->correctedResults.getUncorrectedScore(),
correctedResults.isCorrected(), discarded ? DOUBLE_0 : correctedScore == null ? null
: Double.valueOf(correctedScore * race.getFactor()), correctedResults.getMaxPointsReason(), discarded,
race.getFleetOfCompetitor(competitor));
return new EntryImpl(trackedRankProvider, correctedScore, () -> correctedResults.getUncorrectedScore(),
correctedResults.isCorrected(),
discarded ? DOUBLE_0
: correctedScore == null ? null : Double.valueOf(correctedScore * race.getFactor()),
correctedResults.getMaxPointsReason(), discarded, race.getFleetOfCompetitor(competitor));
}
@Override
public Map<RaceColumn, List<Competitor>> getRankedCompetitorsFromBestToWorstAfterEachRaceColumn(TimePoint timePoint) throws NoWindException {
public Map<RaceColumn, List<Competitor>> getRankedCompetitorsFromBestToWorstAfterEachRaceColumn(TimePoint timePoint)
throws NoWindException {
Map<RaceColumn, List<Competitor>> result = new LinkedHashMap<>();
List<RaceColumn> raceColumnsToConsider = new ArrayList<>();
for (RaceColumn raceColumn : getRaceColumns()) {
@@ -663,7 +693,8 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
public Map<Competitor, Double> call() {
Map<Competitor, Double> netPointsSumPerCompetitorInColumn = new HashMap<>();
for (Competitor competitor : getCompetitors()) {
netPointsSumPerCompetitorInColumn.put(competitor, getNetPoints(competitor, finalRaceColumnsToConsider, timePoint));
netPointsSumPerCompetitorInColumn.put(competitor,
getNetPoints(competitor, finalRaceColumnsToConsider, timePoint));
}
synchronized (result) {
return netPointsSumPerCompetitorInColumn;
@@ -686,27 +717,29 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
@Override
public Map<com.sap.sse.common.Util.Pair<Competitor, RaceColumn>, Entry> getContent(final TimePoint timePoint) throws NoWindException {
public Map<com.sap.sse.common.Util.Pair<Competitor, RaceColumn>, Entry> getContent(final TimePoint timePoint)
throws NoWindException {
Map<com.sap.sse.common.Util.Pair<Competitor, RaceColumn>, Entry> result = new HashMap<com.sap.sse.common.Util.Pair<Competitor, RaceColumn>, Entry>();
Map<Competitor, Set<RaceColumn>> discardedRaces = new HashMap<Competitor, Set<RaceColumn>>();
for (final RaceColumn raceColumn : getRaceColumns()) {
for (final Competitor competitor : getCompetitors()) {
Callable<Integer> trackedRankProvider = ()->getTrackedRank(competitor, raceColumn, timePoint);
final Result correctedResults = getScoreCorrection().getCorrectedScore(trackedRankProvider, competitor, raceColumn,
this, timePoint, new NumberOfCompetitorsFetcherImpl(), getScoringScheme());
Callable<Integer> trackedRankProvider = () -> getTrackedRank(competitor, raceColumn, timePoint);
final Result correctedResults = getScoreCorrection().getCorrectedScore(trackedRankProvider, competitor,
raceColumn, this, timePoint, new NumberOfCompetitorsFetcherImpl(), getScoringScheme());
Set<RaceColumn> discardedRacesForCompetitor = discardedRaces.get(competitor);
if (discardedRacesForCompetitor == null) {
discardedRacesForCompetitor = getResultDiscardingRule().getDiscardedRaceColumns(competitor, this, getRaceColumns(), timePoint);
discardedRacesForCompetitor = getResultDiscardingRule().getDiscardedRaceColumns(competitor, this,
getRaceColumns(), timePoint);
discardedRaces.put(competitor, discardedRacesForCompetitor);
}
boolean discarded = discardedRacesForCompetitor.contains(raceColumn);
final Double correctedScore = correctedResults.getCorrectedScore();
Entry entry = new EntryImpl(trackedRankProvider, correctedScore,
()->correctedResults.getUncorrectedScore(),
correctedResults.isCorrected(),
discarded ? DOUBLE_0 : (correctedScore==null?null:
Double.valueOf((correctedScore * raceColumn.getFactor()))), correctedResults.getMaxPointsReason(),
discarded, raceColumn.getFleetOfCompetitor(competitor));
() -> correctedResults.getUncorrectedScore(), correctedResults.isCorrected(),
discarded ? DOUBLE_0
: (correctedScore == null ? null
: Double.valueOf((correctedScore * raceColumn.getFactor()))),
correctedResults.getMaxPointsReason(), discarded, raceColumn.getFleetOfCompetitor(competitor));
result.put(new com.sap.sse.common.Util.Pair<Competitor, RaceColumn>(competitor, raceColumn), entry);
}
}
@@ -714,7 +747,8 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
/**
* A leaderboard will only accept the addition of a race column if the column's name is unique across the leaderboard.
* A leaderboard will only accept the addition of a race column if the column's name is unique across the
* leaderboard.
*/
@Override
public boolean canAddRaceColumnToContainer(RaceColumn newRaceColumn) {
@@ -731,17 +765,18 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
/**
* Finds out the time point when any of the {@link Leaderboard#getTrackedRaces() tracked races currently attached to
* the <code>leaderboard</code>} and the {@link Leaderboard#getScoreCorrection() score corrections} have last been
* modified. If no tracked race is attached and no time-stamped score corrections have been applied to the leaderboard,
* <code>null</code> is returned. The time point computed this way is a good choice for normalizing queries for later time
* points in an attempt to achieve more cache hits.<p>
* modified. If no tracked race is attached and no time-stamped score corrections have been applied to the
* leaderboard, <code>null</code> is returned. The time point computed this way is a good choice for normalizing
* queries for later time points in an attempt to achieve more cache hits.
* <p>
*
* Note, however, that the result does not tell about structural changes to the leaderboard and therefore cannot be used
* to determine the need for cache invalidation. For example, if a column is added to a leaderboard after the time point
* returned by this method but that column's attached tracked race has finished before the time point returned by this method,
* the result of this method won't change. Still, the contents of the leaderboard will change by a change in column structure.
* A different means to determine the possibility of changes that happened to this leaderboard must be used for cache
* management. Such a facility has to listen for score correction changes, tracked races being attached or detached and
* the column structure changing.
* Note, however, that the result does not tell about structural changes to the leaderboard and therefore cannot be
* used to determine the need for cache invalidation. For example, if a column is added to a leaderboard after the
* time point returned by this method but that column's attached tracked race has finished before the time point
* returned by this method, the result of this method won't change. Still, the contents of the leaderboard will
* change by a change in column structure. A different means to determine the possibility of changes that happened
* to this leaderboard must be used for cache management. Such a facility has to listen for score correction
* changes, tracked races being attached or detached and the column structure changing.
*
* @see TrackedRace#getTimePointOfNewestEvent()
* @see SettableScoreCorrection#getTimePointOfLastCorrectionsValidity()
@@ -750,19 +785,22 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
public TimePoint getTimePointOfLatestModification() {
TimePoint result = null;
for (TrackedRace trackedRace : getTrackedRaces()) {
if (result == null || (trackedRace.getTimePointOfNewestEvent() != null && trackedRace.getTimePointOfNewestEvent().after(result))) {
if (result == null || (trackedRace.getTimePointOfNewestEvent() != null
&& trackedRace.getTimePointOfNewestEvent().after(result))) {
result = trackedRace.getTimePointOfNewestEvent();
}
}
TimePoint timePointOfLastScoreCorrection = getScoreCorrection().getTimePointOfLastCorrectionsValidity();
if (timePointOfLastScoreCorrection != null && (result == null || timePointOfLastScoreCorrection.after(result))) {
if (timePointOfLastScoreCorrection != null
&& (result == null || timePointOfLastScoreCorrection.after(result))) {
result = timePointOfLastScoreCorrection;
}
return result;
}
@Override
public com.sap.sse.common.Util.Pair<GPSFixMoving, Speed> getMaximumSpeedOverGround(Competitor competitor, TimePoint timePoint) {
public com.sap.sse.common.Util.Pair<GPSFixMoving, Speed> getMaximumSpeedOverGround(Competitor competitor,
TimePoint timePoint) {
com.sap.sse.common.Util.Pair<GPSFixMoving, Speed> result = null;
// TODO should we ensure that competitor participated in all race columns?
for (TrackedRace trackedRace : getTrackedRaces()) {
@@ -771,16 +809,17 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
if (!markPassings.isEmpty()) {
TimePoint from = markPassings.first().getTimePoint();
TimePoint to;
if (timePoint.after(markPassings.last().getTimePoint()) &&
markPassings.last().getWaypoint() == trackedRace.getRace().getCourse().getLastWaypoint()) {
if (timePoint.after(markPassings.last().getTimePoint()) && markPassings.last()
.getWaypoint() == trackedRace.getRace().getCourse().getLastWaypoint()) {
// stop counting when competitor finished the race
to = markPassings.last().getTimePoint();
} else {
to = timePoint;
}
com.sap.sse.common.Util.Pair<GPSFixMoving, Speed> maxSpeed = trackedRace.getTrack(competitor).getMaximumSpeedOverGround(from, to);
if (result == null || result.getB() == null ||
(maxSpeed != null && maxSpeed.getB() != null && maxSpeed.getB().compareTo(result.getB()) > 0)) {
com.sap.sse.common.Util.Pair<GPSFixMoving, Speed> maxSpeed = trackedRace.getTrack(competitor)
.getMaximumSpeedOverGround(from, to);
if (result == null || result.getB() == null || (maxSpeed != null && maxSpeed.getB() != null
&& maxSpeed.getB().compareTo(result.getB()) > 0)) {
result = maxSpeed;
}
}
@@ -799,7 +838,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
return result;
}
@Override
public Iterable<Competitor> getCompetitors() {
final Iterable<Competitor> result;
@@ -815,10 +854,11 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
return result;
}
@Override
public Iterable<Competitor> getCompetitors(RaceColumn raceColumn, Fleet fleet) {
return getCompetitorIterableSkippingSuppressed(getAllCompetitors(raceColumn, fleet), getSuppressedCompetitors());
return getCompetitorIterableSkippingSuppressed(getAllCompetitors(raceColumn, fleet),
getSuppressedCompetitors());
}
/**
@@ -838,7 +878,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
LockUtil.unlockAfterRead(suppressedCompetitorsLock);
}
}
@Override
public boolean isSuppressed(Competitor competitor) {
LockUtil.lockForRead(suppressedCompetitorsLock);
@@ -848,12 +888,12 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
LockUtil.unlockAfterRead(suppressedCompetitorsLock);
}
}
@Override
public void setSuppressed(Competitor competitor, boolean suppressed) {
if (competitor == null) {
throw new IllegalArgumentException("Cannot change suppression for a null competitor");
}
if (competitor == null) {
throw new IllegalArgumentException("Cannot change suppression for a null competitor");
}
LockUtil.lockForWrite(suppressedCompetitorsLock);
try {
if (suppressed) {
@@ -874,7 +914,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
TimePoint timePoint = delayToLiveInMillis == null ? now : now.minus(delayToLiveInMillis);
return timePoint;
}
@Override
public void raceLogEventAdded(RaceColumn raceColumn, RaceLogIdentifier raceLogIdentifier, RaceLogEvent event) {
getRaceColumnListeners().notifyListenersAboutRaceLogEventAdded(raceColumn, raceLogIdentifier, event);
@@ -887,14 +927,16 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
public String toString() {
return getName() + " " + (getDefaultCourseArea() != null ? getDefaultCourseArea().getName() : "<No course area defined>") + " " + (getScoringScheme() != null ? getScoringScheme().getType().name() : "<No scoring scheme set>");
return getName() + " "
+ (getDefaultCourseArea() != null ? getDefaultCourseArea().getName() : "<No course area defined>") + " "
+ (getScoringScheme() != null ? getScoringScheme().getType().name() : "<No scoring scheme set>");
}
@Override
public NumberOfCompetitorsInLeaderboardFetcher getNumberOfCompetitorsInLeaderboardFetcher() {
return new NumberOfCompetitorsFetcherImpl();
}
@Override
public Pair<RaceColumn, Fleet> getRaceColumnAndFleet(TrackedRace trackedRace) {
for (final RaceColumn raceColumn : getRaceColumns()) {
@@ -914,8 +956,8 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
Map<Competitor, Boat> competitorsAndTheirBoats = raceColumn.getAllCompetitorsAndTheirBoats();
allBoats.addAll(competitorsAndTheirBoats.values());
}
return Util.getDominantObject(StreamSupport.stream(allBoats.spliterator(), /* parallel */ false).
map(b->b.getBoatClass()).collect(Collectors.toList()));
return Util.getDominantObject(StreamSupport.stream(allBoats.spliterator(), /* parallel */ false)
.map(b -> b.getBoatClass()).collect(Collectors.toList()));
}
}
@@ -1,121 +0,0 @@
package com.sap.sailing.domain.racelog.impl;
import java.util.List;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDeviceCompetitorMappingFinder;
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDeviceMarkMappingFinder;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.common.tracking.GPSFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
import com.sap.sailing.domain.racelog.tracking.SensorFixStore;
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
import com.sap.sailing.domain.racelogtracking.DeviceMappingWithRegattaLogEvent;
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
/**
* At the moment, the timerange covered by the fixes for a device, and the number of fixes for a device are stored in a
* metadata collection. Should be changed, see bug 1982.
*
* @author Fredrik Teschke
*/
public class GPSFixStoreImpl implements GPSFixStore {
private final SensorFixStore sensorFixStore;
public GPSFixStoreImpl(SensorFixStore sensorFixStore) {
this.sensorFixStore = sensorFixStore;
}
private <FixT extends GPSFix> void loadTrack(DynamicGPSFixTrack<?, FixT> track, DeviceIdentifier device,
TimePoint from, TimePoint to, boolean toIsInclusive)
throws NoCorrespondingServiceRegisteredException, TransformationException {
loadTrack(track, device, from, to, toIsInclusive, () -> {
return false;
}, (c) -> {
});
}
private <FixT extends GPSFix> void loadTrack(DynamicGPSFixTrack<?, FixT> track, DeviceIdentifier device,
TimePoint from, TimePoint to, boolean toIsInclusive, BooleanSupplier isPreemptiveStopped,
Consumer<Double> progress)
throws NoCorrespondingServiceRegisteredException, TransformationException {
sensorFixStore.<FixT> loadFixes(fix -> track.add(fix, /* replace */ true), device, from, to, toIsInclusive,
isPreemptiveStopped, progress);
}
@Override
public void loadCompetitorTrack(DynamicGPSFixTrack<Competitor, GPSFixMoving> track, RegattaLog log,
Competitor competitor) throws NoCorrespondingServiceRegisteredException, TransformationException {
List<DeviceMappingWithRegattaLogEvent<Competitor>> mappings = new RegattaLogDeviceCompetitorMappingFinder(log)
.analyze().get(competitor);
if (mappings != null) {
for (DeviceMapping<Competitor> mapping : mappings) {
loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(),
false /* toIsInclusive */);
}
}
}
@Override
public void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, RegattaLog log, Mark mark)
throws NoCorrespondingServiceRegisteredException, TransformationException {
List<DeviceMappingWithRegattaLogEvent<Mark>> mappings = new RegattaLogDeviceMarkMappingFinder(log).analyze()
.get(mark);
if (mappings != null) {
for (DeviceMapping<Mark> mapping : mappings) {
loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(),
false /* toIsInclusive */);
}
}
}
@Override
public void storeFix(DeviceIdentifier device, GPSFix fix) {
sensorFixStore.storeFix(device, fix);
}
@Override
public void loadCompetitorTrack(DynamicGPSFixTrack<Competitor, GPSFixMoving> track,
DeviceMapping<Competitor> mapping, TimePoint start, TimePoint end, BooleanSupplier isPreemptiveStopped,
Consumer<Double> progressReporter)
throws TransformationException, NoCorrespondingServiceRegisteredException {
// loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(), true
// /*inclusive*/);
final TimePoint from = Util.getLatestOfTimePoints(start, mapping.getTimeRange().from());
final TimePoint to = Util.getEarliestOfTimePoints(end, mapping.getTimeRange().to());
loadTrack(track, mapping.getDevice(), from, to, true /* inclusive */, isPreemptiveStopped, progressReporter);
}
@Override
public void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, DeviceMapping<Mark> mapping, TimePoint start,
TimePoint end, BooleanSupplier isPreemptiveStopped, Consumer<Double> progressReport)
throws TransformationException, NoCorrespondingServiceRegisteredException {
final TimePoint from = Util.getLatestOfTimePoints(start, mapping.getTimeRange().from());
final TimePoint to = Util.getEarliestOfTimePoints(end, mapping.getTimeRange().to());
loadTrack(track, mapping.getDevice(), from, to, true /* inclusive */, isPreemptiveStopped, progressReport);
}
@Override
public void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, RegattaLog log, Mark mark, TimePoint start,
TimePoint end) throws TransformationException, NoCorrespondingServiceRegisteredException {
List<DeviceMappingWithRegattaLogEvent<Mark>> mappings = new RegattaLogDeviceMarkMappingFinder(log).analyze()
.get(mark);
if (mappings != null) {
for (DeviceMapping<Mark> mapping : mappings) {
final TimePoint from = Util.getLatestOfTimePoints(start, mapping.getTimeRange().from());
final TimePoint to = Util.getEarliestOfTimePoints(end, mapping.getTimeRange().to());
loadTrack(track, mapping.getDevice(), from, to, false /* toIsInclusive */);
}
}
}
}
@@ -1,54 +0,0 @@
package com.sap.sailing.domain.racelog.tracking;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.common.tracking.GPSFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.TimePoint;
public enum EmptyGPSFixStore implements GPSFixStore {
INSTANCE;
@Override
public void storeFix(DeviceIdentifier device, GPSFix fix) {
}
@Override
public void loadCompetitorTrack(DynamicGPSFixTrack<Competitor, GPSFixMoving> track,
RegattaLog log, Competitor competitor) {
}
@Override
public void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track,
RegattaLog log, Mark mark) {
}
@Override
public void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, RegattaLog log, Mark mark,
TimePoint start, TimePoint end) throws TransformationException, NoCorrespondingServiceRegisteredException {
}
@Override
public void loadCompetitorTrack(DynamicGPSFixTrack<Competitor, GPSFixMoving> track,
DeviceMapping<Competitor> mapping, TimePoint start, TimePoint end, BooleanSupplier isPreemptiveStopped,
Consumer<Double> progressReporter)
throws TransformationException, NoCorrespondingServiceRegisteredException {
}
@Override
public void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, DeviceMapping<Mark> mapping, TimePoint start,
TimePoint end, BooleanSupplier isPreemptiveStopped, Consumer<Double> progressReporter)
throws TransformationException, NoCorrespondingServiceRegisteredException {
}
}
@@ -1,61 +0,0 @@
package com.sap.sailing.domain.racelog.tracking;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.common.tracking.GPSFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.TimePoint;
public interface GPSFixStore {
/**
* Load all fixes that correspond to the {@link RegattaLogDeviceCompetitorMappingEvent}s found in the {@code raceLog}.
*/
void loadCompetitorTrack(DynamicGPSFixTrack<Competitor, GPSFixMoving> track, RegattaLog log,
Competitor competitor) throws TransformationException;
/**
* Load all fixes that correspond to the {@link RegattaLogDeviceMarkMappingEvent}s found in the {@code raceLog}.
*/
void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, RegattaLog log, Mark mark) throws TransformationException,
NoCorrespondingServiceRegisteredException;
/**
* Load all fixes within the start and end time point (inclusive) that correspond to the
* {@link RegattaLogDeviceMarkMappingEvent}s found in the {@code raceLog}.
*
* @param start
* if <code>null</code>, the start of the time range for which to load fixes is only constrained by the
* device mapping intervals
* @param end
* if <code>null</code>, the end of the time range for which to load fixes is only constrained by the
* device mapping intervals
*/
void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, RegattaLog log, Mark mark, TimePoint start,
TimePoint end) throws TransformationException, NoCorrespondingServiceRegisteredException;
void loadCompetitorTrack(DynamicGPSFixTrack<Competitor, GPSFixMoving> track, DeviceMapping<Competitor> mapping,
TimePoint start, TimePoint end, BooleanSupplier isPreemptiveStopped, Consumer<Double> progressReporter)
throws TransformationException, NoCorrespondingServiceRegisteredException;
/**
* Load all fixes that correspond to the {@code mapping}.
*/
void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, DeviceMapping<Mark> mapping, TimePoint start,
TimePoint end, BooleanSupplier isPreemptiveStopped, Consumer<Double> progressReport)
throws TransformationException,
NoCorrespondingServiceRegisteredException;
void storeFix(DeviceIdentifier device, GPSFix fix) throws TransformationException, NoCorrespondingServiceRegisteredException;
}
@@ -0,0 +1,121 @@
package com.sap.sailing.domain.sharding;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sailing.domain.common.sharding.ShardingType;
import com.sap.sailing.domain.leaderboard.caching.LiveLeaderboardUpdater;
/**
* The sharding context is used to store and verify contraints for a thread.
*
* This is currently used to verify if a given thread, that is explicitly expected to only
* trigger the calculation of a given leaderboard, does trigger the calculation of further/ other
* leaderboards.
*
* It is also used to log warnings if a leaderboard is calculated without predefining the thread constraint.
*
* The enum {@link ShardingType} lists the known sharding types. Each sharding type defines a prefix that will
* be used to identify the sharding type from the request, as implemented in {@link #identifyAndSetShardingConstraint(String)}.
*
* By calling {@link #setShardingConstraint(ShardingType, String)} it is possible to directly set a thread constraint.
* This is useful in background computing code, as in {@link LiveLeaderboardUpdater}
*
*/
public class ShardingContext {
private static final Logger logger = Logger.getLogger(ShardingContext.class.getName());
private static final ConcurrentMap<ShardingType, ThreadLocal<String>> shardingMap = new ConcurrentHashMap<>();
/**
* Sets the sharding context. The type of sharding will be identified by the prefix.
*
* @param shardingInfo
*/
public static ShardingType identifyAndSetShardingConstraint(String shardingInfo) {
if (shardingInfo == null || shardingInfo.isEmpty()) {
logger.warning("Empty sharding constraint");
return null;
}
ThreadLocal<String> identifiedShardingHolder = null;
for (ShardingType shardingType : ShardingType.values()) {
if (shardingInfo.startsWith(shardingType.getPrefix())) {
identifiedShardingHolder = shardingMap.computeIfAbsent(shardingType, t -> new ThreadLocal<>());
checkAndSetShardingInfo(shardingType, shardingInfo, identifiedShardingHolder);
return shardingType;
}
}
if (identifiedShardingHolder == null) {
logger.warning("Could not identify sharding type for: " + shardingInfo);
}
return null;
}
/**
* Provide sharding constraint for given sharding type.
*
* @param shardingType
* @param shardingInfo
*/
public static void setShardingConstraint(ShardingType shardingType, String shardingInfo) {
final String encodedShardingInfo = shardingType.encodeIfNeeded(shardingInfo);
ThreadLocal<String> shardingHolder = shardingMap.computeIfAbsent(shardingType, t -> new ThreadLocal<>());
checkAndSetShardingInfo(shardingType, encodedShardingInfo, shardingHolder);
}
/**
* Check if provided sharding information name equals shard constraint.
*
* If the information is null or empty, we log a warning.
* If shard does not have a constraint, we log a warning. If
* the information provided does not match information previously stored in shard,
* we make a severe log entry.
*
* @param shardingInfo
*/
public static void checkConstraint(final ShardingType type, final String shardingInfo) {
if (shardingInfo == null || shardingInfo.isEmpty()) {
logger.warning("Empty sharding constraint");
return;
}
final ThreadLocal<String> shardingHolder = shardingMap.get(type);
if (shardingHolder == null) {
logger.log(Level.WARNING, "No current sharding context set for " + type.name(), new RuntimeException());
return;
}
String currentShardingInfo = shardingHolder.get();
if (currentShardingInfo == null || currentShardingInfo.isEmpty()) {
logger.warning("No current sharding constraint for " + type.name());
return;
}
final String encodedShardingInfo = type.encodeIfNeeded(shardingInfo);
if (!encodedShardingInfo.equals(currentShardingInfo)) {
logger.log(Level.SEVERE, "Current sharding constraint vialation for " + type.name() + ". Got "
+ shardingInfo + ", shard requires " + currentShardingInfo, new RuntimeException());
return;
}
}
public static void clearShardingConstraint(ShardingType type) {
ThreadLocal<String> shardingHolder = shardingMap.get(type);
if (shardingHolder != null) {
shardingHolder.remove();
}
}
private static void checkAndSetShardingInfo(ShardingType shardingType, String encodedShardingInfo,
ThreadLocal<String> shardingHolder) {
if (encodedShardingInfo == null || encodedShardingInfo.isEmpty()) {
logger.log(Level.SEVERE, "Cannot set empty sharding information for " + shardingType.name(),
new RuntimeException());
}
String currentShardingInfo = shardingHolder.get();
if (currentShardingInfo == null) {
shardingHolder.set(encodedShardingInfo);
} else if (!encodedShardingInfo.equals(currentShardingInfo)) {
logger.log(Level.SEVERE, "Switching shard constraint for " + shardingType.name()+". Got <<" + encodedShardingInfo +">>, expeted <<"+ currentShardingInfo+">>", new RuntimeException());
}
}
}
@@ -49,7 +49,7 @@ import com.sap.sailing.domain.leaderboard.caching.LeaderboardDTOCalculationReuse
import com.sap.sailing.domain.markpassingcalculation.MarkPassingCalculator;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
import com.sap.sailing.domain.racelog.tracking.SensorFixStore;
import com.sap.sailing.domain.ranking.RankingMetric;
import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo;
import com.sap.sailing.domain.tracking.impl.NonCachingMarkPositionAtTimePointCache;
@@ -773,7 +773,7 @@ public interface TrackedRace extends Serializable, IsManagedByCache<SharedDomain
void waitUntilLoadingFromWindStoreComplete() throws InterruptedException;
/**
* Whenever a {@link RegattaLog} is attached, fixes are loaded from the {@link GPSFixStore} for all mappings
* Whenever a {@link RegattaLog} is attached, fixes are loaded from the {@link SensorFixStore} for all mappings
* found in the {@code RegattaLog} in a separate thread. This method blocks if there is such a thread loading
* fixes, until that thread is finished.
*/
@@ -812,19 +812,19 @@ public interface TrackedRace extends Serializable, IsManagedByCache<SharedDomain
/**
* Attaches the passed race log with this {@link TrackedRace}.
* This causes fixes from the {@link GPSFixStore} to be loaded for such {@link RegattaLogDeviceMappingEvent}s
* that are present in the raceLog. This loading is offloaded into a separate thread, that blocks
* This causes fixes from the {@link SensorFixStore} to be loaded for such {@link RegattaLogDeviceMappingEvent RegattaLogDeviceMappingEvents}
* that are present in the {@link RaceLog raceLog}. This loading is offloaded into a separate thread, that blocks
* serialization until it is finished. If multiple race logs are attached, the loading process is
* forced to be serialized.
* To garuantee that a the fixes for a race log have been fully loaded before continuing,
* {@link #waitForLoadingFromGPSFixStoreToFinishRunning} can be used.
* To guarantee that a the fixes for a race log have been fully loaded before continuing,
* {@link #waitForLoadingToFinish()} can be used.
* @param raceLog to be attached.
*/
void attachRaceLog(RaceLog raceLog);
/**
* Attaches the passed regatta log with this {@link TrackedRace}.
* This also causes fixes from the {@link GPSFixStore} to be loaded (see {@link #attachRaceLog} for details).
* Attaches the passed {@link RegattaLog} with this {@link TrackedRace}.
* This also causes fixes from the {@link SensorFixStore} to be loaded (see {@link #attachRaceLog(RaceLog)} for details).
*/
void attachRegattaLog(RegattaLog regattaLog);
@@ -846,7 +846,7 @@ public interface TrackedRace extends Serializable, IsManagedByCache<SharedDomain
RaceLog getRaceLog(Serializable identifier);
/**
* A setter for the listener on course design changes suggested by one of the {@link RaceLog}s attached to this
* A setter for the listener on course design changes suggested by one of the {@link RaceLog RaceLog} attached to this
* race. The listener is mostly part of the tracking provider adapter.
*
* @param listener
+79 -13
View File
@@ -29,7 +29,7 @@ html {
body {
background: url(images/spectatorview-bg.png) no-repeat left top #ebebeb;
background: #eee;
font-family: 'Open Sans', Arial, Verdana, sans-serif;
line-height: 1;
font-size: 14px;
@@ -150,11 +150,6 @@ input.magnifier {
z-index: 2000;
}
.mainPanel {
width: 100%;
margin-left: 13px;
}
.errorLabel {
color: #FF0000;
}
@@ -221,15 +216,32 @@ input.magnifier {
top: 9px;
}
.groupingProvider {
padding: 3px 0px;
}
.groupingProviderElement {
margin: 2px;
display: inline-block;
}
.statisticProvider {
padding: 5px 0px 0px 0px;
}
.statisticProviderElement {
margin: 10px 2px 2px 2px;
margin: 2px;
display: inline-block;
}
.statisticSuggestBoxPopup {
z-index: 2;
}
.statisticSuggestBoxPopup .suggestPopupContent {
max-height: 700px;
overflow-y: scroll;
}
.definitionProviderControls {
margin: 2px;
}
@@ -238,14 +250,17 @@ input.magnifier {
margin: 2px;
}
.queryProviderElementLabel {
margin-left: 0px;
}
.queryDefinitionViewerContent {
background-color: white;
padding: 5px;
}
.statisticSuggestBoxPopup .suggestPopupContent {
max-height: 700px;
overflow-y: scroll;
.filterDimensionsTitleLabel {
padding-top: 5px;
}
.filterFilterDimensionsPanel {
@@ -254,7 +269,6 @@ input.magnifier {
.dimensionFilterSelectionTablesContainer {
overflow-x: auto;
border-left: 2px solid #6f7277;
}
.dimensionFilterSelectionHeader {
@@ -267,6 +281,58 @@ input.magnifier {
text-shadow: #ddf 1px 1px 0;
}
.dimensionFilterSelectionTable {
border-top: 2px solid #6f7277;
.dataMiningBorderTop {
border-top: 2px solid #6f7277;
}
.dataMiningBorderLeft {
border-left: 2px solid #6f7277;
}
.dataMiningBorderBottom {
border-border: 2px solid #6f7277;
}
.dataMiningBorderRight {
border-right: 2px solid #6f7277;
}
.gwt-SplitLayoutPanel-VDragger {
background: #fff url(images/thumb_horz.png) center center no-repeat;
width: 100% !important;
height: 100% !important;
left: 0 !important;
top: 0 !important;
border: none;
border-radius: 0px;
opacity: 1;
}
.gwt-SplitLayoutPanel-HDragger {
background: #fff url(images/thumb_vertical.png) center center no-repeat;
width: 100% !important;
height: 100% !important;
left: 0 !important;
top: 0 !important;
border: none;
border-radius: 0px;
margin: 0px;
opacity: 1;
}
.dataMiningMarginBase {
margin: 0px 5px;
}
.dataMiningMarginLeft {
margin-left: 5px;
}
.dataMiningMarginRight {
margin-right: 5px;
}
.resultsPresenterTabHeader * {
display: inline-block;
margin: 0px 3px;
vertical-align: bottom;
}
.emphasizedLabel {
font-weight: 600;
}
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="com.github.sdbg.debug.core.chromeLaunchConfig">
<stringAttribute key="applicationArguments" value=""/>
<stringAttribute key="applicationName" value=""/>
<booleanAttribute key="launchFile" value="false"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/com.sap.sailing.gwt.ui"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<stringAttribute key="projectName" value="com.sap.sailing.gwt.ui"/>
<booleanAttribute key="showLaunchOutput" value="false"/>
<stringAttribute key="url" value="http://127.0.0.1:8888/gwt/DataMining.html"/>
<stringAttribute key="urlQueryParams" value=""/>
</launchConfiguration>
@@ -77,6 +77,7 @@ TrackLifecycle: true
Export-Package: com.google.gwt.user.client.rpc.core.com.sap.sailing.domain.common.confidence.impl,
com.google.gwt.user.client.rpc.core.com.sap.sailing.domain.common.impl,
com.google.gwt.user.client.rpc.core.com.sap.sailing.domain.common.tracking.impl,
com.sap.sailing.gwt.common.communication.routing,
com.sap.sailing.gwt.home.communication,
com.sap.sailing.gwt.home.server,
com.sap.sailing.gwt.server,
@@ -70,6 +70,7 @@
<servlet-mapping>
<servlet-name>SailingService</servlet-name>
<url-pattern>/service/sailing</url-pattern>
<url-pattern>/service/sailing/*</url-pattern>
</servlet-mapping>
<servlet>
@@ -90,6 +91,7 @@
<servlet-mapping>
<servlet-name>sailingDispatch</servlet-name>
<url-pattern>/service/dispatch</url-pattern>
<url-pattern>/service/dispatch/*</url-pattern>
</servlet-mapping>
<servlet>
@@ -1,16 +1,20 @@
package com.sap.sailing.gwt.autoplay.client.app;
import java.util.HashMap;
import java.util.Map;
import com.google.gwt.core.client.GWT;
import com.google.gwt.place.shared.Place;
import com.google.gwt.place.shared.PlaceController;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.web.bindery.event.shared.EventBus;
import com.sap.sailing.gwt.autoplay.client.places.autoplaystart.AutoPlayStartPlace;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sailing.gwt.ui.client.MediaService;
import com.sap.sailing.gwt.ui.client.MediaServiceAsync;
import com.sap.sailing.gwt.ui.client.RemoteServiceMappingConstants;
import com.sap.sailing.gwt.ui.client.SailingService;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.SailingServiceHelper;
import com.sap.sse.gwt.client.EntryPointHelper;
import com.sap.sse.security.ui.client.SecureClientFactoryImpl;
@@ -20,11 +24,13 @@ public abstract class AutoPlayClientFactoryBase
private final MediaServiceAsync mediaService;
private final AutoPlayPlaceNavigator navigator;
private final Map<String, SailingServiceAsync> services = new HashMap<>();
public AutoPlayClientFactoryBase(ApplicationTopLevelView root, EventBus eventBus, PlaceController placeController,
AutoPlayPlaceNavigator navigator) {
super(root, eventBus, placeController);
this.navigator = navigator;
sailingService = GWT.create(SailingService.class);
sailingService = SailingServiceHelper.createSailingServiceInstance();
mediaService = GWT.create(MediaService.class);
EntryPointHelper.registerASyncService((ServiceDefTarget) sailingService,
RemoteServiceMappingConstants.sailingServiceRemotePath);
@@ -39,8 +45,25 @@ public abstract class AutoPlayClientFactoryBase
@Override
public SailingServiceAsync getSailingService() {
if (isConfigured()) {
return getSailingService(() -> getAutoPlayCtxSignalError().getContextDefinition().getLeaderboardName());
}
return sailingService;
}
@Override
public SailingServiceAsync getSailingService(ProvidesLeaderboardRouting routingProvider) {
if (routingProvider == null) {
return sailingService;
} else {
SailingServiceAsync sailingServiceAsync = services.get(routingProvider.routingSuffixPath());
if (sailingServiceAsync == null) {
sailingServiceAsync = SailingServiceHelper.createSailingServiceInstance(routingProvider);
services.put(routingProvider.routingSuffixPath(), sailingServiceAsync);
}
return sailingServiceAsync;
}
}
@Override
public MediaServiceAsync getMediaService() {
@@ -1,10 +1,13 @@
package com.sap.sailing.gwt.autoplay.client.configs;
import com.google.gwt.http.client.UrlBuilder;
import com.google.gwt.user.client.Window;
import com.sap.sailing.gwt.autoplay.client.app.AutoPlayClientFactory;
import com.sap.sailing.gwt.ui.shared.EventDTO;
import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
import com.sap.sse.gwt.client.shared.perspective.PerspectiveCompositeSettings;
import com.sap.sse.gwt.settings.SettingsToUrlSerializer;
import com.sap.sse.gwt.settings.UrlBuilderUtil;
import com.sap.sse.security.ui.client.UserService;
public abstract class AutoPlayConfiguration {
@@ -19,20 +22,28 @@ public abstract class AutoPlayConfiguration {
OnSettingsCallback holder, PerspectiveCompositeSettings<?> settings, AutoPlayContextDefinition apcd,
UserService userService) {
Window.alert("This configuration does not have settings");
}
/**
* This method should be pure/standalone, it is not allowed to make any guesses on fields written by startRootNode,
* as it can be called before that
*/
public void loadSettingsDefault(EventDTO selectedEvent, StrippedLeaderboardDTO leaderboard, UserService userService,
OnSettingsCallback holder) {
holder.newSettings(null);
public void loadSettingsDefault(EventDTO selectedEvent, AutoPlayContextDefinition apcd,
StrippedLeaderboardDTO leaderboard, UserService userService, OnSettingsCallback holder) {
holder.newSettings(null, getUrlWithSettings(apcd, null));
}
private String getUrlWithSettings(AutoPlayContextDefinition apcd, PerspectiveCompositeSettings<?> settings) {
UrlBuilder urlBuilder = UrlBuilderUtil.createUrlBuilderFromCurrentLocationWithCleanParameters();
SettingsToUrlSerializer urlSerializer = new SettingsToUrlSerializer();
if (settings != null) {
urlSerializer.serializeSettingsMapToUrlBuilder(settings, urlBuilder);
}
urlSerializer.serializeToUrlBuilder(apcd, urlBuilder);
return urlBuilder.buildString();
}
public interface OnSettingsCallback {
void newSettings(PerspectiveCompositeSettings<?> newSettings);
void newSettings(PerspectiveCompositeSettings<?> newSettings, String urlWithSettings);
}
}
@@ -26,58 +26,81 @@ import com.sap.sse.security.ui.client.UserService;
public class AutoPlayClassicConfiguration extends AutoPlayConfiguration {
private static final Logger logger = Logger.getLogger(AutoPlayClassicConfiguration.class.getName());
@Override
public void startRootNode(AutoPlayClientFactory cf, AutoPlayContextDefinition context,
PerspectiveCompositeSettings<?> settings, EventDTO initialEventData) {
cf.getSailingService().getAvailableDetailTypesForLeaderboard(context.getLeaderboardName(), new AsyncCallback<Iterable<DetailType>>() {
@Override
public void onFailure(Throwable caught) {
logger.log(Level.WARNING, "Could not load detailtypes for leaderboard", caught);
}
cf.getSailingService().getAvailableDetailTypesForLeaderboard(context.getLeaderboardName(),
null, new AsyncCallback<Iterable<DetailType>>() {
@Override
public void onFailure(Throwable caught) {
logger.log(Level.WARNING, "Could not load detailtypes for leaderboard", caught);
}
@SuppressWarnings("unchecked")
@Override
public void onSuccess(Iterable<DetailType> result) {
StrippedLeaderboardDTO leaderBoardDTO = AutoplayHelper.getSelectedLeaderboard(initialEventData,
context.getLeaderboardName());
AutoplayPerspectiveLifecycle autoplayLifecycle = new AutoplayPerspectiveLifecycle(leaderBoardDTO, cf.getUserService(), result);
cf.setAutoPlayContext(new AutoPlayContextImpl(autoplayLifecycle,
(PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings>) settings,
AutoPlayClassicConfiguration.this, context, initialEventData));
// start sixty inch slide loop nodes...
RootNodeClassic root = new RootNodeClassic(cf);
root.start(cf.getEventBus());
}
});
@SuppressWarnings("unchecked")
@Override
public void onSuccess(Iterable<DetailType> result) {
StrippedLeaderboardDTO leaderBoardDTO = AutoplayHelper.getSelectedLeaderboard(initialEventData,
context.getLeaderboardName());
AutoplayPerspectiveLifecycle autoplayLifecycle = new AutoplayPerspectiveLifecycle(
leaderBoardDTO, cf.getUserService(), result);
cf.setAutoPlayContext(new AutoPlayContextImpl(autoplayLifecycle,
(PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings>) settings,
AutoPlayClassicConfiguration.this, context, initialEventData));
// start sixty inch slide loop nodes...
RootNodeClassic root = new RootNodeClassic(cf);
root.start(cf.getEventBus());
}
});
}
@Override
public void openSettingsDialog(EventDTO selectedEvent, StrippedLeaderboardDTO leaderboard,
OnSettingsCallback settingsCallback, PerspectiveCompositeSettings<?> settings, AutoPlayContextDefinition apcd, UserService userService) {
OnSettingsCallback settingsCallback, PerspectiveCompositeSettings<?> settings,
AutoPlayContextDefinition apcd, UserService userService) {
DialogCallback<PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings>> callback = new DialogCallback<PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings>>() {
@Override
public void ok(PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings> editedObject) {
settingsCallback.newSettings(editedObject);
settingsCallback.newSettings(editedObject,
getUrlWithSettings(apcd, editedObject, leaderboard, userService));
}
@Override
public void cancel() {
}
};
AutoplayPerspectiveLifecycle autoplayLifecycle = new AutoplayPerspectiveLifecycle(leaderboard, userService, Arrays.asList(DetailType.values()));
PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings> autoplayPerspectiveSettings = autoplayLifecycle
.createDefaultSettings();
LinkWithSettingsGenerator<PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings>> settingsGenerator = new LinkWithSettingsGenerator<>(Window.Location.getPath(), autoplayLifecycle::createDefaultSettings, apcd);
new SettingsDialogForLinkSharing<PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings>>(settingsGenerator,
autoplayLifecycle, autoplayPerspectiveSettings, StringMessages.INSTANCE, true, callback).show();
AutoplayPerspectiveLifecycle autoplayLifecycle = new AutoplayPerspectiveLifecycle(leaderboard, userService,
Arrays.asList(DetailType.values()));
@SuppressWarnings("unchecked")
PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings> autoplayPerspectiveSettings = settings != null
? (PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings>) settings
: autoplayLifecycle.createDefaultSettings();
LinkWithSettingsGenerator<PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings>> settingsGenerator = new LinkWithSettingsGenerator<>(
Window.Location.getPath(), autoplayLifecycle::createDefaultSettings, apcd);
new SettingsDialogForLinkSharing<PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings>>(
settingsGenerator, autoplayLifecycle, autoplayPerspectiveSettings, StringMessages.INSTANCE, true,
callback).show();
}
@Override
public void loadSettingsDefault(EventDTO selectedEvent, StrippedLeaderboardDTO leaderboard,
UserService userService, OnSettingsCallback settingsCallback) {
AutoplayPerspectiveLifecycle autoplayLifecycle = new AutoplayPerspectiveLifecycle(leaderboard, userService, Arrays.asList(DetailType.values()));
settingsCallback.newSettings(autoplayLifecycle.createDefaultSettings());
public void loadSettingsDefault(EventDTO selectedEvent, AutoPlayContextDefinition apcd,
StrippedLeaderboardDTO leaderboard, UserService userService, OnSettingsCallback settingsCallback) {
AutoplayPerspectiveLifecycle autoplayLifecycle = new AutoplayPerspectiveLifecycle(leaderboard, userService,
Arrays.asList(DetailType.values()));
PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings> defaultSettings = autoplayLifecycle
.createDefaultSettings();
settingsCallback.newSettings(defaultSettings,
getUrlWithSettings(apcd, defaultSettings, leaderboard, userService));
}
private String getUrlWithSettings(AutoPlayContextDefinition apcd,
PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings> settings, StrippedLeaderboardDTO leaderboard,
UserService userService) {
AutoplayPerspectiveLifecycle autoplayLifecycle = new AutoplayPerspectiveLifecycle(leaderboard, userService,
Arrays.asList(DetailType.values()));
LinkWithSettingsGenerator<PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings>> settingsGenerator = new LinkWithSettingsGenerator<>(
Window.Location.getPath(), autoplayLifecycle::createDefaultSettings, apcd);
return settingsGenerator.createUrl(settings);
}
}
@@ -17,6 +17,7 @@ import com.sap.sailing.gwt.autoplay.client.utils.AutoplayHelper;
import com.sap.sailing.gwt.ui.client.CompetitorSelectionModel;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardEntryPoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.gwt.client.player.Timer;
import com.sap.sse.gwt.client.player.Timer.PlayModes;
import com.sap.sse.gwt.client.shared.perspective.PerspectiveCompositeSettings;
@@ -35,6 +36,7 @@ public class IdleRaceLeaderboard extends FiresPlaceNode {
}
public void onStart() {
leaderboardTimer.setTime(MillisecondsTimePoint.now().asMillis());
leaderboardTimer.play();
PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings> settings = cf.getAutoPlayCtxSignalError()
.getAutoplaySettings();
@@ -93,11 +93,11 @@ public class IdleSixtyInchLeaderboardNode extends FiresPlaceNode {
private void startWithLeaderbaord(final MultiRaceLeaderboardSettings leaderboardSettings,
CompetitorSelectionProvider provider, String leaderboardName) {
MultiRaceLeaderboardPanel leaderboardPanel = new MultiRaceLeaderboardPanel(null, null, cf.getSailingService(),
new AsyncActionsExecutor(), leaderboardSettings, false, provider, timer, null, leaderboardName,
cf.getErrorReporter(), StringMessages.INSTANCE, false, null, false, null, false, true, false, false,
false, new SixtyInchLeaderboardStyle(true), FlagImageResolverImpl.get(),
Arrays.asList(DetailType.values()));
MultiRaceLeaderboardPanel leaderboardPanel = new MultiRaceLeaderboardPanel(null, null,
cf.getSailingService(() -> leaderboardName), new AsyncActionsExecutor(), leaderboardSettings, false,
provider, timer, null, leaderboardName, cf.getErrorReporter(), StringMessages.INSTANCE, false, null,
false, null, false, true, false, false, false, new SixtyInchLeaderboardStyle(true),
FlagImageResolverImpl.get(), Arrays.asList(DetailType.values()));
IdleSixtyInchLeaderboardPlace place = new IdleSixtyInchLeaderboardPlace(leaderboardPanel, provider,
durationConsumer);
@@ -24,6 +24,7 @@ import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.raceboard.RaceBoardPanel;
import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO;
import com.sap.sailing.gwt.ui.shared.RaceboardDataDTO;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.gwt.client.player.Timer;
import com.sap.sse.gwt.client.player.Timer.PlayModes;
import com.sap.sse.gwt.client.shared.perspective.PerspectiveCompositeSettings;
@@ -54,6 +55,8 @@ public class LiveRaceBoardNode extends FiresPlaceNode implements RaceTimesInfoPr
}
public void onStart() {
raceboardTimer.setTime(MillisecondsTimePoint.now().asMillis());
raceboardTimer.play();
raceTimesInfoProvider.addRaceIdentifier(cf.getAutoPlayCtxSignalError().getLifeOrPreLiveRace(), true);
PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings> settings = cf.getAutoPlayCtxSignalError().getAutoplaySettings();
@@ -55,10 +55,10 @@ public class AutoPlayStartPresenterImpl extends AbstractActivity implements Auto
StrippedLeaderboardDTO leaderBoard = AutoplayHelper.getSelectedLeaderboard(event,
apcd.getLeaderboardName());
apcd.getType().getConfig().loadSettingsDefault(event, leaderBoard, clientFactory.getUserService(), new OnSettingsCallback() {
apcd.getType().getConfig().loadSettingsDefault(event, apcd, leaderBoard, clientFactory.getUserService(), new OnSettingsCallback() {
@Override
public void newSettings(PerspectiveCompositeSettings<?> newSettings) {
public void newSettings(PerspectiveCompositeSettings<?> newSettings, String urlWithSettings) {
if (newSettings != null) {
serializer.deserializeSettingsMapFromCurrentLocation(newSettings);
}
@@ -8,7 +8,6 @@ import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.http.client.UrlBuilder;
import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
@@ -30,8 +29,6 @@ import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
import com.sap.sse.common.Util;
import com.sap.sse.gwt.client.GWTLocaleUtil;
import com.sap.sse.gwt.client.shared.perspective.PerspectiveCompositeSettings;
import com.sap.sse.gwt.settings.SettingsToUrlSerializer;
import com.sap.sse.gwt.settings.UrlBuilderUtil;
public class AutoPlayStartViewImpl extends Composite implements AutoPlayStartView {
private static StartPageViewUiBinder uiBinder = GWT.create(StartPageViewUiBinder.class);
@@ -151,9 +148,9 @@ public class AutoPlayStartViewImpl extends Composite implements AutoPlayStartVie
selectedAutoPlayType.getConfig().openSettingsDialog(selectedEvent, selectedLeaderboard,
new OnSettingsCallback() {
@Override
public void newSettings(PerspectiveCompositeSettings<?> newSettings) {
public void newSettings(PerspectiveCompositeSettings<?> newSettings, String urlWithSettings) {
settings = newSettings;
updateURL();
updateURL(urlWithSettings);
}
}, settings, apcd, currentPresenter.getUserService());
}
@@ -197,12 +194,12 @@ public class AutoPlayStartViewImpl extends Composite implements AutoPlayStartVie
settingsButton.removeStyleName(SharedResources.INSTANCE.mainCss().buttoninactive());
startAutoPlayButton.removeStyleName(SharedResources.INSTANCE.mainCss().buttoninactive());
apcd = new AutoPlayContextDefinitionImpl(selectedAutoPlayType, selectedEvent.id, selectedLeaderboardName);
apcd.getType().getConfig().loadSettingsDefault(selectedEvent, selectedLeaderboard, currentPresenter.getUserService(),
apcd.getType().getConfig().loadSettingsDefault(selectedEvent, apcd, selectedLeaderboard, currentPresenter.getUserService(),
new OnSettingsCallback() {
@Override
public void newSettings(PerspectiveCompositeSettings<?> newSettings) {
public void newSettings(PerspectiveCompositeSettings<?> newSettings, String urlWithSettings) {
settings = newSettings;
updateURL();
updateURL(urlWithSettings);
}
});
}
@@ -210,16 +207,10 @@ public class AutoPlayStartViewImpl extends Composite implements AutoPlayStartVie
return readyToGo;
}
private void updateURL() {
UrlBuilder urlBuilder = UrlBuilderUtil.createUrlBuilderFromCurrentLocationWithCleanParameters();
SettingsToUrlSerializer urlSerializer = new SettingsToUrlSerializer();
if (settings != null) {
urlSerializer.serializeSettingsMapToUrlBuilder(settings, urlBuilder);
}
urlSerializer.serializeToUrlBuilder(apcd, urlBuilder);
configuratedUrl = urlBuilder.buildString();
configStarter.setText(configuratedUrl);
configStarter.setHref(configuratedUrl);
private void updateURL(String urlWithSettings) {
configuratedUrl = urlWithSettings;
configStarter.setText(urlWithSettings);
configStarter.setHref(urlWithSettings);
}
@UiHandler("localeSelectionBox")
@@ -6,6 +6,8 @@
<inherits name="com.sap.sse.gwt.CommonSharedResources" />
<source path='client'/>
<source path='communication'/>
<source path='theme'/>
</module>
@@ -45,6 +45,7 @@ public class BoatClassImageResolver {
boatClassIconsMap.put(BoatClassMasterdata.CANOE_TAIFUN.getDisplayName(), imageResources.CanoeTaifunIcon());
boatClassIconsMap.put(BoatClassMasterdata.CONTENDER.getDisplayName(), imageResources.ContenderIcon());
boatClassIconsMap.put(BoatClassMasterdata.CC_30.getDisplayName(), imageResources.CC30Icon());
boatClassIconsMap.put(BoatClassMasterdata.CLUB_SWAN_50.getDisplayName(), imageResources.CLUBSWAN50Icon());
boatClassIconsMap.put(BoatClassMasterdata.DELPHIA_24.getDisplayName(), imageResources.Delphia24Icon());
boatClassIconsMap.put(BoatClassMasterdata.DRAGON_INT.getDisplayName(), imageResources.DragonIcon());
boatClassIconsMap.put(BoatClassMasterdata.DYAS.getDisplayName(), imageResources.DyasIcon());
@@ -58,6 +59,7 @@ public class BoatClassImageResolver {
boatClassIconsMap.put(BoatClassMasterdata.FARR_280.getDisplayName(), imageResources.Farr280Icon());
boatClassIconsMap.put(BoatClassMasterdata.FINN.getDisplayName(), imageResources.FinnIcon());
boatClassIconsMap.put(BoatClassMasterdata.FLYING_DUTCHMAN.getDisplayName(), imageResources.FlyingDutchmanIcon());
boatClassIconsMap.put(BoatClassMasterdata.FLYING_JUNIOR.getDisplayName(), imageResources.FlyingJuniorIcon());
boatClassIconsMap.put(BoatClassMasterdata.FOLKBOAT.getDisplayName(), imageResources.FolkBoatIcon());
boatClassIconsMap.put(BoatClassMasterdata.FUN.getDisplayName(), imageResources.FUNIcon());
boatClassIconsMap.put(BoatClassMasterdata.GC_32.getDisplayName(), imageResources.GC32Icon());
@@ -126,6 +128,7 @@ public class BoatClassImageResolver {
boatClassIconsMap.put(BoatClassMasterdata.TOM_28_MAX.getDisplayName(), imageResources.Tom28MaxIcon());
boatClassIconsMap.put(BoatClassMasterdata.TP52.getDisplayName(), imageResources.TP52Icon());
boatClassIconsMap.put(BoatClassMasterdata.TRIAS.getDisplayName(), imageResources.TriasIcon());
boatClassIconsMap.put(BoatClassMasterdata.VAURIEN.getDisplayName(), imageResources.VaurienIcon());
boatClassIconsMap.put(BoatClassMasterdata.VENT_D_OUEST.getDisplayName(), imageResources.VentdOuestIcon());
boatClassIconsMap.put(BoatClassMasterdata.VIPER_640.getDisplayName(), imageResources.Viper640Icon());
boatClassIconsMap.put(BoatClassMasterdata.VX_ONE.getDisplayName(), imageResources.VXOneIcon());
@@ -132,6 +132,10 @@ public interface BoatClassImageResources extends ClientBundle {
@ImageOptions(preventInlining = true)
ImageResource FinnIcon();
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/FLYING_JUNIOR.png")
@ImageOptions(preventInlining = true)
ImageResource FlyingJuniorIcon();
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/FLYING_DUTCHMAN.png")
@ImageOptions(preventInlining = true)
ImageResource FlyingDutchmanIcon();
@@ -396,6 +400,10 @@ public interface BoatClassImageResources extends ClientBundle {
@ImageOptions(preventInlining = true)
ImageResource CC30Icon();
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/CLUBSWAN50.png")
@ImageOptions(preventInlining = true)
ImageResource CLUBSWAN50Icon();
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/GP_26.png")
@ImageOptions(preventInlining = true)
ImageResource GP26Icon();
@@ -431,4 +439,8 @@ public interface BoatClassImageResources extends ClientBundle {
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/RUNNING.png")
@ImageOptions(preventInlining = true)
ImageResource RunningIcon();
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/VAURIEN.png")
@ImageOptions(preventInlining = true)
ImageResource VaurienIcon();
}
@@ -25,6 +25,7 @@
.tabExtension {
float: right;
margin-top: .5em;
}
.tabExtension > * {
@@ -0,0 +1,16 @@
package com.sap.sailing.gwt.common.communication.routing;
import com.sap.sailing.domain.common.sharding.ShardingType;
import com.sap.sse.gwt.client.ServiceRoutingProvider;
/**
* Interface used to provide leaderboard specific routing, see {@link ServiceRoutingProvider}
*/
public interface ProvidesLeaderboardRouting extends ServiceRoutingProvider {
String getLeaderboardName();
default String routingSuffixPath() {
return ShardingType.LEADERBOARDNAME.encodeIfNeeded(getLeaderboardName());
}
}
@@ -3,6 +3,7 @@ package com.sap.sailing.gwt.home.communication.event;
import java.util.UUID;
import com.google.gwt.core.shared.GwtIncompatible;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.server.EventActionUtil;
@@ -26,7 +27,7 @@ import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException;
* </p>
*/
public class GetCompetitionFormatRacesAction implements
SailingAction<ResultWithTTL<ListResult<RaceCompetitionFormatSeriesDTO>>>, IsClientCacheable {
SailingAction<ResultWithTTL<ListResult<RaceCompetitionFormatSeriesDTO>>>, IsClientCacheable, ProvidesLeaderboardRouting {
private UUID eventId;
private String regattaId;
@@ -58,4 +59,9 @@ public class GetCompetitionFormatRacesAction implements
public void cacheInstanceKey(StringBuilder key) {
key.append(eventId).append("_").append(regattaId);
}
@Override
public String getLeaderboardName() {
return regattaId;
}
}
@@ -3,6 +3,7 @@ package com.sap.sailing.gwt.home.communication.event;
import java.util.UUID;
import com.google.gwt.core.shared.GwtIncompatible;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.server.EventActionUtil;
@@ -25,7 +26,7 @@ import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL;
* </p>
*/
public class GetFinishedRacesAction implements SailingAction<ResultWithTTL<ListResult<RaceListRaceDTO>>>,
IsClientCacheable {
IsClientCacheable, ProvidesLeaderboardRouting {
private UUID eventId;
private String regattaId;
@@ -59,4 +60,9 @@ public class GetFinishedRacesAction implements SailingAction<ResultWithTTL<ListR
public void cacheInstanceKey(StringBuilder key) {
key.append(eventId).append("_").append(regattaId);
}
@Override
public String getLeaderboardName() {
return regattaId;
}
}
@@ -4,6 +4,7 @@ import java.util.UUID;
import com.google.gwt.core.shared.GwtIncompatible;
import com.sap.sailing.domain.base.Event;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.server.EventActionUtil;
@@ -30,7 +31,7 @@ import com.sap.sse.gwt.dispatch.shared.commands.SortedSetResult;
* </p>
*/
public class GetLiveRacesForRegattaAction implements SailingAction<ResultWithTTL<SortedSetResult<LiveRaceDTO>>>,
IsClientCacheable {
IsClientCacheable, ProvidesLeaderboardRouting {
private UUID eventId;
private String regattaName;
@@ -66,4 +67,10 @@ public class GetLiveRacesForRegattaAction implements SailingAction<ResultWithTTL
public void cacheInstanceKey(StringBuilder key) {
key.append(eventId).append("_").append(regattaName);
}
@Override
public String getLeaderboardName() {
return regattaName;
}
}
@@ -3,6 +3,7 @@ package com.sap.sailing.gwt.home.communication.event;
import java.util.UUID;
import com.google.gwt.core.shared.GwtIncompatible;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.communication.event.statistics.EventStatisticsDTO;
@@ -22,7 +23,7 @@ import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException;
* The {@link ResultWithTTL result's} time to live is <i>5 minutes</i>.
* </p>
*/
public class GetRegattaStatisticsAction implements SailingAction<ResultWithTTL<EventStatisticsDTO>>, IsClientCacheable {
public class GetRegattaStatisticsAction implements SailingAction<ResultWithTTL<EventStatisticsDTO>>, IsClientCacheable, ProvidesLeaderboardRouting {
private UUID eventId;
private String regattaId;
@@ -53,4 +54,9 @@ public class GetRegattaStatisticsAction implements SailingAction<ResultWithTTL<E
public void cacheInstanceKey(StringBuilder key) {
key.append(eventId).append("_").append(regattaId);
}
@Override
public String getLeaderboardName() {
return regattaId;
}
}
@@ -3,6 +3,7 @@ package com.sap.sailing.gwt.home.communication.event;
import java.util.UUID;
import com.google.gwt.core.shared.GwtIncompatible;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.communication.regatta.RegattaWithProgressDTO;
@@ -24,7 +25,7 @@ import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL;
* state} using a duration of <i>5 minutes</i> for currently running events.
* </p>
*/
public class GetRegattaWithProgressAction implements SailingAction<ResultWithTTL<RegattaWithProgressDTO>>, IsClientCacheable {
public class GetRegattaWithProgressAction implements SailingAction<ResultWithTTL<RegattaWithProgressDTO>>, IsClientCacheable, ProvidesLeaderboardRouting {
private UUID eventId;
private String regattaId;
@@ -55,4 +56,9 @@ public class GetRegattaWithProgressAction implements SailingAction<ResultWithTTL
public void cacheInstanceKey(StringBuilder key) {
key.append(eventId).append("_").append(regattaId);
}
@Override
public String getLeaderboardName() {
return regattaId;
}
}
@@ -4,6 +4,7 @@ import java.util.UUID;
import com.google.gwt.core.shared.GwtIncompatible;
import com.sap.sailing.domain.base.Event;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.server.EventActionUtil;
@@ -21,7 +22,7 @@ import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL;
* otherwise.
* </p>
*/
public class GetMiniLeaderbordAction implements SailingAction<ResultWithTTL<GetMiniLeaderboardDTO>>, IsClientCacheable {
public class GetMiniLeaderbordAction implements SailingAction<ResultWithTTL<GetMiniLeaderboardDTO>>, IsClientCacheable, ProvidesLeaderboardRouting {
private UUID eventId;
private String leaderboardName;
private int limit = 0;
@@ -74,4 +75,9 @@ public class GetMiniLeaderbordAction implements SailingAction<ResultWithTTL<GetM
key.append("_");
key.append(limit);
}
@Override
public String getLeaderboardName() {
return leaderboardName;
}
}
@@ -13,6 +13,7 @@ import com.sap.sailing.domain.common.RegattaNameAndRaceName;
import com.sap.sailing.domain.common.TargetTimeInfo;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sse.common.Distance;
@@ -32,7 +33,7 @@ import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL;
* otherwise.
* </p>
*/
public class GetSixtyInchStatisticAction implements SailingAction<GetSixtyInchStatisticDTO> {
public class GetSixtyInchStatisticAction implements SailingAction<GetSixtyInchStatisticDTO>, ProvidesLeaderboardRouting {
private static final Logger LOGGER = Logger.getLogger(GetSixtyInchStatisticAction.class.getName());
// transfer as string, to avoid transfering incompatible types
private String racename;
@@ -95,4 +96,9 @@ public class GetSixtyInchStatisticAction implements SailingAction<GetSixtyInchSt
}
return duration;
}
@Override
public String getLeaderboardName() {
return regattaname;
}
}
@@ -5,12 +5,13 @@ import com.google.gwt.place.shared.Place;
import com.google.gwt.place.shared.PlaceController;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.web.bindery.event.shared.EventBus;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sailing.gwt.home.shared.places.start.StartPlace;
import com.sap.sailing.gwt.ui.client.MediaService;
import com.sap.sailing.gwt.ui.client.MediaServiceAsync;
import com.sap.sailing.gwt.ui.client.RemoteServiceMappingConstants;
import com.sap.sailing.gwt.ui.client.SailingService;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.SailingServiceHelper;
import com.sap.sse.gwt.client.EntryPointHelper;
import com.sap.sse.security.ui.client.SecureClientFactoryImpl;
@@ -24,9 +25,8 @@ public abstract class AbstractApplicationClientFactory<ATLV extends ApplicationT
PlaceController placeController, final DesktopPlacesNavigator navigator) {
super(root, eventBus, placeController);
this.navigator = navigator;
sailingService = GWT.create(SailingService.class);
sailingService = SailingServiceHelper.createSailingServiceInstance();
mediaService = GWT.create(MediaService.class);
EntryPointHelper.registerASyncService((ServiceDefTarget) sailingService, RemoteServiceMappingConstants.sailingServiceRemotePath);
EntryPointHelper.registerASyncService((ServiceDefTarget) mediaService, RemoteServiceMappingConstants.mediaServiceRemotePath);
}
@@ -40,6 +40,15 @@ public abstract class AbstractApplicationClientFactory<ATLV extends ApplicationT
return sailingService;
}
@Override
public SailingServiceAsync getSailingService(ProvidesLeaderboardRouting routingProvider) {
if (routingProvider == null) {
return sailingService;
} else {
return SailingServiceHelper.createSailingServiceInstance(routingProvider);
}
}
@Override
public MediaServiceAsync getMediaService() {
return mediaService;
@@ -20,6 +20,7 @@ import com.sap.sailing.gwt.home.shared.app.PlaceNavigation;
import com.sap.sailing.gwt.home.shared.resources.SharedHomeResources;
import com.sap.sailing.gwt.home.shared.utils.EventDatesFormatterUtil;
import com.sap.sailing.gwt.home.shared.utils.LabelTypeUtil;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.gwt.client.LinkUtil;
public class EventTeaser extends Composite {
@@ -85,6 +86,9 @@ public class EventTeaser extends Composite {
public void setSeriesInformation(PlaceNavigation<?> seriesNavigation, EventListEventSeriesDTO eventSeries) {
eventImage.appendChild(new EventTeaserSeriesInfoCorner(seriesNavigation, eventSeries).getElement());
eventName.setInnerSafeHtml(LongNamesUtil.breakLongName(eventSeries.getDisplayName()));
venue.setInnerText(StringMessages.INSTANCE.lastEvent(event.getLocationOrVenue()));
eventImage.setTitle(StringMessages.INSTANCE.teaserOverallLinkToolTip());
}
public void hideImage(boolean hide) {
@@ -20,12 +20,12 @@ public class SailorInfo extends Composite {
FlowPanel panel = new FlowPanel();
Style panelStyle = panel.getElement().getStyle();
panelStyle.setDisplay(Display.INLINE_BLOCK);
panelStyle.setVerticalAlign(VerticalAlign.BOTTOM);
Label sailorInfoLabel = new Label();
sailorInfoLabel.getElement().setInnerHTML(i18n.sailorInfoLongText().replace("\n", "<br />"));
Style labelStyle = sailorInfoLabel.getElement().getStyle();
labelStyle.setDisplay(Display.INLINE_BLOCK);
sailorInfoLabel.getElement().getStyle().setMarginTop(0.5, Unit.EM);
sailorInfoLabel.getElement().getStyle().setMarginRight(0.5, Unit.EM);
panel.add(sailorInfoLabel);
@@ -37,7 +37,6 @@ import com.sap.sailing.gwt.settings.client.raceboard.RaceBoardPerspectiveOwnSett
import com.sap.sailing.gwt.settings.client.raceboard.RaceboardContextDefinition;
import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaOverviewContextDefinition;
import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaRaceStatesSettings;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.refresh.ErrorAndBusyClientFactory;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapLifecycle;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapSettings;
@@ -83,10 +82,6 @@ public abstract class AbstractEventActivity<PLACE extends AbstractEventPlace> ex
this.timerForClientServerOffset = new Timer(PlayModes.Replay);
this.clientFactory = clientFactory;
}
public SailingServiceAsync getSailingService() {
return clientFactory.getSailingService();
}
public SailingDispatchSystem getDispatch() {
return clientFactory.getDispatch();
@@ -21,7 +21,6 @@ import com.sap.sailing.gwt.home.shared.places.event.EventDefaultPlace;
import com.sap.sailing.gwt.home.shared.places.events.EventsPlace;
import com.sap.sailing.gwt.home.shared.places.fakeseries.SeriesDefaultPlace;
import com.sap.sailing.gwt.home.shared.places.start.StartPlace;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.refresh.ErrorAndBusyClientFactory;
import com.sap.sse.gwt.client.player.Timer;
@@ -37,7 +36,6 @@ public interface EventView<PLACE extends AbstractEventPlace, PRES extends EventV
boolean needsSelectionInHeader();
void forPlaceSelection(PlaceCallback callback);
Timer getTimerForClientServerOffset();
SailingServiceAsync getSailingService();
AbstractEventRegattaPlace getPlaceForRegatta(String regattaId);
AbstractEventRegattaPlace getPlaceForRegattaRaces(String regattaId);
@@ -4,7 +4,10 @@ import java.util.ArrayList;
import java.util.List;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.sap.sailing.domain.common.DetailType;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.dto.EventType;
import com.sap.sailing.gwt.home.communication.event.EventReferenceWithStateDTO;
import com.sap.sailing.gwt.home.communication.event.EventState;
@@ -50,7 +53,7 @@ public class EventRegattaActivity extends AbstractEventActivity<AbstractEventReg
currentView = new TabletAndDesktopRegattaEventView(flagImageResolver);
if (this.ctx.getRegattaAnalyticsManager() == null) {
ctx.withRegattaAnalyticsManager(new RegattaAnalyticsDataManager(
clientFactory.getSailingService(),
clientFactory,
asyncActionsExecutor,
new Timer(PlayModes.Live, PlayStates.Paused, delayBetweenAutoAdvancesInMilliseconds),
clientFactory.getErrorReporter(), flagImageResolver));
@@ -158,4 +161,10 @@ public class EventRegattaActivity extends AbstractEventActivity<AbstractEventReg
public UserService getUserService() {
return clientFactory.getUserService();
}
@Override
public void getAvailableDetailTypesForLeaderboard(String leaderboardName, RegattaAndRaceIdentifier raceOrNull,
AsyncCallback<Iterable<DetailType>> asyncCallback) {
clientFactory.getSailingService(()-> leaderboardName).getAvailableDetailTypesForLeaderboard(leaderboardName, raceOrNull, asyncCallback);
}
}
@@ -1,5 +1,8 @@
package com.sap.sailing.gwt.home.desktop.places.event.regatta;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.domain.common.DetailType;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.gwt.home.desktop.places.event.EventView;
import com.sap.sailing.gwt.home.desktop.places.event.regatta.overviewtab.RegattaOverviewPlace;
import com.sap.sailing.gwt.home.shared.app.PlaceNavigation;
@@ -15,5 +18,8 @@ public interface EventRegattaView extends EventView<AbstractEventRegattaPlace, E
Timer getAutoRefreshTimer();
UserService getUserService();
void getAvailableDetailTypesForLeaderboard(String leaderboardName, RegattaAndRaceIdentifier raceOrNull,
AsyncCallback<Iterable<DetailType>> asyncCallback);
}
}
@@ -6,6 +6,7 @@ import com.sap.sailing.gwt.settings.client.leaderboard.MultiRaceLeaderboardSetti
import com.sap.sailing.gwt.ui.client.CompetitorSelectionModel;
import com.sap.sailing.gwt.ui.client.DebugIdHelper;
import com.sap.sailing.gwt.ui.client.FlagImageResolver;
import com.sap.sailing.gwt.ui.client.SailingClientFactory;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.shared.charts.MultiCompetitorLeaderboardChart;
@@ -31,16 +32,16 @@ public class RegattaAnalyticsDataManager {
private final CompetitorSelectionModel competitorSelectionProvider;
private final AsyncActionsExecutor asyncActionsExecutor;
private final ErrorReporter errorReporter;
private final SailingServiceAsync sailingService;
private final SailingClientFactory sailingCF;
private final Timer timer;
private final FlagImageResolver flagImageResolver;
public RegattaAnalyticsDataManager(final SailingServiceAsync sailingService,
public RegattaAnalyticsDataManager(final SailingClientFactory sailingCF,
AsyncActionsExecutor asyncActionsExecutor, Timer timer, ErrorReporter errorReporter,
FlagImageResolver flagImageResolver) {
this.flagImageResolver = flagImageResolver;
this.competitorSelectionProvider = new CompetitorSelectionModel(/* hasMultiSelection */true);
this.sailingService = sailingService;
this.sailingCF = sailingCF;
this.asyncActionsExecutor = asyncActionsExecutor;
this.timer = timer;
this.errorReporter = errorReporter;
@@ -53,6 +54,7 @@ public class RegattaAnalyticsDataManager {
final String leaderboardGroupName, String leaderboardName, boolean showRaceDetails,
boolean autoExpandLastRaceColumn, Iterable<DetailType> availableDetailTypes) {
if (leaderboardPanel == null) {
SailingServiceAsync sailingService = sailingCF.getSailingService(()-> leaderboardName);
leaderboardPanel = new MultiRaceLeaderboardPanel(parent, context, sailingService,
asyncActionsExecutor,
leaderboardSettings,
@@ -68,6 +70,7 @@ public class RegattaAnalyticsDataManager {
public MultiCompetitorLeaderboardChart createMultiCompetitorChart(String leaderboardName, DetailType chartDetailType) {
if(multiCompetitorChart == null) {
SailingServiceAsync sailingService = sailingCF.getSailingService(()-> leaderboardName);
multiCompetitorChart = new MultiCompetitorLeaderboardChart(null, null, sailingService, asyncActionsExecutor,
leaderboardName, chartDetailType,
competitorSelectionProvider, timer, StringMessages.INSTANCE, false, errorReporter);
@@ -2,6 +2,7 @@ package com.sap.sailing.gwt.home.desktop.places.event.regatta;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.TextTransform;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
@@ -65,7 +66,12 @@ public class TabletAndDesktopRegattaEventView extends Composite implements Event
racesTabUi = new RegattaRacesTabView(flagImageResolver);
regattaOverviewTabUi = new RegattaOverviewTabView(flagImageResolver);
initWidget(uiBinder.createAndBindUi(this));
String sailorsInfoURL = currentPresenter.getEventDTO().getSailorsInfoWebsiteURL();
if (sailorsInfoURL != null && !sailorsInfoURL.isEmpty()) {
tabPanelUi.addTabExtension(new SailorInfo(sailorsInfoURL));
}
if(currentPresenter.getEventDTO().getType() == EventType.SERIES) {
final PlaceNavigation<SeriesDefaultPlace> currentEventSeriesNavigation = currentPresenter.getCurrentEventSeriesNavigation();
Anchor seriesAnchor = new Anchor(i18n.overallLeaderboardSelection());
@@ -82,14 +88,10 @@ public class TabletAndDesktopRegattaEventView extends Composite implements Event
seriesAnchor.setStyleName(SharedResources.INSTANCE.mainCss().button());
seriesAnchor.addStyleName(SharedResources.INSTANCE.mainCss().buttonprimary());
Style style = seriesAnchor.getElement().getStyle();
style.setFontSize(16, Unit.PX);
style.setPadding(0.75, Unit.EM);
style.setPaddingLeft(0.75, Unit.EM);
style.setPaddingRight(0.75, Unit.EM);
style.setTextTransform(TextTransform.UPPERCASE);
tabPanelUi.addTabExtension(seriesAnchor);
} else {
String sailorsInfoURL = currentPresenter.getEventDTO().getSailorsInfoWebsiteURL();
if(sailorsInfoURL != null && ! sailorsInfoURL.isEmpty()) {
tabPanelUi.addTabExtension(new SailorInfo(sailorsInfoURL));
}
}
final Iterable<SpotDTO> spots = currentPresenter.getEventDTO().getAllWindFinderSpotIdsUsedByEvent();
@@ -99,8 +99,8 @@ public class RegattaCompetitorAnalyticsTabView extends SharedLeaderboardRegattaT
}
};
if (regattaAnalyticsManager.getLeaderboardPanel() == null) {
currentPresenter.getSailingService().getAvailableDetailTypesForLeaderboard(leaderboardName,
new AsyncCallback<Iterable<DetailType>>() {
currentPresenter.getAvailableDetailTypesForLeaderboard(leaderboardName,
null, new AsyncCallback<Iterable<DetailType>>() {
@Override
public void onSuccess(Iterable<DetailType> result) {
@@ -147,8 +147,8 @@ public class RegattaLeaderboardTabView extends SharedLeaderboardRegattaTabView<R
private void loadAvailableDetailTypes(final String leaderboardName, final AcceptsOneWidget contentArea,
final Consumer<Iterable<DetailType>> callback) {
currentPresenter.getSailingService().getAvailableDetailTypesForLeaderboard(leaderboardName,
new AsyncCallback<Iterable<DetailType>>() {
currentPresenter.getAvailableDetailTypesForLeaderboard(leaderboardName,
null, new AsyncCallback<Iterable<DetailType>>() {
@Override
public void onSuccess(Iterable<DetailType> result) {
@@ -3,8 +3,11 @@ package com.sap.sailing.gwt.home.desktop.places.fakeseries;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.function.Function;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.domain.common.DetailType;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.gwt.settings.client.leaderboard.MultiCompetitorLeaderboardChartSettings;
import com.sap.sailing.gwt.settings.client.leaderboard.MultiRaceLeaderboardSettings;
@@ -12,6 +15,7 @@ import com.sap.sailing.gwt.ui.client.CompetitorSelectionChangeListener;
import com.sap.sailing.gwt.ui.client.CompetitorSelectionModel;
import com.sap.sailing.gwt.ui.client.DebugIdHelper;
import com.sap.sailing.gwt.ui.client.FlagImageResolver;
import com.sap.sailing.gwt.ui.client.SailingClientFactory;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.shared.charts.MultiCompetitorLeaderboardChart;
@@ -42,33 +46,32 @@ public class EventSeriesAnalyticsDataManager {
private final CompetitorSelectionModel competitorSelectionProvider;
private final AsyncActionsExecutor asyncActionsExecutor;
private final ErrorReporter errorReporter;
private final SailingServiceAsync sailingService;
private final SailingClientFactory sailingCF;
private final Timer timer;
private final int MAX_COMPETITORS_IN_CHART = 30;
private final FlagImageResolver flagImageResolver;
public EventSeriesAnalyticsDataManager(final SailingServiceAsync sailingService,
public EventSeriesAnalyticsDataManager(final SailingClientFactory sailingCF,
AsyncActionsExecutor asyncActionsExecutor, Timer timer, ErrorReporter errorReporter,
FlagImageResolver flagImageResolver) {
this.flagImageResolver = flagImageResolver;
this.competitorSelectionProvider = new CompetitorSelectionModel(/* hasMultiSelection */true);
this.sailingService = sailingService;
this.sailingCF = sailingCF;
this.asyncActionsExecutor = asyncActionsExecutor;
this.timer = timer;
this.errorReporter = errorReporter;
this.overallLeaderboardPanel = null;
this.multiCompetitorChart = null;
}
public SailingServiceAsync getSailingService() {
return sailingService;
}
public MultiRaceLeaderboardPanel createMultiRaceOverallLeaderboardPanel(Component<?> parent, ComponentContext<?> context,
final MultiRaceLeaderboardSettings leaderboardSettings,
final String leaderboardGroupName, String leaderboardName, boolean showRaceDetails,
boolean autoExpandLastRaceColumn, Iterable<DetailType> availableDetailTypes) {
if(overallLeaderboardPanel == null) {
SailingServiceAsync sailingService = sailingCF.getSailingService(()-> leaderboardName);
overallLeaderboardPanel = new MultiRaceLeaderboardPanel(parent, context, sailingService, asyncActionsExecutor,
leaderboardSettings, true,
competitorSelectionProvider, timer, leaderboardGroupName, leaderboardName, errorReporter,
@@ -84,7 +87,10 @@ public class EventSeriesAnalyticsDataManager {
public MultiCompetitorLeaderboardChart createMultiCompetitorChart(Component<?> parent,
ComponentContext<?> context, String leaderboardName,
DetailType chartDetailType) {
if(multiCompetitorChart == null) {
SailingServiceAsync sailingService = sailingCF.getSailingService(()-> leaderboardName);
multiCompetitorChart = new MultiCompetitorLeaderboardChart(parent, context, sailingService,
asyncActionsExecutor,
leaderboardName, chartDetailType,
@@ -98,8 +104,10 @@ public class EventSeriesAnalyticsDataManager {
MultiRaceLeaderboardSettings leaderboardSettings,
String preselectedLeaderboardName, String leaderboardGroupName,
String metaLeaderboardName, boolean showRaceDetails, boolean autoExpandLastRaceColumn, Iterable<DetailType> availableDetailTypes) {
if(multiLeaderboardPanel == null) {
multiLeaderboardPanel = new MultiLeaderboardProxyPanel(parent, context, sailingService, metaLeaderboardName,
if (multiLeaderboardPanel == null) {
final Function<String, SailingServiceAsync> sailingServiceFactory = leaderBoardName -> sailingCF
.getSailingService(() -> leaderBoardName);
multiLeaderboardPanel = new MultiLeaderboardProxyPanel(parent, context, sailingServiceFactory, metaLeaderboardName,
asyncActionsExecutor, timer, true /* isEmbedded */,
preselectedLeaderboardName, errorReporter, StringMessages.INSTANCE,
showRaceDetails, autoExpandLastRaceColumn, leaderboardSettings, flagImageResolver, availableDetailTypes);
@@ -179,4 +187,10 @@ public class EventSeriesAnalyticsDataManager {
public Timer getTimer() {
return timer;
}
public void getAvailableDetailTypesForLeaderboard(String leaderboardName, RegattaAndRaceIdentifier raceOrNull,
AsyncCallback<Iterable<DetailType>> asyncCallback) {
SailingServiceAsync sailingService = sailingCF.getSailingService(()-> leaderboardName);
sailingService.getAvailableDetailTypesForLeaderboard(leaderboardName, raceOrNull, asyncCallback);
}
}
@@ -59,7 +59,7 @@ public class SeriesActivity extends AbstractActivity implements SeriesView.Prese
if (this.ctx.getAnalyticsManager() == null) {
ctx.withAnalyticsManager(new EventSeriesAnalyticsDataManager( //
clientFactory.getSailingService(), //
clientFactory, //
asyncActionsExecutor, //
new Timer(PlayModes.Live, PlayStates.Paused, delayBetweenAutoAdvancesInMilliseconds), //
clientFactory.getErrorReporter(), flagImageResolver));
@@ -78,8 +78,8 @@ public class EventSeriesCompetitorAnalyticsTabView extends SharedLeaderboardEven
}
};
if (eventSeriesAnalyticsManager.getLeaderboardPanel() == null) {
eventSeriesAnalyticsManager.getSailingService().getAvailableDetailTypesForLeaderboard(leaderboardName,
new AsyncCallback<Iterable<DetailType>>() {
eventSeriesAnalyticsManager.getAvailableDetailTypesForLeaderboard(leaderboardName,
null, new AsyncCallback<Iterable<DetailType>>() {
@Override
public void onSuccess(Iterable<DetailType> result) {
@@ -77,8 +77,8 @@ public class EventSeriesLeaderboardsTabView extends Composite implements SeriesT
final EventSeriesAnalyticsDataManager regattaAnalyticsManager = currentPresenter.getCtx()
.getAnalyticsManager();
regattaAnalyticsManager.getSailingService().getAvailableDetailTypesForLeaderboard(leaderboardName,
new AsyncCallback<Iterable<DetailType>>() {
regattaAnalyticsManager.getAvailableDetailTypesForLeaderboard(leaderboardName,
null, new AsyncCallback<Iterable<DetailType>>() {
@Override
public void onSuccess(Iterable<DetailType> result) {
@@ -64,7 +64,7 @@ public class EventSeriesOverallLeaderboardTabView extends SharedLeaderboardEvent
contentArea.setWidget(currentPresenter.getErrorAndBusyClientFactory().createBusyView());
String leaderboardName = currentPresenter.getSeriesDTO().getLeaderboardId();
if (leaderboardName != null && !leaderboardName.isEmpty()) {
currentPresenter.getCtx().getAnalyticsManager().getSailingService().getAvailableDetailTypesForLeaderboard(leaderboardName, new AsyncCallback<Iterable<DetailType>>() {
currentPresenter.getCtx().getAnalyticsManager().getAvailableDetailTypesForLeaderboard(leaderboardName, null, new AsyncCallback<Iterable<DetailType>>() {
@Override
public void onSuccess(Iterable<DetailType> result) {
@@ -4,6 +4,14 @@
<div id="mainContent">
<h4 class="articleHeadline">What's New - SAP Sailing Race Manager</h4>
<div class="innerContent">
<h5 class="articleSubheadline">February 2018</h5>
<ul class="bulletList">
<li>The protest time is now configurable in the backend. An empty value means, the RCApp
will take 90 minutes as default. If no time is set in the backend, the RCApp will save a
custom duration as new default. A server side duration (device or regatta specific) will always
be the default.</li>
</ul>
<h5 class="articleSubheadline">August 2017</h5>
<ul class="bulletList">
<li>The result list can now be edited without a finish time.</li>
@@ -22,6 +30,11 @@
for the competitor is cleared, the rank is set to 0 and the penalty is
set to "NONE" then the competitor will remain in the list, and this
"empty" result will be sent to the server, clearing any previous score
corrections that were sent to the server. This is the only way to
"reset" an erroneous score correction entirely from the app, because
swiping and thus removing the competitor from the list would leave the
previous score correction unchanged on the server upon the next result
publication.
</li>
<li>When entering and publishing partial results, updates will only be applied
for those competitors for which a result has been entered. In particular,
@@ -30,12 +43,6 @@
partial results entered on one device will not unnecessarily remove changes
applied on another device.
</li>
corrections that were sent to the server. This is the only way to
"reset" an erroneous score correction entirely from the app, because
swiping and thus removing the competitor from the list would leave the
previous score correction unchanged on the server upon the next result
publication.
</li>
</ul>
<h5 class="articleSubheadline">April 2017</h5>
@@ -19,13 +19,10 @@
<li>Selecting a filter dimension adds a table containing the available values of the selected dimension. The order of
the value tables is equal to the order of the dimensions list.
</li>
<li>Note that the selection of the filter dimensions follows the <q>table with checkbox column</q> pattern. So simply clicking on a
dimension will result in deselecting all previously selected dimensions, removing possible filter values. Clicking on the
checkbox column or using <q>ctrl+click</q> is advised.
</li>
<li>Each filter value table now has its own scroll-bar.</li>
</ul>
</li>
<li>The grouping dimensions are now ordered alphabetically.</li>
</ul>
<h5 class="articleSubheadline">April 2018</h5>
@@ -6,6 +6,7 @@ import java.util.Set;
import java.util.UUID;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
@@ -39,9 +40,11 @@ public abstract class AbstractEventView<P extends EventViewBase.Presenter> exten
static class AbstractEventViewLayout {
@UiField(provided = true) EventHeader eventHeaderUi;
@UiField Quickfinder quickFinderUi;
@UiField SimpleInfoBlock simpleInfoUi;
@UiField SimpleInfoBlock sailorInfoUi;
@UiField SimpleInfoBlock seriesNavigationoUi;
@UiField DivElement windfinderWrapperUi;
@UiField(provided = true) WindfinderControl windfinderUi;
@UiField SimplePanel viewContentUi;;
@UiField SimplePanel viewContentUi;
private AbstractEventViewLayout(EventViewDTO event, String regattaName, PlaceNavigation<?> logoNavigation) {
this.eventHeaderUi = new EventHeader(event, regattaName, logoNavigation);
@@ -125,18 +128,19 @@ public abstract class AbstractEventView<P extends EventViewBase.Presenter> exten
@Override
public void setSailorInfos(String description, String buttonLabel, String url) {
layout.simpleInfoUi.setDescription(SafeHtmlUtils.fromString(description.replace("\n", " ")));
layout.simpleInfoUi.setAction(buttonLabel, url);
layout.sailorInfoUi.setDescription(SafeHtmlUtils.fromString(description.replace("\n", " ")));
layout.sailorInfoUi.setAction(buttonLabel, url);
}
@Override
public void setWindfinderNavigations(Iterable<SpotDTO> spotData) {
layout.windfinderWrapperUi.getStyle().clearDisplay();
layout.windfinderUi.setSpotData(spotData);
}
@Override
public void setSeriesNavigation(String buttonLabel, PlaceNavigation<?> placeNavigation) {
layout.simpleInfoUi.setAction(buttonLabel, placeNavigation);
layout.seriesNavigationoUi.setAction(buttonLabel, placeNavigation);
}
}
@@ -7,9 +7,12 @@
.headerWrapper {
background-color: #f2f2f2;
}
.windfinderWrapper {
padding-bottom: 10px;
margin: 0 10px;
}
.windfinder {
display: block;
margin: 0 10px 10px;
width: 100%;
border-radius: .384615384615385em;
text-align: center;
}
@@ -18,8 +21,11 @@
<div class="{style.headerWrapper}">
<mp:eventheader.EventHeader ui:field="eventHeaderUi" />
<mp:quickfinder.Quickfinder ui:field="quickFinderUi" />
<mp:simpleinfoblock.SimpleInfoBlock ui:field="simpleInfoUi" />
<sp:windfinder.WindfinderControl ui:field="windfinderUi" addStyleNames="{style.windfinder}" />
<mp:simpleinfoblock.SimpleInfoBlock ui:field="sailorInfoUi" />
<mp:simpleinfoblock.SimpleInfoBlock ui:field="seriesNavigationoUi" />
<div class="{style.windfinderWrapper}" style="display:none;" ui:field="windfinderWrapperUi">
<sp:windfinder.WindfinderControl ui:field="windfinderUi" addStyleNames="{style.windfinder}" />
</div>
</div>
<g:SimplePanel ui:field="viewContentUi"></g:SimplePanel>
</g:HTMLPanel>
@@ -30,11 +30,11 @@ public class RegattaActivity extends AbstractEventActivity<RegattaOverviewPlace>
@Override
protected EventViewBase initView() {
final AbstractEventOverview view = new RegattaOverviewImpl(this, flagImageResolver);
initSailorInfo(view);
initSeriesNavigation(view);
initQuickfinder(view, true);
initWindfinderNavigations(view);
if (!isMultiRegattaEvent()) {
// initSailorInfo(view);
initMedia(view);
}
return view;
@@ -1,8 +1,17 @@
package com.sap.sailing.gwt.home.server.servlets;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;
import com.sap.sailing.domain.common.sharding.ShardingType;
import com.sap.sailing.domain.sharding.ShardingContext;
import com.sap.sailing.domain.windfinder.WindFinderTrackerFactory;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.server.SailingDispatchContextImpl;
@@ -47,4 +56,19 @@ public class SailingDispatchServlet extends AbstractDispatchServlet<SailingDispa
userStoreTracker.getService(), trackedRaceStatisticsCacheTracker.getService(),
request.getClientLocaleName(), getThreadLocalRequest());
}
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
ShardingType identifiedShardingType = null;
try {
if (req instanceof HttpServletRequest) {
identifiedShardingType = ShardingContext.identifyAndSetShardingConstraint( ((HttpServletRequest) req).getPathInfo());
}
super.service(req, res);
} finally {
if (identifiedShardingType != null) {
ShardingContext.clearShardingConstraint(identifiedShardingType);
}
}
}
}
@@ -26,8 +26,6 @@ public interface AnniversaryLegalMessages extends Messages{
String anniversaryLegalNoticeSectionContestParagraph(int anniversary);
String anniversaryLegalNoticeSectionCommunicationParagraphTitle();
String anniversaryLegalNoticeSectionCommunicationParagraph();
String anniversaryLegalNoticeSectionCharitablyPurposeParagraphTitle();
String anniversaryLegalNoticeSectionCharitablyPurposeParagraph();
String anniversaryLegalNoticeSectionPrizesParagraphTitle();
String anniversaryLegalNoticeSectionPrizesParagraph(int anniversary);
String anniversaryLegalNoticeSectionPersonalDataAndRightsToImagesParagraphTitle();
@@ -7,18 +7,16 @@ anniversaryLegalNoticeSectionOrganizationAndParticipationParagraph3=The organize
anniversaryLegalNoticeSectionRequirementsHeadline=Prerequisites
anniversaryLegalNoticeSectionRequirementsListItem1=SAP Sailing Analytics must be responsible for the live data analysis of each race.
anniversaryLegalNoticeSectionRequirementsListItem2=To win the prize, a race must enter into the regatta evaluation and be finished.
anniversaryLegalNoticeSectionRequirementsListItem3=The \u20AC10,000 are to be used solely for charitable purposes.
anniversaryLegalNoticeSectionRequirementsListItem3=The prize money is used solely for the purpose of paying catering (food, beverage, service).
anniversaryLegalNoticeSectionContestParagraphTitle=Contest
anniversaryLegalNoticeSectionContestParagraph=The contest will run until the {0,number,#,###}th race has begun.
anniversaryLegalNoticeSectionCommunicationParagraphTitle=Notification
anniversaryLegalNoticeSectionCommunicationParagraph=The winner will be automatically announced at www.sapsailing.com.
anniversaryLegalNoticeSectionCharitablyPurposeParagraphTitle=Charitable purposes
anniversaryLegalNoticeSectionCharitablyPurposeParagraph=The charitable purpose for which the prize is to be used must fulfill certain requirements. The winner must invest the prize in promoting sports, education, literature, the public good, health and safety, the fight against poverty, or similar aims without attempting to gain any private benefit, profit, or political influence.
anniversaryLegalNoticeSectionPrizesParagraphTitle=Prizes
anniversaryLegalNoticeSectionPrizesParagraph=The organizer of the {0,number,#,###}th race will receive the prize money.
anniversaryLegalNoticeSectionPersonalDataAndRightsToImagesParagraphTitle=Personal data and image rights
anniversaryLegalNoticeSectionPersonalDataAndRightsToImagesParagraph1=By participating in the contest, each organizer grants permission (and warrants to have received corresponding consent from its members) to the organizer, its subsidiaries and affiliated businesses, respective licensees, successors, and assignees to use the contest winner''s name, likeness, and entry for purposes of advertising and trade without further notice, consent, or compensation with regard to the contest and the event at which the contest took place, unless prohibited by law. This includes printing, publishing, broadcasting, distributing, and using the contest winner''s name, portrait, picture, voice, likeness, or image (or statements from associated members about the contest) for promotional purposes in any media now known or hereafter arising anywhere in the world.
anniversaryLegalNoticeSectionPersonalDataAndRightsToImagesParagraph2=SAP SE has set the total sum at \u20AC10,000. Event organizers must propose a charitable purpose for which they plan to use the prize to SAP SE. SAP SE reserves the right to approve these proposals or reject them should they not be deemed charitable.
anniversaryLegalNoticeSectionPersonalDataAndRightsToImagesParagraph2=SAP SE has set the total sum at \u20AC3,000. Event organizers must propose a catering plan to SAP SE. SAP SE reserves the right to approve the proposal or reject it.
anniversaryLegalNoticeSectionDisclaimerSectionParagraphTitle=Disclaimer
anniversaryLegalNoticeSectionDisclaimerSectionParagraph=SAP will assume no responsibility or liability for incomplete, inaccurate, or misdirected entries.
anniversaryLegalNoticeSectionOtherParagraphTitle=Additional information
@@ -41,10 +41,6 @@
<span><ui:text from="{i18n.anniversaryLegalNoticeSectionCommunicationParagraphTitle}"/></span>
<span><ui:text from="{i18n.anniversaryLegalNoticeSectionCommunicationParagraph}"/></span>
</p>
<p>
<span><ui:text from="{i18n.anniversaryLegalNoticeSectionCharitablyPurposeParagraphTitle}"/></span>
<span><ui:text from="{i18n.anniversaryLegalNoticeSectionCharitablyPurposeParagraph}"/></span>
</p>
<p>
<span><ui:text from="{i18n.anniversaryLegalNoticeSectionPrizesParagraphTitle}"/></span>
<span ui:field="legalNoticeSectionPrizes"></span>
@@ -12,6 +12,8 @@ import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.gwt.client.Notification;
import com.sap.sse.gwt.client.Notification.NotificationType;
public class ErrorMessage extends Composite {
@@ -42,7 +44,7 @@ public class ErrorMessage extends Composite {
}
this.errorMessageDetail.setInnerText(errorMessageDetail);
Window.setStatus(errorMessageDetail);
Notification.notify(errorMessageDetail, NotificationType.WARNING);
}
public void addReloadPageButtonStyleNames(String styleNames) {
@@ -7,7 +7,7 @@
text-decoration: none;
vertical-align: bottom;
padding-left: 1em;
padding-right: 0.5em
padding-right: 0.5em;
}
.windfindercontrol_text, .windfindercontrol_icon {
display: inline-block;
@@ -64,6 +64,7 @@ public class RegattaOverviewEntryPoint extends AbstractSailingEntryPoint {
return;
}
createAndAddDetailPanel();
createAndAddRegattaPanel(regattaOverviewContextDefinition);
toggleDetailPanel(false);
@@ -88,7 +89,7 @@ public class RegattaOverviewEntryPoint extends AbstractSailingEntryPoint {
}
private void createAndAddRegattaPanel(RegattaOverviewContextDefinition regattaOverviewContextDefinition) {
regattaPanel = new RegattaOverviewPanel(sailingService, getUserService(), this, getStringMessages(),
regattaPanel = new RegattaOverviewPanel(getSailingService(), getUserService(), this, getStringMessages(),
regattaOverviewContextDefinition);
regattaPanel.addHandler(new EventDTOLoadedEvent.Handler() {
@@ -83,14 +83,14 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
private Widget createAdminConsolePanel() {
AdminConsolePanel panel = new AdminConsolePanel(getUserService(), SailingPermissionsForRoleProvider.INSTANCE,
sailingService, getStringMessages().releaseNotes(), "/release_notes_admin.html", /* error reporter */ this, SecurityStylesheetResources.INSTANCE.css(), getStringMessages());
getSailingService(), getStringMessages().releaseNotes(), "/release_notes_admin.html", /* error reporter */ this, SecurityStylesheetResources.INSTANCE.css(), getStringMessages());
panel.addStyleName("adminConsolePanel");
regattasDisplayers = new HashSet<>();
leaderboardsDisplayers = new HashSet<>();
leaderboardGroupsDisplayers = new HashSet<>();
final EventManagementPanel eventManagementPanel = new EventManagementPanel(sailingService, this, this, getStringMessages(), panel);
final EventManagementPanel eventManagementPanel = new EventManagementPanel(getSailingService(), this, this, getStringMessages(), panel);
eventManagementPanel.ensureDebugId("EventManagement");
panel.addToVerticalTabPanel(new DefaultRefreshableAdminConsolePanel<EventManagementPanel>(eventManagementPanel) {
@Override
@@ -104,7 +104,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
/* REGATTAS */
RegattaManagementPanel regattaManagementPanel = new RegattaManagementPanel(
sailingService, this, getStringMessages(), this, eventManagementPanel);
getSailingService(), this, getStringMessages(), this, eventManagementPanel);
regattaManagementPanel.ensureDebugId("RegattaStructureManagement");
panel.addToVerticalTabPanel(new DefaultRefreshableAdminConsolePanel<RegattaManagementPanel>(regattaManagementPanel) {
@Override
@@ -117,7 +117,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
/* LEADERBOARDS */
final HorizontalTabLayoutPanel leaderboardTabPanel = panel.addVerticalTab(getStringMessages().leaderboards(), "LeaderboardPanel");
final LeaderboardConfigPanel leaderboardConfigPanel = new LeaderboardConfigPanel(sailingService, this, this,
final LeaderboardConfigPanel leaderboardConfigPanel = new LeaderboardConfigPanel(getSailingService(), this, this,
getStringMessages(), /* showRaceDetails */true, this);
leaderboardConfigPanel.ensureDebugId("LeaderboardConfiguration");
panel.addToTabPanel(leaderboardTabPanel, new DefaultRefreshableAdminConsolePanel<LeaderboardConfigPanel>(leaderboardConfigPanel) {
@@ -129,7 +129,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
regattasDisplayers.add(leaderboardConfigPanel);
leaderboardsDisplayers.add(leaderboardConfigPanel);
final LeaderboardGroupConfigPanel leaderboardGroupConfigPanel = new LeaderboardGroupConfigPanel(sailingService,
final LeaderboardGroupConfigPanel leaderboardGroupConfigPanel = new LeaderboardGroupConfigPanel(getSailingService(),
this, this, this, this, getStringMessages());
leaderboardGroupConfigPanel.ensureDebugId("LeaderboardGroupConfiguration");
panel.addToTabPanel(leaderboardTabPanel, new DefaultRefreshableAdminConsolePanel<LeaderboardGroupConfigPanel>(leaderboardGroupConfigPanel) {
@@ -154,7 +154,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
final HorizontalTabLayoutPanel racesTabPanel = panel.addVerticalTab(getStringMessages().trackedRaces(), "RacesPanel");
racesTabPanel.ensureDebugId("RacesPanel");
final TrackedRacesManagementPanel trackedRacesManagementPanel = new TrackedRacesManagementPanel(sailingService, this,
final TrackedRacesManagementPanel trackedRacesManagementPanel = new TrackedRacesManagementPanel(getSailingService(), this,
this, getStringMessages());
trackedRacesManagementPanel.ensureDebugId("TrackedRacesManagement");
panel.addToTabPanel(racesTabPanel, new DefaultRefreshableAdminConsolePanel<TrackedRacesManagementPanel>(trackedRacesManagementPanel) {
@@ -165,7 +165,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
}, getStringMessages().trackedRaces(), Permission.SHOW_TRACKED_RACES);
regattasDisplayers.add(trackedRacesManagementPanel);
final CompetitorPanel competitorPanel = new CompetitorPanel(sailingService, getStringMessages(), this);
final CompetitorPanel competitorPanel = new CompetitorPanel(getSailingService(), getStringMessages(), this);
competitorPanel.ensureDebugId("CompetitorPanel");
panel.addToTabPanel(racesTabPanel, new DefaultRefreshableAdminConsolePanel<CompetitorPanel>(competitorPanel) {
@Override
@@ -174,7 +174,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
}
}, getStringMessages().competitors(), Permission.MANAGE_ALL_COMPETITORS);
final BoatPanel boatPanel = new BoatPanel(sailingService, getStringMessages(), this);
final BoatPanel boatPanel = new BoatPanel(getSailingService(), getStringMessages(), this);
boatPanel.ensureDebugId("BoatPanel");
panel.addToTabPanel(racesTabPanel, new DefaultRefreshableAdminConsolePanel<BoatPanel>(boatPanel) {
@Override
@@ -183,18 +183,18 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
}
}, getStringMessages().boats(), Permission.MANAGE_ALL_BOATS);
RaceCourseManagementPanel raceCourseManagementPanel = new RaceCourseManagementPanel(sailingService, this, this, getStringMessages());
RaceCourseManagementPanel raceCourseManagementPanel = new RaceCourseManagementPanel(getSailingService(), this, this, getStringMessages());
panel.addToTabPanel(racesTabPanel, new DefaultRefreshableAdminConsolePanel<RaceCourseManagementPanel>(raceCourseManagementPanel), getStringMessages().courseLayout(), Permission.MANAGE_COURSE_LAYOUT);
regattasDisplayers.add(raceCourseManagementPanel);
final AsyncActionsExecutor asyncActionsExecutor = new AsyncActionsExecutor();
WindPanel windPanel = new WindPanel(sailingService, asyncActionsExecutor, this, this, getStringMessages());
WindPanel windPanel = new WindPanel(getSailingService(), asyncActionsExecutor, this, this, getStringMessages());
panel.addToTabPanel(racesTabPanel, new DefaultRefreshableAdminConsolePanel<WindPanel>(windPanel), getStringMessages().wind(),
Permission.MANAGE_WIND);
regattasDisplayers.add(windPanel);
final MediaPanel mediaPanel = new MediaPanel(regattasDisplayers, sailingService, this, mediaService, this, getStringMessages());
final MediaPanel mediaPanel = new MediaPanel(regattasDisplayers, getSailingService(), this, mediaService, this, getStringMessages());
panel.addToTabPanel(racesTabPanel, new DefaultRefreshableAdminConsolePanel<MediaPanel>(mediaPanel) {
@Override
public void refreshAfterBecomingVisible() {
@@ -205,7 +205,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
/* RACE COMMITTEE APP */
final HorizontalTabLayoutPanel raceCommitteeTabPanel = panel.addVerticalTab(getStringMessages().raceCommitteeApp(), "RaceCommiteeAppPanel");
final DeviceConfigurationUserPanel deviceConfigurationUserPanel = new DeviceConfigurationUserPanel(sailingService,
final DeviceConfigurationUserPanel deviceConfigurationUserPanel = new DeviceConfigurationUserPanel(getSailingService(),
getUserService(), getStringMessages(), this);
panel.addToTabPanel(raceCommitteeTabPanel, new DefaultRefreshableAdminConsolePanel<DeviceConfigurationUserPanel>(deviceConfigurationUserPanel),
getStringMessages().deviceConfiguration(), Permission.MANAGE_DEVICE_CONFIGURATION);
@@ -213,7 +213,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
/* CONNECTORS */
final HorizontalTabLayoutPanel connectorsTabPanel = panel.addVerticalTab(getStringMessages().connectors(), "TrackingProviderPanel");
TracTracEventManagementPanel tractracEventManagementPanel = new TracTracEventManagementPanel(sailingService,
TracTracEventManagementPanel tractracEventManagementPanel = new TracTracEventManagementPanel(getSailingService(),
this, this, getStringMessages());
tractracEventManagementPanel.ensureDebugId("TracTracEventManagement");
panel.addToTabPanel(connectorsTabPanel, new DefaultRefreshableAdminConsolePanel<TracTracEventManagementPanel>(tractracEventManagementPanel),
@@ -221,19 +221,19 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
regattasDisplayers.add(tractracEventManagementPanel);
SwissTimingReplayConnectorPanel swissTimingReplayConnectorPanel = new SwissTimingReplayConnectorPanel(
sailingService, this, this, getStringMessages());
getSailingService(), this, this, getStringMessages());
panel.addToTabPanel(connectorsTabPanel, new DefaultRefreshableAdminConsolePanel<SwissTimingReplayConnectorPanel>(swissTimingReplayConnectorPanel),
getStringMessages().swissTimingArchiveConnector(), Permission.MANAGE_TRACKED_RACES);
regattasDisplayers.add(swissTimingReplayConnectorPanel);
SwissTimingEventManagementPanel swisstimingEventManagementPanel = new SwissTimingEventManagementPanel(
sailingService, this, this, getStringMessages());
getSailingService(), this, this, getStringMessages());
panel.addToTabPanel(connectorsTabPanel, new DefaultRefreshableAdminConsolePanel<SwissTimingEventManagementPanel>(swisstimingEventManagementPanel),
getStringMessages().swissTimingEvents(), Permission.MANAGE_TRACKED_RACES);
regattasDisplayers.add(swisstimingEventManagementPanel);
final SmartphoneTrackingEventManagementPanel raceLogTrackingEventManagementPanel = new SmartphoneTrackingEventManagementPanel(
sailingService, this, this, this, getStringMessages());
getSailingService(), this, this, this, getStringMessages());
raceLogTrackingEventManagementPanel.ensureDebugId("SmartphoneTrackingPanel");
panel.addToTabPanel(connectorsTabPanel, new DefaultRefreshableAdminConsolePanel<SmartphoneTrackingEventManagementPanel>(raceLogTrackingEventManagementPanel) {
@Override
@@ -244,12 +244,12 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
regattasDisplayers.add(raceLogTrackingEventManagementPanel);
leaderboardsDisplayers.add(raceLogTrackingEventManagementPanel);
IgtimiAccountsPanel igtimiAccountsPanel = new IgtimiAccountsPanel(sailingService, this, getStringMessages());
IgtimiAccountsPanel igtimiAccountsPanel = new IgtimiAccountsPanel(getSailingService(), this, getStringMessages());
igtimiAccountsPanel.ensureDebugId("IgtimiAccounts");
panel.addToTabPanel(connectorsTabPanel, new DefaultRefreshableAdminConsolePanel<IgtimiAccountsPanel>(igtimiAccountsPanel),
getStringMessages().igtimiAccounts(), Permission.MANAGE_IGTIMI_ACCOUNTS);
ExpeditionDeviceConfigurationsPanel expeditionDeviceConfigurationsPanel = new ExpeditionDeviceConfigurationsPanel(sailingService, this, getStringMessages());
ExpeditionDeviceConfigurationsPanel expeditionDeviceConfigurationsPanel = new ExpeditionDeviceConfigurationsPanel(getSailingService(), this, getStringMessages());
expeditionDeviceConfigurationsPanel.ensureDebugId("ExpeditionDeviceConfigurations");
panel.addToTabPanel(connectorsTabPanel, new DefaultRefreshableAdminConsolePanel<ExpeditionDeviceConfigurationsPanel>(expeditionDeviceConfigurationsPanel) {
@Override
@@ -258,11 +258,11 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
}
}, getStringMessages().expeditionDeviceConfigurations(), Permission.MANAGE_EXPEDITION_DEVICE_CONFIGURATIONS);
ResultImportUrlsManagementPanel resultImportUrlsManagementPanel = new ResultImportUrlsManagementPanel(sailingService, this, getStringMessages());
ResultImportUrlsManagementPanel resultImportUrlsManagementPanel = new ResultImportUrlsManagementPanel(getSailingService(), this, getStringMessages());
panel.addToTabPanel(connectorsTabPanel, new DefaultRefreshableAdminConsolePanel<ResultImportUrlsManagementPanel>(resultImportUrlsManagementPanel),
getStringMessages().resultImportUrls(), Permission.MANAGE_RESULT_IMPORT_URLS);
StructureImportManagementPanel structureImportUrlsManagementPanel = new StructureImportManagementPanel(sailingService, this, getStringMessages(), this, eventManagementPanel);
StructureImportManagementPanel structureImportUrlsManagementPanel = new StructureImportManagementPanel(getSailingService(), this, getStringMessages(), this, eventManagementPanel);
panel.addToTabPanel(connectorsTabPanel, new DefaultRefreshableAdminConsolePanel<StructureImportManagementPanel>(structureImportUrlsManagementPanel),
getStringMessages().manage2Sail() + " " + getStringMessages().regattaStructureImport(), Permission.MANAGE_STRUCTURE_IMPORT_URLS);
@@ -270,7 +270,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
final HorizontalTabLayoutPanel advancedTabPanel = panel.addVerticalTab(getStringMessages().advanced(), "AdvancedPanel");
advancedTabPanel.ensureDebugId("AdvancedTab");
final ReplicationPanel replicationPanel = new ReplicationPanel(sailingService, this, getStringMessages());
final ReplicationPanel replicationPanel = new ReplicationPanel(getSailingService(), this, getStringMessages());
panel.addToTabPanel(advancedTabPanel, new DefaultRefreshableAdminConsolePanel<ReplicationPanel>(replicationPanel) {
@Override
public void refreshAfterBecomingVisible() {
@@ -278,17 +278,17 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
}
}, getStringMessages().replication(), Permission.MANAGE_REPLICATION);
final MasterDataImportPanel masterDataImportPanel = new MasterDataImportPanel(getStringMessages(), sailingService,
final MasterDataImportPanel masterDataImportPanel = new MasterDataImportPanel(getStringMessages(), getSailingService(),
this, eventManagementPanel, this, this, mediaPanel);
masterDataImportPanel.ensureDebugId("MasterDataImport");
panel.addToTabPanel(advancedTabPanel, new DefaultRefreshableAdminConsolePanel<MasterDataImportPanel>(masterDataImportPanel),
getStringMessages().masterDataImportPanel(), Permission.MANAGE_MASTERDATA_IMPORT);
RemoteServerInstancesManagementPanel remoteServerInstancesManagementPanel = new RemoteServerInstancesManagementPanel(sailingService, this, getStringMessages());
RemoteServerInstancesManagementPanel remoteServerInstancesManagementPanel = new RemoteServerInstancesManagementPanel(getSailingService(), this, getStringMessages());
panel.addToTabPanel(advancedTabPanel, new DefaultRefreshableAdminConsolePanel<RemoteServerInstancesManagementPanel>(remoteServerInstancesManagementPanel),
getStringMessages().remoteServerInstances(), Permission.MANAGE_SAILING_SERVER_INSTANCES);
LocalServerManagementPanel localServerInstancesManagementPanel = new LocalServerManagementPanel(sailingService, this, getStringMessages());
LocalServerManagementPanel localServerInstancesManagementPanel = new LocalServerManagementPanel(getSailingService(), this, getStringMessages());
panel.addToTabPanel(advancedTabPanel, new DefaultRefreshableAdminConsolePanel<LocalServerManagementPanel>(localServerInstancesManagementPanel),
getStringMessages().localServer(), Permission.MANAGE_LOCAL_SERVER_INSTANCE);
@@ -297,7 +297,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
panel.addToTabPanel(advancedTabPanel, new DefaultRefreshableAdminConsolePanel<UserManagementPanel>(userManagementPanel),
getStringMessages().userManagement(), Permission.MANAGE_USERS);
final FileStoragePanel fileStoragePanel = new FileStoragePanel(sailingService, this);
final FileStoragePanel fileStoragePanel = new FileStoragePanel(getSailingService(), this);
panel.addToTabPanel(advancedTabPanel, new DefaultRefreshableAdminConsolePanel<FileStoragePanel>(fileStoragePanel),
getStringMessages().fileStorage(), Permission.MANAGE_FILE_STORAGE);
@@ -311,7 +311,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
@Override
public void fillLeaderboards() {
sailingService.getLeaderboards(new MarkedAsyncCallback<List<StrippedLeaderboardDTO>>(
getSailingService().getLeaderboards(new MarkedAsyncCallback<List<StrippedLeaderboardDTO>>(
new AsyncCallback<List<StrippedLeaderboardDTO>>() {
@Override
public void onSuccess(List<StrippedLeaderboardDTO> leaderboards) {
@@ -338,7 +338,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
@Override
public void fillLeaderboardGroups() {
sailingService.getLeaderboardGroups(false /*withGeoLocationData*/,
getSailingService().getLeaderboardGroups(false /*withGeoLocationData*/,
new MarkedAsyncCallback<List<LeaderboardGroupDTO>>(
new AsyncCallback<List<LeaderboardGroupDTO>>() {
@Override
@@ -366,7 +366,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
@Override
public void fillRegattas() {
sailingService.getRegattas(new MarkedAsyncCallback<List<RegattaDTO>>(
getSailingService().getRegattas(new MarkedAsyncCallback<List<RegattaDTO>>(
new AsyncCallback<List<RegattaDTO>>() {
@Override
public void onSuccess(List<RegattaDTO> result) {
@@ -1,6 +1,6 @@
package com.sap.sailing.gwt.ui.adminconsole;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@@ -334,7 +334,7 @@ TrackedRaceChangedListener, LeaderboardsDisplayer {
});
editCompetitorsDialog.show();
} else if (LeaderboardConfigImagesBarCell.ACTION_CONFIGURE_URL.equals(value)) {
sailingService.getAvailableDetailTypesForLeaderboard(leaderboardDTO.name, new AsyncCallback<Iterable<DetailType>>() {
sailingService.getAvailableDetailTypesForLeaderboard(leaderboardDTO.name, null, new AsyncCallback<Iterable<DetailType>>() {
@Override
public void onFailure(Throwable caught) {
@@ -4,7 +4,6 @@ import java.util.Date;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlowPanel;
@@ -14,6 +13,8 @@ import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.RaceCourseDTO;
import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.Notification;
import com.sap.sse.gwt.client.Notification.NotificationType;
/**
* A panel that has a race selection (inherited from {@link AbstractRaceManagementPanel}) and which adds a table
@@ -41,7 +42,7 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
@Override
public void onSuccess(Void result) {
Window.setStatus(stringMessages.successfullyUpdatedCourse());
Notification.notify(stringMessages.successfullyUpdatedCourse(), NotificationType.INFO);
refreshSelectedRaceData();
}
});
@@ -23,12 +23,13 @@ import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.DeviceConfigurationDTO;
import com.sap.sailing.gwt.ui.shared.DeviceConfigurationDTO.RegattaConfigurationDTO;
import com.sap.sailing.gwt.ui.shared.DeviceConfigurationDTO.RegattaConfigurationDTO.RacingProcedureConfigurationDTO;
import com.sap.sse.common.Duration;
import com.sap.sse.gwt.client.controls.IntegerBox;
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurationDTO.RegattaConfigurationDTO> {
private final AdminConsoleResources resources = GWT.create(AdminConsoleResources.class);
private final StringMessages stringMessages;
private final DeviceConfigurationDTO.RegattaConfigurationDTO originalConfiguration;
@@ -36,6 +37,7 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
private ListBox racingProcedureListBox;
private ListBox designerModeEntryListBox;
private IntegerBox protestTimeInMinutesTextBox;
private DisclosurePanel rrs26DisclosurePanel;
private CheckBox rrs26EnabledBox;
@@ -118,9 +120,10 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
}
private void setupGeneral() {
Grid grid = new Grid(2, 2);
Grid grid = new Grid(3, 2);
setupCourseDesignerListBox(grid, 0);
setupRacingProcedureListBox(grid, 1);
setupProtestTimeTextBox(grid, 2);
contentPanel.add(grid);
}
@@ -155,6 +158,14 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
grid.setWidget(gridRow, 1, designerModeEntryListBox);
}
private void setupProtestTimeTextBox(Grid grid, int gridRow) {
final Integer protestTimeDurationInMinutes = originalConfiguration.defaultProtestTimeDuration == null ? null :
(int) originalConfiguration.defaultProtestTimeDuration.asMinutes();
protestTimeInMinutesTextBox = createIntegerBox(protestTimeDurationInMinutes, 3);
grid.setWidget(gridRow, 0, new Label(stringMessages.protestTime()));
grid.setWidget(gridRow, 1, protestTimeInMinutesTextBox);
}
private ListBox setupClassFlagListBox(RacingProcedureConfigurationDTO config) {
ListBox box = createListBox(false);
Flags selectedFlag = null;
@@ -345,6 +356,7 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
if (originalConfiguration.gateStartConfiguration != null) {
gateStartGolfDownBox.setValue(originalConfiguration.gateStartConfiguration.hasAdditionalGolfDownTime);
}
grid.setWidget(0, 0, new Label(stringMessages.classFlag() + ":"));
grid.setWidget(0, 1, gateStartClassFlagListBox);
grid.setWidget(0, 2, createHelpImage(stringMessages.classFlagHelpText("Gate Start")));
@@ -500,6 +512,8 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
CourseDesignerMode mode = CourseDesignerMode.valueOf(designerModeEntryListBox.getValue(index));
result.defaultCourseDesignerMode = mode == CourseDesignerMode.UNKNOWN ? null : mode;
}
result.defaultProtestTimeDuration = protestTimeInMinutesTextBox.getValue() == null ? null :
Duration.ONE_MINUTE.times(protestTimeInMinutesTextBox.getValue());
if (rrs26EnabledBox.getValue()) {
result.rrs26Configuration = new DeviceConfigurationDTO.RegattaConfigurationDTO.RRS26ConfigurationDTO();
getRacingProcedureConfigurationResults(result.rrs26Configuration, rrs26ClassFlagListBox, rrs26RecallBox, rrs26ResultEntryBox);
@@ -15,7 +15,6 @@ import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CaptionPanel;
@@ -30,6 +29,8 @@ import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.EventBaseDTO;
import com.sap.sailing.gwt.ui.shared.RemoteSailingServerReferenceDTO;
import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.Notification;
import com.sap.sse.gwt.client.Notification.NotificationType;
import com.sap.sse.gwt.client.celltable.BaseCelltable;
import com.sap.sse.gwt.client.celltable.EntityIdentityComparator;
import com.sap.sse.gwt.client.celltable.RefreshableMultiSelectionModel;
@@ -209,7 +210,7 @@ public class RemoteServerInstancesManagementPanel extends SimplePanel {
@Override
public void onSuccess(Void result) {
refreshSailingServerList();
Window.setStatus(stringMessages.successfullyUpdatedSailingServers());
Notification.notify(stringMessages.successfullyUpdatedSailingServers(), NotificationType.INFO);
}
});
}
@@ -230,8 +231,8 @@ public class RemoteServerInstancesManagementPanel extends SimplePanel {
@Override
public void onSuccess(RemoteSailingServerReferenceDTO result) {
filteredServerTablePanel.add(result);
Window.setStatus(stringMessages.successfullyUpdatedSailingServers());
filteredServerTablePanel.add(result);
Notification.notify(stringMessages.successfullyUpdatedSailingServers(), NotificationType.INFO);
}
});
}
@@ -8,7 +8,6 @@ import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlowPanel;
@@ -22,6 +21,8 @@ import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.TextfieldEntryDialog;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.Notification;
import com.sap.sse.gwt.client.Notification.NotificationType;
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback;
@@ -163,7 +164,7 @@ public class ResultImportUrlsManagementPanel extends FlowPanel {
@Override
public void onSuccess(Void result) {
Window.setStatus(stringMessages.successfullyUpdatedResultImportUrls());
Notification.notify(stringMessages.successfullyUpdatedResultImportUrls(), NotificationType.INFO);
}
});
}
@@ -198,7 +199,7 @@ public class ResultImportUrlsManagementPanel extends FlowPanel {
@Override
public void onSuccess(Void result) {
urlListBox.addItem(url);
Window.setStatus(stringMessages.successfullyUpdatedResultImportUrls());
Notification.notify(stringMessages.successfullyUpdatedResultImportUrls(), NotificationType.INFO);
}
});
}
@@ -5,14 +5,12 @@ import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.ColumnSortEvent.Handler;
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
@@ -35,15 +33,15 @@ import com.sap.sailing.domain.common.RegattaName;
import com.sap.sailing.gwt.ui.client.RegattaRefresher;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.shared.controls.FlushableCellTable;
import com.sap.sailing.gwt.ui.client.shared.controls.SelectionCheckboxColumn;
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
import com.sap.sailing.gwt.ui.shared.SwissTimingConfigurationDTO;
import com.sap.sailing.gwt.ui.shared.SwissTimingEventRecordDTO;
import com.sap.sailing.gwt.ui.shared.SwissTimingRaceRecordDTO;
import com.sap.sse.common.util.NaturalComparator;
import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.celltable.BaseCelltable;
import com.sap.sse.gwt.client.celltable.EntityIdentityComparator;
import com.sap.sse.gwt.client.celltable.RefreshableMultiSelectionModel;
import com.sap.sse.gwt.client.panels.LabeledAbstractFilterablePanel;
/**
@@ -55,15 +53,22 @@ import com.sap.sse.gwt.client.panels.LabeledAbstractFilterablePanel;
*
*/
public class SwissTimingEventManagementPanel extends AbstractEventManagementPanel {
private static final AdminConsoleTableResources tableRes = GWT.create(AdminConsoleTableResources.class);
private final LabeledAbstractFilterablePanel<SwissTimingRaceRecordDTO> filterablePanelEvents;
private final ListDataProvider<SwissTimingRaceRecordDTO> raceList;
private final CellTable<SwissTimingRaceRecordDTO> raceTable;
private final FlushableCellTable<SwissTimingRaceRecordDTO> raceTable;
private final Map<String, SwissTimingConfigurationDTO> previousConfigurations;
private final ListBox previousConfigurationsComboBox;
private final TextBox eventIdBox;
private final TextBox jsonUrlBox;
private final TextBox hostnameTextbox;
private final IntegerBox portIntegerbox;
private final List<SwissTimingRaceRecordDTO> availableSwissTimingRaces = new ArrayList<SwissTimingRaceRecordDTO>();
private final String manage2sailBaseAPIUrl = "http://manage2sail.com/api/public/links/event/";
private final String manage2sailAPIaccessToken = "?accesstoken=bDAv8CwsTM94ujZ";
private final String manage2sailUrlAppendix = "&mediaType=json&includeRaces=true";
private final String eventIdPattern = "[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}";
public SwissTimingEventManagementPanel(final SailingServiceAsync sailingService,
ErrorReporter errorReporter,
@@ -83,7 +88,7 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
captionPanelConnections.setContentWidget(verticalPanel);
captionPanelConnections.setStyleName("bold");
Grid connectionsGrid = new Grid(5, 2);
Grid connectionsGrid = new Grid(6, 2);
verticalPanel.add(connectionsGrid);
previousConfigurations = new HashMap<String, SwissTimingConfigurationDTO>();
@@ -102,89 +107,50 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
}
});
fillConfigurations();
jsonUrlBox = new TextBox();
jsonUrlBox.getElement().getStyle().setWidth(50, Unit.EM);
connectionsGrid.setWidget(0, 0, new Label(stringMessages.swissTimingEvents() + ":"));
connectionsGrid.setWidget(0, 1, previousConfigurationsComboBox);
connectionsGrid.setWidget(1, 0, new Label("Manage2Sail Event-URL (json):"));
connectionsGrid.setWidget(1, 1, jsonUrlBox);
eventIdBox = new TextBox();
eventIdBox.getElement().getStyle().setWidth(30, Unit.EM);
eventIdBox.setTitle(stringMessages.manage2SailEventIdBoxTooltip());
connectionsGrid.setWidget(1, 0, new Label(stringMessages.manage2SailEventIdBox() + ":"));
connectionsGrid.setWidget(1, 1, eventIdBox);
eventIdBox.addChangeHandler(event -> {
if (eventIdBox.getValue() != "") {
updateUrlFromEventId(eventIdBox.getValue());
}
});
connectionsGrid.setWidget(2, 0, new Label(stringMessages.manage2SailEventURLBox() + ":"));
connectionsGrid.setWidget(2, 1, jsonUrlBox);
jsonUrlBox.addChangeHandler(event -> {
if (jsonUrlBox.getValue() != "") {
updateEventIdFromUrl(jsonUrlBox.getValue());
}
});
hostnameTextbox = new TextBox();
portIntegerbox = new IntegerBox();
connectionsGrid.setWidget(2, 0, new Label(stringConstants.hostname() + ":"));
connectionsGrid.setWidget(2, 1, hostnameTextbox);
connectionsGrid.setWidget(3, 0, new Label(stringConstants.hostname() + ":"));
connectionsGrid.setWidget(3, 1, hostnameTextbox);
connectionsGrid.setWidget(3, 0, new Label(stringConstants.port() + ":"));
connectionsGrid.setWidget(3, 1, portIntegerbox);
connectionsGrid.setWidget(4, 0, new Label(stringMessages.manage2SailPort() + ":"));
connectionsGrid.setWidget(4, 1, portIntegerbox);
Button btnListRaces = new Button(stringConstants.listRaces());
connectionsGrid.setWidget(4, 1, btnListRaces);
connectionsGrid.setWidget(5, 1, btnListRaces);
btnListRaces.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
fillRaces(sailingService);
}
});
TextColumn<SwissTimingRaceRecordDTO> raceNameColumn = new TextColumn<SwissTimingRaceRecordDTO>() {
@Override
public String getValue(SwissTimingRaceRecordDTO object) {
return object.getName();
}
};
TextColumn<SwissTimingRaceRecordDTO> regattaNameColumn = new TextColumn<SwissTimingRaceRecordDTO>() {
@Override
public String getValue(SwissTimingRaceRecordDTO object) {
return object.regattaName;
}
};
TextColumn<SwissTimingRaceRecordDTO> seriesNameColumn = new TextColumn<SwissTimingRaceRecordDTO>() {
@Override
public String getValue(SwissTimingRaceRecordDTO object) {
return object.seriesName;
}
};
TextColumn<SwissTimingRaceRecordDTO> raceIdColumn = new TextColumn<SwissTimingRaceRecordDTO>() {
@Override
public String getValue(SwissTimingRaceRecordDTO object) {
return object.raceId;
}
};
TextColumn<SwissTimingRaceRecordDTO> boatClassColumn = new TextColumn<SwissTimingRaceRecordDTO>() {
@Override
public String getValue(SwissTimingRaceRecordDTO object) {
return object.boatClass != null ? object.boatClass : "";
}
};
TextColumn<SwissTimingRaceRecordDTO> genderColumn = new TextColumn<SwissTimingRaceRecordDTO>() {
@Override
public String getValue(SwissTimingRaceRecordDTO object) {
return object.gender != null ? object.gender : "";
}
};
TextColumn<SwissTimingRaceRecordDTO> raceStatusColumn = new TextColumn<SwissTimingRaceRecordDTO>() {
@Override
public String getValue(SwissTimingRaceRecordDTO object) {
return object.raceStatus != null ? object.raceStatus : "";
}
};
TextColumn<SwissTimingRaceRecordDTO> raceStartTimeColumn = new TextColumn<SwissTimingRaceRecordDTO>() {
@Override
public String getValue(SwissTimingRaceRecordDTO object) {
return object.raceStartTime==null?"":dateFormatter.render(object.raceStartTime) + " " + timeFormatter.render(object.raceStartTime);
}
};
HorizontalPanel racesSplitPanel = new HorizontalPanel();
mainPanel.add(racesSplitPanel);
@@ -236,7 +202,7 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
useInternalMarkPassingAlgorithmCheckbox.setWordWrap(false);
useInternalMarkPassingAlgorithmCheckbox.setValue(Boolean.FALSE);
trackableRacesPanel.add(useInternalMarkPassingAlgorithmCheckbox);
// text box for filtering the cell table
HorizontalPanel filterPanel = new HorizontalPanel();
filterPanel.setSpacing(5);
@@ -246,23 +212,7 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
filterPanel.add(lblFilterEvents);
filterPanel.setCellVerticalAlignment(lblFilterEvents, HasVerticalAlignment.ALIGN_MIDDLE);
raceNameColumn.setSortable(true);
raceStartTimeColumn.setSortable(true);
boatClassColumn.setSortable(true);
raceIdColumn.setSortable(true);
genderColumn.setSortable(true);
raceStatusColumn.setSortable(true);
AdminConsoleTableResources tableRes = GWT.create(AdminConsoleTableResources.class);
raceTable = new BaseCelltable<SwissTimingRaceRecordDTO>(/* pageSize */10000, tableRes);
raceTable.addColumn(regattaNameColumn, stringConstants.regatta());
raceTable.addColumn(seriesNameColumn, stringConstants.series());
raceTable.addColumn(raceNameColumn, stringConstants.name());
//raceTable.addColumn(raceIdColumn, stringConstants.id());
raceTable.addColumn(raceStatusColumn, stringConstants.status());
raceTable.addColumn(boatClassColumn, stringConstants.boatClass());
raceTable.addColumn(genderColumn, "Gender");
raceTable.addColumn(raceStartTimeColumn, stringConstants.startTime());
raceTable = new FlushableCellTable<SwissTimingRaceRecordDTO>(/* pageSize */10000, tableRes);
raceTable.setWidth("300px");
raceList = new ListDataProvider<SwissTimingRaceRecordDTO>();
filterablePanelEvents = new LabeledAbstractFilterablePanel<SwissTimingRaceRecordDTO>(lblFilterEvents,
@@ -282,19 +232,99 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
return strings;
}
};
raceTable.setSelectionModel(new RefreshableMultiSelectionModel<SwissTimingRaceRecordDTO>(
new EntityIdentityComparator<SwissTimingRaceRecordDTO>() {
@Override
public boolean representSameEntity(SwissTimingRaceRecordDTO dto1, SwissTimingRaceRecordDTO dto2) {
return dto1.raceId.equals(dto2.raceId);
}
@Override
public int hashCode(SwissTimingRaceRecordDTO t) {
return t.raceId.hashCode();
}
}, filterablePanelEvents.getAllListDataProvider()) {
});
final EntityIdentityComparator<SwissTimingRaceRecordDTO> entityIdentityComparator = new EntityIdentityComparator<SwissTimingRaceRecordDTO>() {
@Override
public boolean representSameEntity(SwissTimingRaceRecordDTO dto1, SwissTimingRaceRecordDTO dto2) {
return dto1.raceId.equals(dto2.raceId);
}
@Override
public int hashCode(SwissTimingRaceRecordDTO t) {
return t.raceId.hashCode();
}
};
TextColumn<SwissTimingRaceRecordDTO> raceNameColumn = new TextColumn<SwissTimingRaceRecordDTO>() {
@Override
public String getValue(SwissTimingRaceRecordDTO object) {
return object.getName();
}
};
TextColumn<SwissTimingRaceRecordDTO> regattaNameColumn = new TextColumn<SwissTimingRaceRecordDTO>() {
@Override
public String getValue(SwissTimingRaceRecordDTO object) {
return object.regattaName;
}
};
SelectionCheckboxColumn<SwissTimingRaceRecordDTO> selectionColumn = new SelectionCheckboxColumn<SwissTimingRaceRecordDTO>(
tableRes.cellTableStyle().cellTableCheckboxSelected(),
tableRes.cellTableStyle().cellTableCheckboxDeselected(),
tableRes.cellTableStyle().cellTableCheckboxColumnCell(), entityIdentityComparator, raceList, raceTable);
TextColumn<SwissTimingRaceRecordDTO> seriesNameColumn = new TextColumn<SwissTimingRaceRecordDTO>() {
@Override
public String getValue(SwissTimingRaceRecordDTO object) {
return object.seriesName;
}
};
TextColumn<SwissTimingRaceRecordDTO> raceIdColumn = new TextColumn<SwissTimingRaceRecordDTO>() {
@Override
public String getValue(SwissTimingRaceRecordDTO object) {
return object.raceId;
}
};
TextColumn<SwissTimingRaceRecordDTO> boatClassColumn = new TextColumn<SwissTimingRaceRecordDTO>() {
@Override
public String getValue(SwissTimingRaceRecordDTO object) {
return object.boatClass != null ? object.boatClass : "";
}
};
TextColumn<SwissTimingRaceRecordDTO> genderColumn = new TextColumn<SwissTimingRaceRecordDTO>() {
@Override
public String getValue(SwissTimingRaceRecordDTO object) {
return object.gender != null ? object.gender : "";
}
};
TextColumn<SwissTimingRaceRecordDTO> raceStatusColumn = new TextColumn<SwissTimingRaceRecordDTO>() {
@Override
public String getValue(SwissTimingRaceRecordDTO object) {
return object.raceStatus != null ? object.raceStatus : "";
}
};
TextColumn<SwissTimingRaceRecordDTO> raceStartTimeColumn = new TextColumn<SwissTimingRaceRecordDTO>() {
@Override
public String getValue(SwissTimingRaceRecordDTO object) {
return object.raceStartTime==null?"":dateFormatter.render(object.raceStartTime) + " " + timeFormatter.render(object.raceStartTime);
}
};
raceNameColumn.setSortable(true);
raceStartTimeColumn.setSortable(true);
boatClassColumn.setSortable(true);
raceIdColumn.setSortable(true);
genderColumn.setSortable(true);
raceStatusColumn.setSortable(true);
raceTable.addColumn(selectionColumn, selectionColumn.getHeader());
raceTable.addColumn(regattaNameColumn, stringConstants.regatta());
raceTable.addColumn(seriesNameColumn, stringConstants.series());
raceTable.addColumn(raceNameColumn, stringConstants.name());
//raceTable.addColumn(raceIdColumn, stringConstants.id());
raceTable.addColumn(raceStatusColumn, stringConstants.status());
raceTable.addColumn(boatClassColumn, stringConstants.boatClass());
raceTable.addColumn(genderColumn, stringConstants.gender());
raceTable.addColumn(raceStartTimeColumn, stringConstants.startTime());
raceTable.setSelectionModel(selectionColumn.getSelectionModel(), selectionColumn.getSelectionManager());
trackableRacesPanel.add(raceTable);
raceList.addDataDisplay(raceTable);
Handler columnSortHandler = getRaceTableColumnSortHandler(raceList.getList(), regattaNameColumn, seriesNameColumn,
@@ -318,6 +348,31 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
});
}
/**
* This function tries to infer a valid JsonUrl for any input given that matches the pattern of an event Id from
* M2S. If there is an event id detected the Json Url gets updated and the event Id textbox is filled with the
* detected event Id. The ID pattern is defined in {@link eventIdPattern}.
*/
private void updateUrlFromEventId(String eventIdTextbox) {
if (eventIdTextbox.matches(".*" + eventIdPattern + ".*")) {
final String inferredEventId = eventIdTextbox.replaceFirst(".*(" + eventIdPattern + ").*", "$1");
jsonUrlBox.setValue(
manage2sailBaseAPIUrl + inferredEventId + manage2sailAPIaccessToken + manage2sailUrlAppendix);
eventIdBox.setValue(inferredEventId);
}
}
/**
* Similar to {@link #updateUrlFromEventId} this function tries to extract a M2S event Id by looking at the given
* url in the Json Url Textbox. The value of {@link eventIdBox} is then set to the event ID inferred from the Json Url.
*/
private void updateEventIdFromUrl(String jsonUrlTextBox) {
if (jsonUrlTextBox.matches("http://manage2sail.com/.*" + eventIdPattern + ".*")) {
final String inferredEventId = jsonUrlTextBox.replaceFirst(".*(" + eventIdPattern + ").*", "$1");
eventIdBox.setValue(inferredEventId);
}
}
private ListHandler<SwissTimingRaceRecordDTO> getRaceTableColumnSortHandler(List<SwissTimingRaceRecordDTO> raceRecords,
Column<SwissTimingRaceRecordDTO, ?> regattaNameColumn, Column<SwissTimingRaceRecordDTO, ?> seriesNameColumn,
Column<SwissTimingRaceRecordDTO, ?> nameColumn, Column<SwissTimingRaceRecordDTO, ?> trackingStartColumn,
@@ -1,17 +1,32 @@
package com.sap.sailing.gwt.ui.client;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.sap.sse.gwt.client.EntryPointHelper;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sse.gwt.client.ServiceRoutingProvider;
import com.sap.sse.security.ui.client.AbstractSecureEntryPoint;
public abstract class AbstractSailingEntryPoint extends AbstractSecureEntryPoint<StringMessages> {
protected final SailingServiceAsync sailingService = GWT.create(SailingService.class);
private SailingServiceAsync sailingService;
@Override
protected void doOnModuleLoad() {
super.doOnModuleLoad();
EntryPointHelper.registerASyncService((ServiceDefTarget) sailingService, RemoteServiceMappingConstants.sailingServiceRemotePath);
}
/**
* Lazily initialize sailing service. Concrete entry point subclasses may influence sailing service creation by
* implementing a given routing information providing interface {@link ProvidesLeaderboardRouting}. The routing
* information provided via {@link ProvidesLeaderboardRouting#getLeaderboardName()} needs to be available when this
* method is called for the first time. Repetitive calls will not cause a new leaderboard name to take effect.
*/
protected SailingServiceAsync getSailingService() {
if (sailingService == null) {
if (this instanceof ServiceRoutingProvider) {
sailingService = SailingServiceHelper.createSailingServiceInstance((ServiceRoutingProvider)this);
} else {
sailingService = SailingServiceHelper.createSailingServiceInstance();
}
}
return sailingService;
}
@Override
@@ -1,5 +1,6 @@
package com.sap.sailing.gwt.ui.client;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sse.gwt.client.mvp.ClientFactory;
import com.sap.sse.gwt.client.mvp.ErrorView;
import com.sap.sse.security.ui.client.WithSecurity;
@@ -11,9 +12,12 @@ import com.sap.sse.security.ui.client.WithSecurity;
*
*/
public interface SailingClientFactory extends ClientFactory, WithSecurity {
SailingServiceAsync getSailingService();
SailingServiceAsync getSailingService(ProvidesLeaderboardRouting routingProvider);
MediaServiceAsync getMediaService();
ErrorView createErrorView(String errorMessage, Throwable errorReason);
}
@@ -54,7 +54,7 @@ import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.common.tracking.impl.PreciseCompactGPSFixMovingImpl.PreciseCompactPosition;
import com.sap.sailing.domain.common.windfinder.SpotDTO;
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
import com.sap.sailing.domain.racelog.tracking.SensorFixStore;
import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapter;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.expeditionconnector.ExpeditionDeviceConfiguration;
@@ -539,7 +539,7 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
RaceCourseDTO getLastCourseDefinitionInRaceLog(String leaderboardName, String raceColumnName, String fleetName) throws NotFoundException;
/**
* Adds a fix to the {@link GPSFixStore}, and creates a mapping with a virtual device for exactly the current
* Adds a fix to the {@link SensorFixStore}, and creates a mapping with a virtual device for exactly the current
* timepoint.
*
* @param timePoint
@@ -756,7 +756,7 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
List<String> getRaceDisplayNamesFromLeaderboard(String leaderboardName, List<String> raceColumnNames) throws NotFoundException;
Iterable<DetailType> getAvailableDetailTypesForLeaderboard(String leaderboardName);
Iterable<DetailType> getAvailableDetailTypesForLeaderboard(String leaderboardName, RegattaAndRaceIdentifier raceOrNull);
SpotDTO getWindFinderSpot(String spotId) throws Exception;
@@ -778,5 +778,8 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
*/
SliceRacePreperationDTO prepareForSlicingOfRace(RegattaAndRaceIdentifier raceIdentifier);
Boolean checkIfRaceIsTracked(RegattaAndRaceIdentifier race);
/**
* Checks if the given race is currently in state tracking or loading.
*/
Boolean checkIfRaceIsTracking(RegattaAndRaceIdentifier race);
}
@@ -965,7 +965,7 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan
void getRaceDisplayNamesFromLeaderboard(final String leaderboardName, List<String> raceColumnNames, AsyncCallback<List<String>> callback);
void getAvailableDetailTypesForLeaderboard(String leaderboardName,
void getAvailableDetailTypesForLeaderboard(String leaderboardName, RegattaAndRaceIdentifier raceOrNull,
AsyncCallback<Iterable<DetailType>> asyncCallback);
void canSliceRace(RegattaAndRaceIdentifier raceIdentifier, AsyncCallback<Boolean> callback);
@@ -985,5 +985,8 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan
*/
void getWindFinderSpot(String spotId, AsyncCallback<SpotDTO> callback);
void checkIfRaceIsTracked(RegattaAndRaceIdentifier raceIdentifier, AsyncCallback<Boolean> asyncCallback);
/**
* @see SailingService#checkIfRaceIsTracking(RegattaAndRaceIdentifier)
*/
void checkIfRaceIsTracking(RegattaAndRaceIdentifier raceIdentifier, AsyncCallback<Boolean> asyncCallback);
}
@@ -0,0 +1,60 @@
package com.sap.sailing.gwt.ui.client;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.sap.sse.gwt.client.ServiceRoutingProvider;
/**
* Set of convenience factory methods that create a {@link SailingServiceAsync} instance.
*/
public abstract class SailingServiceHelper {
private final static String moduleBaseURL = GWT.getModuleBaseURL();
private SailingServiceHelper() {
}
/**
* Creates a new {@link SailingServiceAsync} instance, should be used when code resides in the same bundle as the sailing service code.
*/
public static SailingServiceAsync createSailingServiceInstance() {
return createSailingServiceInstance(true, null);
}
/**
* Creates a new {@link SailingServiceAsync} instance.
*
* @param sameBundle {@code false} if using {@link SailingService} from a different OSGi bundle (e.g. dashboards), {@code true} otherwise
*/
public static SailingServiceAsync createSailingServiceInstance(boolean sameBundle) {
return createSailingServiceInstance(sameBundle, null);
}
/**
* Creates a new {@link SailingServiceAsync} instance that uses a routing provider, for code in same bundle.
*/
public static SailingServiceAsync createSailingServiceInstance(ServiceRoutingProvider routingProvider) {
return createSailingServiceInstance(true, routingProvider);
}
/**
* Crates a new {@link SailingServiceAsync} instance.
*
* @param sameBundle {@code false} if using {@link SailingService} from a different OSGi bundle (e.g. dashboards), {@code true} otherwise
*/
public static SailingServiceAsync createSailingServiceInstance(boolean sameBundle, ServiceRoutingProvider routingProvider) {
SailingServiceAsync service = GWT.create(SailingService.class);
ServiceDefTarget serviceToRegister = (ServiceDefTarget) service;
StringBuilder baseURL = new StringBuilder();
baseURL.append(moduleBaseURL.substring(0, moduleBaseURL.lastIndexOf('/', moduleBaseURL.length() - 2) + 1));
if (!sameBundle) {
baseURL.append(RemoteServiceMappingConstants.WEB_CONTEXT_PATH).append("/");
}
baseURL.append(RemoteServiceMappingConstants.sailingServiceRemotePath);
if (routingProvider != null) {
baseURL.append(routingProvider.routingSuffixPath());
}
serviceToRegister.setServiceEntryPoint(baseURL.toString());
return service;
}
}
@@ -153,7 +153,6 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
String legDetailsToShow();
String columnMoveUp();
String columnMoveDown();
String port();
String raceStartTimeColumn();
String showOnlySelectedCompetitors();
String showSelectedCompetitorsInfo();
@@ -2076,4 +2075,11 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
String multiUrlChangeNewURL();
String multiUrlNoPrefixWarning();
String multiUrlChangeExplain();
String lastEvent(String locationOrVenue);
String teaserOverallLinkToolTip();
String gender();
String manage2SailEventIdBox();
String manage2SailEventURLBox();
String manage2SailEventIdBoxTooltip();
String manage2SailPort();
}
@@ -153,7 +153,6 @@ overallDetailsToShow=Overall Details
legDetailsToShow=Leg Details
columnMoveUp=Up
columnMoveDown=Down
port=Port
raceStartTimeColumn=Race Started
showOnlySelectedCompetitors=Show only selected competitors
showSelectedCompetitorsInfo=Show info box for selected competitors
@@ -1870,7 +1869,7 @@ anniversaryMajorCountdownTeaser[one]=Countdown! Only {0,number,#,###} race left
anniversaryMajorCountdownDescription=We are celebrating our {0,number,#,###}th race on www.sapsailing.com! Which race will break the mark? The organizer of this anniversary race will receive a total sum of 10,000 Euro for charity purposes. The winner will be announced on this website. Stay tuned and count with us.
anniversaryRepdigitCountdownTeaser=Countdown! Only {0,number,#,###} races left until the {1,number,#,###}th race.
anniversaryRepdigitCountdownTeaser[one]=Countdown! Only {0,number,#,###} race left until the {1,number,#,###}th race.
anniversaryRepdigitCountdownDescription=We are celebrating our lucky number races! Who will make the {0,number, #,###}th race on www.sapsailing.com? The participants of this race will get a free top-class summer festival from SAP. The winners will be announced on this website. Stay tuned and count with us.
anniversaryRepdigitCountdownDescription=We are celebrating our lucky number races! Who will make the {0,number, #,###}th race on www.sapsailing.com? The organizers will get a free barbecue with drinks. The winners will be announced on this website. Stay tuned and count with us.
anniversaryAnnouncementTeaser=Mission accomplished! {0,number,#,###} races with SAP Sailing Analytics!
anniversaryAnnouncementDescription= 3,2,1... We congratulate the participants of the race {0}. You did it! We thank you for your trust in SAP Sailing Analytics and hopefully continue sailing some more 10,000 races with you!
anniversaryRaceLinkText=Show anniversary race
@@ -2069,4 +2068,11 @@ multiUrlChangeCannotSave=An error occured while saving
multiUrlChangeSave=Save url changes
multiUrlChangeNewURL=new url
multiUrlNoPrefixWarning=No common prefix was found, this usually means that not all selected videos are hosted at the same location currently. Proceed at own risk!
multiUrlChangeExplain=This dialog will bulk replace common parts at the start of mediatrack urls. Make sure all urls start with the same prefix! Also please take a look at the new url column, and test the resulting urls before pressing save!
multiUrlChangeExplain=This dialog will bulk replace common parts at the start of mediatrack urls. Make sure all urls start with the same prefix! Also please take a look at the new url column, and test the resulting urls before pressing save!
lastEvent=Last Event: {0}
teaserOverallLinkToolTip=To see the overall series, click the yellow corner
gender=Gender
manage2SailEventIdBox=Manage2Sail Event ID
manage2SailEventURLBox=Manage2Sail EventURL (json)
manage2SailEventIdBoxTooltip=Event ID or a URL that contains the event ID from Manage2Sail
manage2SailPort=Port
@@ -155,7 +155,6 @@ overallDetailsToShow=Regatta-Details
legDetailsToShow=Schenkeldetails
columnMoveUp=Hoch
columnMoveDown=Runter
port=Backbord
raceStartTimeColumn=Rennstart
showOnlySelectedCompetitors=Nur ausgewählte Teilnehmer anzeigen
showSelectedCompetitorsInfo=Infobox für ausgewählte Teilnehmer anzeigen
@@ -1876,7 +1875,7 @@ anniversaryMajorCountdownTeaser[one]=Countdown! Noch {0,number,#,###} Rennen bis
anniversaryMajorCountdownDescription=Wir zelebrieren unser {0,number,#,###}. Rennen auf www.sapsailing.com! Welches Rennen schafft es die Marke zu durchbrechen? Der Veranstalter des Jubiläumsrennens erhält insgesamt 10.000 Euro für Wohltätigkeitszwecke. Der Gewinner wird auf der Website bekannt gegeben. Stay tuned.
anniversaryRepdigitCountdownTeaser=Countdown! Noch {0,number,#,###} Rennen bis zum {1,number,#,###}. Rennen.
anniversaryRepdigitCountdownTeaser[one]=Countdown! Noch {0,number,#,###} Rennen bis zum {1,number,#,###}. Rennen.
anniversaryRepdigitCountdownDescription=Wir zelebrieren unsere Schnapszahlenrennen! Wer schafft es das {0,number,#,###}. Rennen zu machen? Dem Gewinner schenkt SAP ein Sommerfest der Extraklasse! Der Gewinner wird auf der Website bekannt gegeben. Stay tuned.
anniversaryRepdigitCountdownDescription=Wir zelebrieren unsere Schnapszahlenrennen! Wer schafft es, das {0,number,#,###}. Rennen zu machen? Den Veranstaltern schenkt SAP ein kostenloses Barbecue mit Getränken. Der Gewinner wird auf der Website bekannt gegeben. Stay tuned.
anniversaryAnnouncementTeaser=Mission erfüllt! {0,number,#,###} Rennen mit SAP Sailing Analytics!
anniversaryAnnouncementDescription=3,2,1... Wir gratulieren den Teilnehmern des Rennens {0}. Ihr habt es geschafft die Marke zu durchbrechen. Wir danken euch für euer Vertrauen in SAP Sailing Analytics und hoffen, dass wir noch viele weitere Rennen mit euch machen werden!
anniversaryRaceLinkText=Jubiläumsrennen anzeigen
@@ -2065,4 +2064,11 @@ multiUrlChangeCannotSave=Es ist ein Fehler beim Speichern aufgetreten
multiUrlChangeSave=Änderungen der URLs speichern
multiUrlChangeNewURL=Neue Url
multiUrlNoPrefixWarning=Es wurde kein gemeinsamer Präfix gefunden, dies deutet darauf hin, dass nicht alle ausgewählten Videos vom gleichen Host kommen. Auf eigene Gefahr fortsetzen!
multiUrlChangeExplain=Dieser Dialog ermöglicht es, mehrere URL-Anfänge gleichzeitig auszutauschen. Hierzu müssen diese den gleichen Präfix besitzen. Bitte unbedingt die Spalte mit den neuen URLs beachten und diese testen bevor gespeichert wird!
multiUrlChangeExplain=Dieser Dialog ermöglicht es, mehrere URL-Anfänge gleichzeitig auszutauschen. Hierzu müssen diese den gleichen Präfix besitzen. Bitte unbedingt die Spalte mit den neuen URLs beachten und diese testen bevor gespeichert wird!
lastEvent=Letztes Event: {0}
teaserOverallLinkToolTip=Um die Serien-Übersicht zu sehen, in die gelbe Ecke klicken
gender=Geschlecht
manage2SailEventId=Manage2Sail Event ID
manage2SailEventURL=Manage2Sail Event URL (json)
manage2SailEventIdBoxTooltip=Event ID von Manage 2 Sail oder URL die die Event ID beinhaltet
manage2SailPort=Port
@@ -158,7 +158,6 @@ overallDetailsToShow=Detalles generales
legDetailsToShow=Detalles de tramo
columnMoveUp=Arriba
columnMoveDown=Abajo
port=Babor
raceStartTimeColumn=Carrera iniciada
showOnlySelectedCompetitors=Mostrar solo competidores seleccionados
showSelectedCompetitorsInfo=Mostrar cuadro de información para competidores seleccionados
@@ -158,7 +158,6 @@ overallDetailsToShow=Détails généraux
legDetailsToShow=Détails de la portion de parcours
columnMoveUp=Dans le lit
columnMoveDown=Arrière
port=À bâbord
raceStartTimeColumn=Course lancée
showOnlySelectedCompetitors=Afficher uniquement concurrents sélectionnés
showSelectedCompetitorsInfo=Afficher carré d''infos pour concurrents sélectionnés
@@ -158,7 +158,6 @@ overallDetailsToShow=全体詳細
legDetailsToShow=レグ詳細
columnMoveUp=上
columnMoveDown=下
port=ポート
raceStartTimeColumn=レーススタート済
showOnlySelectedCompetitors=選択した競技者のみ表示
showSelectedCompetitorsInfo=選択した競技者の情報ボックスを表示
@@ -158,7 +158,6 @@ overallDetailsToShow=Detalhes gerais
legDetailsToShow=Detalhes da perna
columnMoveUp=Para cima
columnMoveDown=Para baixo
port=Bombordo
raceStartTimeColumn=Corrida iniciada
showOnlySelectedCompetitors=Visualizar somente os competidores selecionados
showSelectedCompetitorsInfo=Visualizar caixa de informações para competidores selecionados
@@ -158,7 +158,6 @@ overallDetailsToShow=Общие подробности
legDetailsToShow=Подробности
columnMoveUp=Вверх
columnMoveDown=Вниз
port=Порт
raceStartTimeColumn=Гонка начата
showOnlySelectedCompetitors=Показать только выбранных участников
showSelectedCompetitorsInfo=Показать окно сведений для выбранных участников
@@ -158,7 +158,6 @@ overallDetailsToShow=总体详情
legDetailsToShow=航段详情
columnMoveUp=向上
columnMoveDown=向下
port=端口
raceStartTimeColumn=比赛轮次开始时间
showOnlySelectedCompetitors=仅显示选择的参赛队
showSelectedCompetitorsInfo=显示所选参赛队的信息框
@@ -13,6 +13,8 @@ import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.media.client.Audio;
import com.google.gwt.media.client.MediaBase;
import com.google.gwt.typedarrays.shared.Int8Array;
@@ -40,6 +42,8 @@ import com.sap.sse.common.impl.MillisecondsDurationImpl;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.media.MimeType;
import com.sap.sse.gwt.client.controls.busyindicator.SimpleBusyIndicator;
import com.sap.sse.gwt.client.controls.datetime.DateAndTimeInput;
import com.sap.sse.gwt.client.controls.datetime.DateTimeInput.Accuracy;
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
public class NewMediaDialog extends DataEntryDialog<MediaTrack> {
@@ -63,7 +67,7 @@ public class NewMediaDialog extends DataEntryDialog<MediaTrack> {
private TextBox titleBox;
protected TextBox startTimeBox;
protected DateAndTimeInput startTimeBox;
private SimplePanel infoLabel; // showing either mime type or youtube id
@@ -83,6 +87,7 @@ public class NewMediaDialog extends DataEntryDialog<MediaTrack> {
private Button defaultTimeButton;
private SimpleBusyIndicator busyIndicator;
boolean manuallyEditedStartTime = false;
public NewMediaDialog(MediaServiceAsync mediaService, TimePoint defaultStartTime, StringMessages stringMessages,
RegattaAndRaceIdentifier raceIdentifier, DialogCallback<MediaTrack> dialogCallback) {
@@ -98,39 +103,16 @@ public class NewMediaDialog extends DataEntryDialog<MediaTrack> {
@Override
protected MediaTrack getResult() {
mediaTrack.title = titleBox.getValue();
updateStartTimeFromUi();
updateDurationFromUi();
connectMediaWithRace();
return mediaTrack;
}
private void updateDurationFromUi() {
String duration = durationBox.getValue();
if (duration != null && !duration.trim().isEmpty()) {
mediaTrack.duration = TimeFormatUtil.hrsMinSecToMilliSeconds(duration);
} else {
mediaTrack.duration = null;
}
}
protected void connectMediaWithRace() {
Set<RegattaAndRaceIdentifier> assignedRaces = new HashSet<RegattaAndRaceIdentifier>();
assignedRaces.add(this.raceIdentifier);
mediaTrack.assignedRaces = assignedRaces;
}
protected void updateStartTimeFromUi() {
String startTimeText = startTimeBox.getValue();
if (startTimeText != null && !startTimeText.equals("")) {
try {
Date startTime = TimeFormatUtil.DATETIME_FORMAT.parse(startTimeText);
mediaTrack.startTime = new MillisecondsTimePoint(startTime);
} catch (IllegalArgumentException ex) {
// TODO: highlight format error in UI
}
}
}
private void loadMediaDuration() {
MediaBase mediaBase = Audio.createIfSupported();
if (mediaBase != null) {
@@ -150,7 +132,9 @@ public class NewMediaDialog extends DataEntryDialog<MediaTrack> {
}-*/;
public void loadedmetadata(MediaElement mediaElement) {
mediaTrack.startTime = this.defaultStartTime;
if (!manuallyEditedStartTime) {
mediaTrack.startTime = this.defaultStartTime;
}
double duration = mediaElement.getDuration();
if (duration > 0) {
mediaTrack.duration = new MillisecondsDurationImpl((long) Math.round(duration * 1000));
@@ -166,7 +150,19 @@ public class NewMediaDialog extends DataEntryDialog<MediaTrack> {
Grid formGrid = new Grid(6, 2);
formGrid.setCellSpacing(3);
formGrid.setWidget(0, 0, new Label(stringMessages.url() + ":"));
urlBox = createUrlBox();
urlBox = createTextBox(null);
urlBox.addChangeHandler(new ChangeHandler() {
@Override
public void onChange(ChangeEvent event) {
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
public void execute() {
manuallyEditedStartTime = false;
updateFromUrl();
}
});
}
});
formGrid.setWidget(0, 1, urlBox);
formGrid.setWidget(1, 0, new Label(stringMessages.name() + ":"));
titleBox = createTextBox(null);
@@ -177,13 +173,23 @@ public class NewMediaDialog extends DataEntryDialog<MediaTrack> {
infoLabel.setWidget(new Label(""));
formGrid.setWidget(2, 1, infoLabel);
formGrid.setWidget(3, 0, new Label(stringMessages.startTime() + ":"));
startTimeBox = createTextBox(null);
startTimeBox = new DateAndTimeInput(Accuracy.MILLISECONDS);
FlowPanel startTimePanel = new FlowPanel();
startTimePanel.add(startTimeBox);
startTimeBox.addValueChangeHandler(new ValueChangeHandler<Date>() {
@Override
public void onValueChange(ValueChangeEvent<Date> event) {
manuallyEditedStartTime = true;
mediaTrack.startTime = new MillisecondsTimePoint(event.getValue());
}
});
defaultTimeButton = new Button(StringMessages.INSTANCE.resetStartTimeToDefault());
defaultTimeButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
manuallyEditedStartTime = true;
mediaTrack.startTime = defaultStartTime;
refreshUI();
}
@@ -192,6 +198,17 @@ public class NewMediaDialog extends DataEntryDialog<MediaTrack> {
formGrid.setWidget(3, 1, startTimePanel);
formGrid.setWidget(4, 0, new Label(stringMessages.duration() + ":"));
durationBox = createTextBox(null);
durationBox.addValueChangeHandler(new ValueChangeHandler<String>() {
@Override
public void onValueChange(ValueChangeEvent<String> event) {
String duration = durationBox.getValue();
if (duration != null && !duration.trim().isEmpty()) {
mediaTrack.duration = TimeFormatUtil.hrsMinSecToMilliSeconds(duration);
} else {
mediaTrack.duration = null;
}
}
});
formGrid.setWidget(4, 1, durationBox);
busyIndicator = new SimpleBusyIndicator();
formGrid.setWidget(5, 0, busyIndicator);
@@ -199,22 +216,6 @@ public class NewMediaDialog extends DataEntryDialog<MediaTrack> {
return mainPanel;
}
private TextBox createUrlBox() {
TextBox result = createTextBox(null);
result.addChangeHandler(new ChangeHandler() {
@Override
public void onChange(ChangeEvent event) {
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
public void execute() {
updateFromUrl();
}
});
}
});
return result;
}
protected void updateFromUrl() {
String url = urlBox.getValue();
String youtubeId = YoutubeApi.getIdByUrl(url);
@@ -315,7 +316,7 @@ public class NewMediaDialog extends DataEntryDialog<MediaTrack> {
refreshUI();
}
private void refreshUI() {
protected void refreshUI() {
titleBox.setValue(mediaTrack.title, DONT_FIRE_EVENTS);
if (mediaTrack.isYoutube()) {
infoLabelLabel.setText(stringMessages.youtubeId() + ":");
@@ -335,10 +336,7 @@ public class NewMediaDialog extends DataEntryDialog<MediaTrack> {
}
}
TimePoint startTime = mediaTrack.startTime != null ? mediaTrack.startTime : defaultStartTime;
String startTimeText = TimeFormatUtil.DATETIME_FORMAT.format(startTime.asDate());
startTimeBox.setText(startTimeText);
updateStartTimeFromUi();
startTimeBox.setValue(startTime == null ? null : startTime.asDate());
if (mediaTrack.duration != null) {
durationBox.setText(TimeFormatUtil.durationToHrsMinSec(mediaTrack.duration));
} else {
@@ -439,7 +437,7 @@ public class NewMediaDialog extends DataEntryDialog<MediaTrack> {
} else {
mediaTrack.duration = result.getDuration();
mediaTrack.mimeType = result.isSpherical() ? MimeType.mp4panorama : MimeType.mp4;
if (result.getRecordStartedTime() != null) {
if (result.getRecordStartedTime() != null && !manuallyEditedStartTime) {
mediaTrack.startTime = new MillisecondsTimePoint(result.getRecordStartedTime());
}
refreshUI();
@@ -1,5 +1,6 @@
package com.sap.sailing.gwt.ui.client.media;
import java.util.Date;
import java.util.Set;
import com.google.gwt.user.client.ui.VerticalPanel;
@@ -13,7 +14,6 @@ import com.sap.sailing.gwt.ui.client.RegattasDisplayer;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.gwt.client.ErrorReporter;
public class NewMediaWithRaceSelectionDialog extends NewMediaDialog {
@@ -41,19 +41,7 @@ public class NewMediaWithRaceSelectionDialog extends NewMediaDialog {
this.regattasDisplayers = regattasDisplayers;
}
protected void updateStartTimeFromUi() {
try {
String startTime = startTimeBox.getValue();
if (startTime != null && !startTime.equals("")) {
mediaTrack.startTime = new MillisecondsTimePoint(TimeFormatUtil.DATETIME_FORMAT.parse(startTime));
regattaRefresher.fillRegattas();
listOfRacesForMedia.setVisible(true);
}
} catch (Exception e) {
listOfRacesForMedia.setVisible(false);
}
}
@Override
protected void connectMediaWithRace() {
mediaTrack.assignedRaces = racesForMediaDialog.getAssignedRaces();
}
@@ -81,6 +69,7 @@ public class NewMediaWithRaceSelectionDialog extends NewMediaDialog {
return listOfRacesForMedia = racesForMediaDialog.getAdditionalWidget();
}
@Override
protected Widget getAdditionalWidget() {
VerticalPanel mainPanel = (VerticalPanel) super.getAdditionalWidget();
mainPanel.add(racesForMedia());
@@ -88,4 +77,17 @@ public class NewMediaWithRaceSelectionDialog extends NewMediaDialog {
return mainPanel;
}
@Override
protected void refreshUI() {
super.refreshUI();
try {
Date value = startTimeBox.getValue();
if (value != null) {
regattaRefresher.fillRegattas();
listOfRacesForMedia.setVisible(true);
}
} catch (Exception e) {
listOfRacesForMedia.setVisible(false);
}
}
}
@@ -114,7 +114,6 @@ public class EditMarkPositionPanel extends AbstractRaceChart<AbstractSettings> i
private LinePlotOptions markSeriesPlotOptions;
private final Label noMarkSelectedLabel;
private MapWidget map;
private boolean visible;
private List<HandlerRegistration> courseMarkClickHandlers;
private Map<MarkDTO, Pair<Date, Date>> marksFromToTimes;
@@ -131,6 +130,7 @@ public class EditMarkPositionPanel extends AbstractRaceChart<AbstractSettings> i
private final MarkPositionService markPositionService;
private final RaceIdentifierToLeaderboardRaceColumnAndFleetMapper raceIdentifierToLeaderboardRaceColumnAndFleetMapper;
protected boolean nonTrackingWarningWasDisplayed;
public EditMarkPositionPanel(Component<?> parent, ComponentContext<?> context, final RaceMap raceMap,
final SingleRaceLeaderboardPanel leaderboardPanel,
@@ -373,20 +373,25 @@ public class EditMarkPositionPanel extends AbstractRaceChart<AbstractSettings> i
overlay.setVisible(false);
if (currentFixPositionChooser == null) {
OverlayClickHandler.this.unregisterAll();
currentFixPositionChooser = new FixPositionChooser(EditMarkPositionPanel.this, stringMessages, map, getIndexOfFixInPolyline(mark, fix), polyline.getPath(), overlay, new Callback<Position, Exception>() {
@Override
public void onFailure(Exception reason) {
overlay.setVisible(true);
OverlayClickHandler.this.registerAll();
resetCurrentFixPositionChooser();
}
@Override
public void onSuccess(Position result) {
editMarkFix(mark, fix, result);
overlay.setVisible(true);
OverlayClickHandler.this.registerAll();
resetCurrentFixPositionChooser();
}
checkIfTracking(() -> {
currentFixPositionChooser = new FixPositionChooser(EditMarkPositionPanel.this,
stringMessages, map, getIndexOfFixInPolyline(mark, fix), polyline.getPath(),
overlay, new Callback<Position, Exception>() {
@Override
public void onFailure(Exception reason) {
overlay.setVisible(true);
OverlayClickHandler.this.registerAll();
resetCurrentFixPositionChooser();
}
@Override
public void onSuccess(Position result) {
editMarkFix(mark, fix, result);
overlay.setVisible(true);
OverlayClickHandler.this.registerAll();
resetCurrentFixPositionChooser();
}
});
});
}
popup.hide();
@@ -407,26 +412,28 @@ public class EditMarkPositionPanel extends AbstractRaceChart<AbstractSettings> i
}
private void addDeleteItemAndShowPopup(boolean enableDelete) {
final MenuItem delete;
Runnable r = () -> {
final MenuItem delete = new MenuItem(stringMessages.deleteFix(), new ScheduledCommand() {
@Override
public void execute() {
if (enableDelete) {
removeMarkFix(mark, fix);
popup.hide();
}
}
});
if (!enableDelete) {
delete.setEnabled(false);
delete.setTitle(stringMessages.theDeletionOfThisFix());
}
menu.addItem(delete);
popup.setWidget(menu);
};
if (enableDelete) {
delete = new MenuItem(stringMessages.deleteFix(), new ScheduledCommand() {
@Override
public void execute() {
removeMarkFix(mark, fix);
popup.hide();
}
});
checkIfTracking(r);
} else {
delete = new MenuItem(stringMessages.deleteFix(), new ScheduledCommand() {
@Override
public void execute() {
}
});
delete.setEnabled(false);
delete.setTitle(stringMessages.theDeletionOfThisFix());
r.run();
}
menu.addItem(delete);
popup.setWidget(menu);
}
});
}
@@ -704,20 +711,8 @@ public class EditMarkPositionPanel extends AbstractRaceChart<AbstractSettings> i
}
public void setVisible(boolean visible) {
this.visible = visible;
if(visible && !isVisible()){
sailingService.checkIfRaceIsTracked(selectedRaceIdentifier, new AsyncCallback<Boolean>() {
@Override
public void onFailure(Throwable caught) {
Window.alert(stringMessages.serverError());
}
@Override
public void onSuccess(Boolean result) {
if (Boolean.FALSE.equals(result)) {
Window.alert(stringMessages.positionEditOnNonTrackingRace());
}
}
});
if (visible && !isVisible()) {
checkIfTracking(() -> {});
}
if (map == null) {
map = raceMap.getMap();
@@ -725,7 +720,7 @@ public class EditMarkPositionPanel extends AbstractRaceChart<AbstractSettings> i
setMap(map);
}
}
if (this.visible) {
if (visible) {
if (sideBySideComponentViewer != null) {
sideBySideComponentViewer.setLeftComponent(marksPanel);
sideBySideComponentViewer.setLeftComponentToggleButtonVisible(false);
@@ -756,7 +751,30 @@ public class EditMarkPositionPanel extends AbstractRaceChart<AbstractSettings> i
raceMap.unregisterAllCourseMarkInfoWindowClickHandlers();
raceMap.registerAllCourseMarkInfoWindowClickHandlers();
}
super.setVisible(this.visible);
super.setVisible(visible);
}
private void checkIfTracking(Runnable continuation) {
if (nonTrackingWarningWasDisplayed) {
continuation.run();
} else {
sailingService.checkIfRaceIsTracking(selectedRaceIdentifier, new AsyncCallback<Boolean>() {
@Override
public void onFailure(Throwable caught) {
Window.alert(stringMessages.serverError());
continuation.run();
}
@Override
public void onSuccess(Boolean result) {
if (Boolean.FALSE.equals(result)) {
Window.alert(stringMessages.positionEditOnNonTrackingRace());
nonTrackingWarningWasDisplayed = true;
}
continuation.run();
}
});
}
}
@Override
@@ -943,17 +961,21 @@ public class EditMarkPositionPanel extends AbstractRaceChart<AbstractSettings> i
* Is thrown when another fix position chooser is still open
*/
public void createFixPositionChooserToAddFixToMark(MarkDTO mark, Callback<Position, Exception> callback) {
if (currentFixPositionChooser != null) {
if (currentFixPositionChooser != null) {
return;
}
int index = 0;
for (GPSFixDTO fix : marks.get(mark).keySet()) {
if (fix.timepoint.after(timer.getTime()))
break;
index++;
}
Polyline polyline = polylines.get(mark);
currentFixPositionChooser = new FixPositionChooser(this, stringMessages, map, index, polyline != null ? polyline.getPath() : null, map.getCenter(), raceMap.getCoordinateSystem(), callback);
checkIfTracking(() -> {
int index = 0;
for (GPSFixDTO fix : marks.get(mark).keySet()) {
if (fix.timepoint.after(timer.getTime()))
break;
index++;
}
Polyline polyline = polylines.get(mark);
currentFixPositionChooser = new FixPositionChooser(EditMarkPositionPanel.this, stringMessages, map, index,
polyline != null ? polyline.getPath() : null, map.getCenter(), raceMap.getCoordinateSystem(),
callback);
});
}
public void resetCurrentFixPositionChooser() {
@@ -50,12 +50,6 @@ public interface MarkPositionService {
void getMarksInTrackedRace(LeaderboardNameRaceColumnNameAndFleetName raceIdentifier, AsyncCallback<Iterable<MarkDTO>> callback);
// Jonas Dann: I had no great idea for handling of massive amount of fixes. An exception is no real option. I
// think the fixes have to be thinned out somehow and maybe shown in more detail when zoomed in. The aggregation of
// fixes is in my eyes no option, because then you have to define behaviour when moving them.
// I had no remaining time to incorporate the thinned out variable in my code.
void getMarkTracks(LeaderboardNameRaceColumnNameAndFleetName raceIdentifier, AsyncCallback<MarkTracksDTO> callback);
void getMarkTrack(LeaderboardNameRaceColumnNameAndFleetName raceIdentifier, String markIdAsString, AsyncCallback<MarkTrackDTO> callback);
/**
@@ -20,11 +20,6 @@ public class MarkPositionServiceForSailingService implements MarkPositionService
sailingService.getMarksInTrackedRace(raceIdentifier.getLeaderboardName(), raceIdentifier.getRaceColumnName(), raceIdentifier.getFleetName(), callback);
}
@Override
public void getMarkTracks(LeaderboardNameRaceColumnNameAndFleetName raceIdentifier, AsyncCallback<MarkTracksDTO> callback) {
sailingService.getMarkTracks(raceIdentifier.getLeaderboardName(), raceIdentifier.getRaceColumnName(), raceIdentifier.getFleetName(), callback);
}
@Override
public void getMarkTrack(LeaderboardNameRaceColumnNameAndFleetName raceIdentifier, String markIdAsString,
AsyncCallback<MarkTrackDTO> callback) {
@@ -6,6 +6,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.moxieapps.gwt.highcharts.client.Axis;
@@ -226,65 +227,46 @@ public class WindChart extends AbstractRaceChart<WindChartSettings> implements R
}
private void updateVisibleSeries() {
List<Series> currentSeries = Arrays.asList(chart.getSeries());
Set<Series> visibleSeries = new HashSet<Series>(currentSeries);
final Set<Series> visibleSeries = new HashSet<Series>(Arrays.asList(chart.getSeries()));
if (preselectFilter != null) {
forceSeriesSelection(visibleSeries, windSourceDirectionSeries);
forceSeriesSelection(visibleSeries, windSourceSpeedSeries);
} else {
if (settings.isShowWindDirectionsSeries()) {
for (Map.Entry<WindSource, Series> e : windSourceDirectionSeries.entrySet()) {
Series series = e.getValue();
if (settings.getWindDirectionSourcesToDisplay().contains(e.getKey().getType())) {
if (!visibleSeries.contains(series)) {
chart.addSeries(series, false, false);
}
series.select(true); // ensures that the checkbox will be ticked
series.setVisible(true); //and that it is actually being rendered
} else {
if (visibleSeries.contains(series)) {
chart.removeSeries(series, false);
}
}
}
} else {
for (Map.Entry<WindSource, Series> e : windSourceDirectionSeries.entrySet()) {
Series series = e.getValue();
if (visibleSeries.contains(series)) {
chart.removeSeries(series, false);
}
}
}
if (settings.isShowWindSpeedSeries()) {
for (Map.Entry<WindSource, Series> e : windSourceSpeedSeries.entrySet()) {
Series series = e.getValue();
if (settings.getWindSpeedSourcesToDisplay().contains(e.getKey().getType())) {
if (!visibleSeries.contains(series)) {
chart.addSeries(series, false, false);
}
series.select(true); // ensures that the checkbox will be ticked
series.setVisible(true); //and that it is actually being rendered
} else {
if (visibleSeries.contains(series)) {
chart.removeSeries(series, false);
}
}
}
} else {
for (Map.Entry<WindSource, Series> e : windSourceSpeedSeries.entrySet()) {
Series series = e.getValue();
if (visibleSeries.contains(series)) {
chart.removeSeries(series, false);
}
}
}
final boolean showDirectionSeries = settings.isShowWindDirectionsSeries();
final Set<WindSourceType> directionSourceTypesToDisplay = settings.getWindDirectionSourcesToDisplay();
updateSeries(visibleSeries, windSourceDirectionSeries, showDirectionSeries, directionSourceTypesToDisplay);
final boolean showSpeedSeries = settings.isShowWindSpeedSeries();
final Set<WindSourceType> speedSourceTypesToDisplay = settings.getWindSpeedSourcesToDisplay();
updateSeries(visibleSeries, windSourceSpeedSeries, showSpeedSeries, speedSourceTypesToDisplay);
}
onResize();
}
private void updateSeries(final Set<Series> visibleSeries, final Map<WindSource, Series> windSourceToSeriesMap,
final boolean showSeries, final Set<WindSourceType> windSourceTypesToDisplay) {
if (showSeries) {
for (Entry<WindSource, Series> entry : windSourceToSeriesMap.entrySet()) {
final Series series = entry.getValue();
if (windSourceTypesToDisplay.contains(entry.getKey().getType())) {
if (!visibleSeries.contains(series)) {
chart.addSeries(series, false, false);
}
} else if (visibleSeries.contains(series)) {
chart.removeSeries(series, false);
}
}
} else {
for (Entry<WindSource, Series> entry : windSourceToSeriesMap.entrySet()) {
final Series series = entry.getValue();
if (visibleSeries.contains(series)) {
chart.removeSeries(series, false);
}
}
}
}
private boolean forceSeriesSelection(Set<Series> visibleSeries, Map<WindSource, Series> toProcess) {
boolean wasInResult = false;
for (Map.Entry<WindSource, Series> e : toProcess.entrySet()) {
@@ -44,7 +44,8 @@ public class BoatClassVectorGraphicsResolver {
BoatClassMasterdata.A_CAT, BoatClassMasterdata.TORNADO, BoatClassMasterdata.FLYING_PHANTOM);
BoatClassVectorGraphics keelBoatWithGennaker = new KeelBoatWithGennakerVectorGraphics(BoatClassMasterdata.J70,
BoatClassMasterdata.B_ONE, BoatClassMasterdata.J80, BoatClassMasterdata.LASER_SB3, BoatClassMasterdata.LONGTZE,
BoatClassMasterdata.RS_FEVA, BoatClassMasterdata.RS_TERA, BoatClassMasterdata.RS100, BoatClassMasterdata.TP52);
BoatClassMasterdata.RS_FEVA, BoatClassMasterdata.RS_TERA, BoatClassMasterdata.RS100, BoatClassMasterdata.TP52,
BoatClassMasterdata.CLUB_SWAN_50);
BoatClassVectorGraphics dinghyWithSpinnaker = new DinghyWithSpinnakerVectorGraphics(BoatClassMasterdata._420,
BoatClassMasterdata._470, BoatClassMasterdata._5O5, BoatClassMasterdata.CADET, BoatClassMasterdata.FLYING_DUTCHMAN,
BoatClassMasterdata.FOLKBOAT, BoatClassMasterdata.DYAS, BoatClassMasterdata.DRAGON_INT,
@@ -53,7 +54,7 @@ public class BoatClassVectorGraphicsResolver {
BoatClassMasterdata.TOM_28_MAX, BoatClassMasterdata.DELPHIA_24,
BoatClassMasterdata.RS200, BoatClassMasterdata.RS400, BoatClassMasterdata.RS500, BoatClassMasterdata.RS800,
BoatClassMasterdata.STREAMLINE, BoatClassMasterdata.SWAN_45, BoatClassMasterdata.TEENY, BoatClassMasterdata.X_99,
BoatClassMasterdata.TRIAS, BoatClassMasterdata.VENT_D_OUEST);
BoatClassMasterdata.TRIAS, BoatClassMasterdata.VENT_D_OUEST, BoatClassMasterdata.FLYING_JUNIOR, BoatClassMasterdata.VAURIEN);
BoatClassVectorGraphics circle = new CircleVectorGraphics(BoatClassMasterdata.RUNNING);
defaultBoatVectorGraphics = dinghyWithSpinnaker; // TODO see bug 2571; this should be a slup-rigged icon working for 470, 505, J/70 etc.
@@ -24,7 +24,7 @@ public class ManeuverTableLifecycle implements ComponentLifecycle<ManeuverTableS
@Override
public String getLocalizedShortName() {
return stringMessages.wind();
return stringMessages.maneuverTable();
}
@Override
@@ -13,11 +13,10 @@ public class ManeuverTableSettings extends AbstractGenericSerializableSettings {
private EnumSetSetting<ManeuverType> selectedManeuverTypes;
private Iterable<ManeuverType> defaultTypes = Arrays.asList(ManeuverType.values());
@Override
protected void addChildSettings() {
selectedManeuverTypes = new EnumSetSetting<>("selectedManeuverTypes", this, defaultTypes,
selectedManeuverTypes = new EnumSetSetting<>("selectedManeuverTypes", this,
Arrays.asList(ManeuverType.TACK, ManeuverType.JIBE, ManeuverType.PENALTY_CIRCLE),
ManeuverType::valueOf);
}
@@ -25,9 +24,6 @@ public class ManeuverTableSettings extends AbstractGenericSerializableSettings {
* The default settings
*/
public ManeuverTableSettings() {
selectedManeuverTypes.addValue(ManeuverType.TACK);
selectedManeuverTypes.addValue(ManeuverType.JIBE);
selectedManeuverTypes.addValue(ManeuverType.PENALTY_CIRCLE);
}
public ManeuverTableSettings(Set<ManeuverType> selectedManeuverTypes) {
Loaded 100 of 198 files, more files were not shown because too many files have changed in this diff. Show more