Merge branch 'master' into ubilabs--rcapp--bug-3119

Conflicts:
	mobile/com.sap.sailing.racecommittee.app/res/values-de/strings.xml
	mobile/com.sap.sailing.racecommittee.app/res/values/strings.xml
	mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/RaceListFragment.java
This commit is contained in:
Axel Uhl committed 2015-07-17 20:43:30 +02:00
commit 57fc41b020
56 files changed
+2502 -1187

No files matched your search

+59
View File
@@ -0,0 +1,59 @@
#!/usr/bin/env bash
# set up some constants
## Manage2Sail
M2SURL="http://manage2sail.com"
M2SEVENTID="???xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx???"
M2SACCESSTOKEN="???xyz???"
M2SSTRING=${M2SURL}"/api/public/links/event/"${M2SEVENTID}"?accesstoken="${M2SACCESSTOKEN}"&mediaType=json"
## Local JSON
LOCALJSON="/tmp/???EVENT???results.json"
LOCALJSON_OLD=$LOCALJSON.old
## Mails (each email in new line)
MAILINGLIST="/home/trac/mailinglists/???EVENT???updatemailinglist"
## Eventname
EVENTNAME="???Eventname Jahr???"
## Misc
DOSENDMAIL=false
### ROUTINE ###
# get current json from manage2sail
wget -O "$LOCALJSON" "$M2SSTRING" >/dev/null 2>&1
if [ -f "$LOCALJSON_OLD" ]; then
# results previously downloaded; now compare
# sort by manage2sail Regattas.Id
LOCALJSON_SORTED="${LOCALJSON}.sorted"
LOCALJSON_OLD_SORTED="${LOCALJSON_OLD}.sorted"
cat "$LOCALJSON" | jq -r '.Regattas|sort_by(.Name)' >"$LOCALJSON_SORTED"
cat "$LOCALJSON_OLD" | jq -r '.Regattas|sort_by(.Name)' >"$LOCALJSON_OLD_SORTED"
# filter only necessary values
LOCALJSON_FORMATTED="${LOCALJSON}.formatted"
LOCALJSON_OLD_FORMATTED="${LOCALJSON_OLD}.formatted"
cat "$LOCALJSON_SORTED" | jq -r '.[]|{Final, LastPublishedRoundName, Published, Name, ClassName, Id}|select(.Published != null)' >"$LOCALJSON_FORMATTED"
cat "$LOCALJSON_OLD_SORTED" | jq -r '.[]|{Final, LastPublishedRoundName, Published, Name, ClassName, Id}|select(.Published != null)' >"$LOCALJSON_OLD_FORMATTED"
# diff sorted+formatted json
diff -q "$LOCALJSON_OLD_FORMATTED" "$LOCALJSON_FORMATTED"
if [ "$?" != "0" ]; then
echo "Found diff between $LOCALJSON_OLD_FORMATTED and $LOCALJSON_FORMATTED
`diff -q "$LOCALJSON_OLD_FORMATTED" "$LOCALJSON_FORMATTED"`
Sending mail."
DOSENDMAIL=true
fi
fi
if [ "$DOSENDMAIL" = "true" ]; then
echo "`date` Sending mail to `cat "$MAILINGLIST"`"
echo "$LOCALJSON has changed. Consider re-importing results for $EVENTNAME. Differences:
------------------
`diff -U 6 "$LOCALJSON_OLD_FORMATTED" "$LOCALJSON_FORMATTED"`
------------------
To unsubscribe, change $MAILINGLIST on `hostname`." | mail -s "SAP result import update: $EVENTNAME" `cat "$MAILINGLIST" | grep -v "^#"`
fi
# move to old
mv "$LOCALJSON" "$LOCALJSON_OLD"
# clean up temporary files
rm -rf "$LOCALJSON_SORTED" "$LOCALJSON_OLD_SORTED" "$LOCALJSON_FORMATTED" "$LOCALJSON_OLD_FORMATTED"
+20
View File
@@ -0,0 +1,20 @@
#!/bin/bash
# groups Apache / httpd log entries into "${referrer}.ips" files, where ${referrer} is the
# referrer URL identifying the "event"; the lines written to the .ips files hold the IP
# address of the requestor, the date (not the time) and the user agent string.
# Sorting for unique entries should give a count similar to what goaccess is using to
# determine "unique visitors."
# A sample line:
# 505Worlds2012.sapsailing.com 66.249.73.53 - - [12/Jan/2014:03:33:11 +0000] "GET /robots.txt HTTP/1.1" 404 238 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
#cat $* | sed -e 's/^\([^ ]*\) \([^ ]*\) \([^ ]*\) \([^ ]*\) \[\([^:]*\):\([^]]*\)\] \"[^\"]*\" [^ ]* [^ ]* \"[^\"]\" \"\([\"]*\)\"\(.*\)$/\1 \2 \5 \7/'
cat $* | sed -e 's/^\([^ ]*\) \([^ ]*\) \([^ ]*\) \([^ ]*\) \[\([^:]*\):\([^]]*\)\] \"[^\"]*\" [^ ]* [^ ]* \"[^\"]*\" \"\([^\"]*\)\"/\1 \2 \5 \7/' | while read referrer hit; do
echo "$hit" >>${referrer}.ips
done
for i in *.ips; do
echo -n "$i "
cat $i | sort -u | wc | awk '{ print $1; }'
done | tee unique-ips-days-useragents-per-event
echo "Done. Wrote results to `pwd`/unique-ips-days-useragents-per-event
Binary file not shown.
@@ -148,7 +148,7 @@ public class StartlineAnalysisCard extends Composite implements HasWidgets, Star
asyncActionsExecutor, null, Collections.singletonList(startAnalysisDTO.regattaAndRaceIdentifier), 5000l /* requestInterval */);
raceMap = new RaceMap(sailingServiceAsync, asyncActionsExecutor, null, timer, competitorSelectionModel,
StringMessages.INSTANCE, false, false, false, startAnalysisDTO.regattaAndRaceIdentifier,
resources.combinedWindPanelStyle());
resources.combinedWindPanelStyle(), /* showHeaderPanel */ true);
raceMap.onRaceSelectionChange(Collections.singletonList(startAnalysisDTO.regattaAndRaceIdentifier));
raceMap.getSettings().setZoomSettings(new RaceMapZoomSettings(zoomTypes, false));
raceMap.getSettings().setHelpLinesSettings(getHelpLineSettings());
@@ -27,9 +27,10 @@ public enum WindSourceType {
TRACK_BASED_ESTIMATION(false, 0.5, /* useSpeed */ false),
/**
* Inferred from the race course layout if the course is known to have its first leg be an upwind leg
* Inferred from the race course layout if the course is known to have its first leg be an upwind leg. This
* source has very low confidence and must be superseded by any other wind source.
*/
COURSE_BASED(false, 0.3, /* useSpeed */ false),
COURSE_BASED(false, 0.01, /* useSpeed */ false),
/**
* Wind estimation combined from all other wind sources, using <code>TrackedRace.getWind(...)</code>, based on
@@ -139,7 +139,6 @@ import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Timed;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.impl.MillisecondsDurationImpl;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.concurrent.LockUtil;
import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
@@ -3669,7 +3668,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
if (polarDataService == null) {
throw new NotEnoughDataHasBeenAddedException("Target time estimation failed. No polar service available.");
}
Duration durationOfAllLegs = new MillisecondsDurationImpl(0);
Duration durationOfAllLegs = Duration.NULL;
for (TrackedLeg leg : trackedLegs.values()) {
Duration durationOfLeg = leg.getEstimatedTimeToComplete(polarDataService, timepoint);
durationOfAllLegs = durationOfAllLegs.plus(durationOfLeg);
@@ -11,6 +11,6 @@
</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/Home.html"/>
<stringAttribute key="url" value="http://127.0.0.1:8888/gwt/AdminConsole.html"/>
<stringAttribute key="urlQueryParams" value=""/>
</launchConfiguration>
@@ -0,0 +1,695 @@
/** Add css rules here for your application. */
/*
body #calendar:after
content: " ";
display: block;
height: 0;
clear: both;
visibility: hidden;
*/
* {
font-family: 'Open Sans', sans-serif;
font-size: 12px;
}
iframe {
display: block;
width: 100%;
height: 100%;
border: none;
overflow-y: auto;
overflow-x: hidden;
}
.clear {
clear: both;
font-size: 1px;
height: 0px;
line-height: 0px;
margin: -1px 0 0;
width: 100%;
}
.cover {
left: -1000px;
overflow: hidden;
position: absolute;
top: -1000px;
}
body {
background: white;
font-family: 'Open Sans', Arial, Verdana, sans-serif;
line-height: 1;
font-size: 14px;
font-weight: 400;
margin: 0;
}
table td, select, button {
font-family: 'Open Sans', Arial, Verdana, sans-serif;
line-height: 1;
font-size: 14px;
}
.contentOuterPanel {
background: #dddcdc;
margin: 0 12px 0 12px;
padding: 12px;
}
/** Example rules used by the template application (remove for your app) */
h1 {
font-size: 2em;
font-family: 'Open Sans', Arial, Verdana, sans-serif;
font-weight: 700;
color: #777777;
margin: 40px 0px 70px;
text-align: center;
}
table {
border-collapse: separate;
}
.CombinedWindPanelParentDiv {
padding-top: 34px;
padding-left: 10px;
}
.TrueNorthIndicatorPanelParentDiv {
padding-top: 10px;
padding-left: 10px;
}
.MapSimulationLegendParentDiv {
padding-bottom: 10px;
padding-right: 10px;
pointer-events: none;
}
.MapSimulationLegend {
pointer-events: all;
}
.RaceMap-HeaderPanel {
height: 60px;
width: 100%;
background-color: #333;
opacity: .5;
}
.leaderboardLabel {
border-bottom: 2px solid #007dc0;
padding: 0 0 6px 0;
font-weight: 700;
}
.refreshAndSettings {
background: #f2f2f2;
border-bottom: 2px solid #fff;
border-top: 2px solid #fff;
height: 30px;
}
.refreshAndSettings table td {
padding: 0 10px 0 0;
}
.refreshAndSettings table table td {
padding: 0 0 0 0;
}
.race-name {
line-height: 1.0;
}
.openColumn {
position: relative;
vertical-align: middle;
}
img.openColumn {
display: block;
margin: 3px auto 3px auto !important;
}
.breadcrumbPanel {
height: 30px;
margin: 0 12px 13px 12px;
}
.mainPanel {
width: 100%;
}
.raceBoardNavigation {
float: left;
margin: 9px 0 0 12px;
font-family: 'Open Sans', Arial, Verdana, sans-serif;
font-weight: 300;
}
.raceBoardControls {
float: right;
margin: 9px 0 0 12px;
font-family: 'Open Sans', Arial, Verdana, sans-serif;
font-weight: 300;
}
.raceBoardNavigation-navigationitem {
color: #dddcdc;
text-transform: uppercase;
font-weight: 500;
margin: 0 12px 0 0;
padding: 0 0 5px 0;
}
.raceBoardNavigation-navigationitem:hover {
border-bottom: 4px solid #f0ab00;
color: #dddcdc;
text-decoration: none;
}
.raceBoardNavigation-navigationitem:active {
border-bottom: 4px solid #f0ab00;
color: #dddcdc;
text-decoration: none;
}
.competitorInfo-Canvas {
pointer-events: none;
}
.gwt-DialogBox {
z-index: 20;
}
.abstractChartPanel-importantMessageOfChart {
font-family: 'Open Sans', Arial, Verdana, sans-serif;
font-weight: 600;
font-size: 20px;
height: 70px;
margin: 0 auto;
padding: 49px 0 0 80px;
width: 300px;
color: #7c7c7c;
background: url(images/important-message.png) left center no-repeat;
}
.breadcrumbPanel-NextArrow {
display: none;
}
.errorLabel {
color: #FF0000;
}
.raceBoardNavigation-settingsButtonPanel {
float: right;
margin: 9px 12px 0 0;
}
.raceBoardNavigation-settingsButton {
background: url(images/settings_white.png),
url(images/btn-cta-orangeleft.png);
background-position: center, center 0;
background-repeat: no-repeat, repeat-x;
width: 27px;
height: 23px;
margin: 0 12px 0 1px;
-webkit-border-radius: 0px 3px 3px 0px;
-moz-border-radius: 0px 3px 3px 0px;
-o-border-radius: 0px 3px 3px 0px;
-ms-border-radius: 0px 3px 3px 0px;
border-radius: 0px 3px 3px 0px;
}
.raceBoardNavigation-settingsButton:hover {
background-image: url(images/settings_white.png),
url(images/btn-cta-orangeleft.png);
background-position: center, center -30px;
background-repeat: no-repeat, repeat-x;
cursor: pointer;
}
.raceBoardNavigation-filterButton:hover {
background-image: url(images/filter_white.png),
url(images/btn-cta-orangeleft.png);
background-position: center, center -30px;
background-repeat: no-repeat, repeat-x;
cursor: pointer;
}
.raceBoardNavigation-innerElement {
background: url("images/btn-cta-orangeleft.png") repeat-x scroll center
0 transparent;
color: #FFFFFF;
cursor: pointer;
font-family: 'Open Sans', Verdana, Arial, sans-serif;
font-weight: 600;
font-size: 14px;
margin: 0 0 0 0;
padding: 2px 7px 2px 3px;
height: 18px;
display: inline-block;
text-decoration: none;
border-radius: 5px 0 0 5px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.25);
border-bottom: 1px solid rgba(0, 0, 0, 0.25);
}
.raceBoardNavigation-innerElement:active {
top: 1px;
position: relative;
}
.raceBoardNavigation-innerElement:hover {
background: url("images/btn-cta-orangeleft.png") repeat-x scroll center
-30px transparent;
cursor: pointer;
}
.raceBoardNavigation-innerElement label {
cursor: pointer;
}
.raceBoardNavigation-standaloneElement {
background: url("images/btn-cta-orangeleft.png") repeat-x scroll center
0 transparent;
color: #FFFFFF;
cursor: pointer;
font-family: 'Open Sans', Verdana, Arial, sans-serif;
font-weight: 600;
font-size: 14px;
margin: 0 0 0 0;
padding: 2px 7px 2px 3px;
height: 23px;
display: inline-block;
text-decoration: none;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.25);
border-bottom: 1px solid rgba(0, 0, 0, 0.25);
border-radius: 5px 5px 5px 5px;
}
.raceBoardNavigation-standaloneElement:active {
top: 1px;
position: relative;
}
.raceBoardNavigation-standaloneElement:hover {
background: url("images/btn-cta-orangeleft.png") repeat-x scroll center
-30px transparent;
cursor: pointer;
}
.raceBoardNavigation-standaloneElement label {
cursor: pointer;
}
.timePanelButton {
float: left;
margin: 0 0 0 5px;
}
.timePanelButton-SlowDown {
background-color: red !important;
}
.timePanelButton-SpeedUp {
background-color: green !important;
}
.playPauseButton {
padding: 0;
float: left;
width: 32px;
height: 28px;
background: url(images/viewicons/@1x/img/SAP_RV_Play_INACTIVE.png)
center no-repeat;
cursor: pointer;
border: 1px solid #cecece;
border-radius: 4px;
outline: 0;
}
.playPauseButton:hover {
cursor: pointer;
background-color: #cecece;
}
.playPauseButtonPause {
background: url(images/viewicons/@2x/img/SAP_RV_Pause_INACTIVE.png) 2px
0 no-repeat;
outline: 0;
background-size: contain;
}
.playPauseButtonPause:hover {
cursor: pointer;
}
.backToLivePlayButton {
width: 42px;
height: 38px;
font-size: 8px;
white-space: normal;
border-radius: 4px;
border: none;
margin-right: 23px;
margin-top: 5px;
margin-bottom: 5px;
z-index: 1;
}
.backToLivePlayButton-Inactive {
color: #6dc021;
background-color: white;
font-weight: bold;
}
.backToLivePlayButton-Active {
background-color: #6dc021;
color: white;
font-weight: normal;
}
.backToLivePlayButton:hover {
border: 2px solid gray;
}
.backToLivePlayButton:focus {
outline: 0 !important;
}
.dockLayoutPanel div[style="position: absolute; overflow: hidden; left: 0px; right: 0px; bottom: 0px; height: 90px;"]
{
z-index: 10;
}
.browserOptimizedMessage {
padding: 15px 0px;
}
.trackingQuality-circle {
width: 8px;
height: 8px;
border-radius: 50%;
float: left;
}
.circleYellow {
background: #fbba00;
}
.circleGreen {
background: #8ab54e;
}
.circleRed {
background: #f01010;
}
.busyIndicator-Simple {
position: absolute;
top: 0.7em;
right: 7.4em;
}
.busyIndicator-Circle {
}
.raceBoard-TitlePanel {
position: relative;
top: 10px;
z-index: 10;
color: #fff;
margin-left: auto;
margin-right: auto;
}
.raceBoard-TitlePanel-RaceNameLabel {
font-size: 32px;
font-weight: bold;
padding: 7px;
}
.raceBoard-Logo {
position: absolute;
top: 6px;
left: 10px;
z-index: 10;
cursor: pointer;
}
.SideBySideComponentViewer-MainPanel {
top: 12px;
}
.TimePanel-ShowExtended-Button {
width: 29px;
height: 28px;
float: left;
cursor: pointer;
border-radius: 4px;
border: 1px solid #ececec;
}
.TimePanel-ShowExtended-Button-Open {
background: white url(images/arrows_bottom_black.png) center no-repeat;
}
.TimePanel-ShowExtended-Button-Closed {
background: white url(images/arrows_top_black.png) center no-repeat;
}
.TimePanel-ShowExtended-Button:hover {
background-color: #cecece;
}
.TimePanel-ShowExtended-Button:focus {
outline: 0 !important;
}
.RaceBoard-globalNavigation-Link {
display: inline;
margin-right: 3px;
}
.RaceBoard-globalNavigation-Link a {
color: #fff;
cursor: pointer;
}
.RaceBoard-globalNavigation-Link+.RaceBoard-globalNavigation-Link:before
{
content: ' \00bb\00a0';
}
.TimePanel-settingsButtonStyle {
position: absolute;
right: 0px;
z-index: 1;
border: none;
}
.TimePanel-settingsButtonStyle:focus {
outline: 0 !important;
}
.TimePanel-settingsButtonStyle:hover {
border: 1px solid gray;
}
.gwt-SplitLayoutPanel-NorthSouthToggleButton-Closed-multiCompetitorRaceChart
{
background-color: white;
background-image:
url(images/viewicons/@1x/img/SAP_RV_CompetitorCharts_INACTIVE.png),
url(images/arrows_top_black_small.png);
background-repeat: no-repeat, no-repeat;
background-position: 5% 50%, 95% 50%
}
.gwt-SplitLayoutPanel-NorthSouthToggleButton-Open-multiCompetitorRaceChart
{
background-color: white;
background-image:
url(images/viewicons/@1x/img/SAP_RV_CompetitorCharts_GHOSTED.png),
url(images/arrows_bottom_black_small.png);
background-repeat: no-repeat, no-repeat;
background-position: 5% 50%, 95% 50%
}
.gwt-SplitLayoutPanel-NorthSouthToggleButton-Closed-windChart {
background-color: white;
background-image:
url(images/viewicons/@1x/img/SAP_RV_CompetitorCharts_INACTIVE.png),
url(images/arrows_top_black_small.png);
background-repeat: no-repeat, no-repeat;
background-position: 5% 50%, 95% 50%
}
.gwt-SplitLayoutPanel-NorthSouthToggleButton-Open-windChart {
background-color: white;
background-image:
url(images/viewicons/@1x/img/SAP_RV_CompetitorCharts_GHOSTED.png),
url(images/arrows_bottom_black_small.png);
background-repeat: no-repeat, no-repeat;
background-position: 5% 50%, 95% 50%
}
.gwt-SplitLayoutPanel-EastToggleButton-Open-leaderboard {
background-color: white;
background-image:
url(images/viewicons/@1x/img/SAP_RV_Leaderboard_GHOSTED.png),
url(images/arrows_top_black_small.png);
background-repeat: no-repeat, no-repeat;
background-position: 4% 50%, 96% 50%
}
.gwt-SplitLayoutPanel-EastToggleButton-Closed-leaderboard {
background-color: white;
background-image:
url(images/viewicons/@1x/img/SAP_RV_Leaderboard_INACTIVE.png),
url(images/arrows_bottom_black_small.png);
background-repeat: no-repeat, no-repeat;
background-position: 4% 50%, 96% 50%
}
.gwt-SplitLayoutPanel-NorthSouthToggleButton-Closed-media,
.gwt-SplitLayoutPanel-NorthSouthToggleButton-Open-media {
background-color: white;
background-image:
url(images/viewicons/@1x/img/SAP_RV_AudioVideo_INACTIVE.png);
background-repeat: no-repeat, no-repeat;
background-position: 10% 50%, 90% 50%
}
.gwt-SplitLayoutPanel-NorthSouthToggleButton-mediaplaying {
background-image:
url(images/viewicons/@1x/img/SAP_RV_AudioVideo_GHOSTED.png);
}
.gwt-SplitLayoutPanel-NorthSouthToggleButton-Small-media {
background-position: 5% 50%, 100% 50% !important;
margin-left: 0px !important;
padding: 2px 35px !important;
}
@external gwt-ToggleButton-up, gwt-ToggleButton-down, gwt-ToggleButton-up-hovering, gwt-ToggleButton-down-hovering;
.gwt-ToggleButton-up, .gwt-ToggleButton-up-hovering {
background: url(images/unlock.png) center no-repeat;
margin-left: 5px;
}
.gwt-ToggleButton-down, .gwt-ToggleButton-down-hovering {
background: url(images/lock.png) center no-repeat;
margin-left: 5px;
}
.RegattaRaceInformation-Header {
font-family: 'Open Sans', Arial, Verdana, sans-serif;
position: relative;
left: 140px;
top: 11px;
}
.RegattaRaceInformation-Header .RaceName-Label {
display: inline;
color: white;
margin-right: 10px;
font-size: 36px;
}
.RegattaRaceInformation-Header .RaceSeriesAndFleet-Label {
display: inline;
color: white;
font-size: 15px;
}
.RegattaAndRaceTime-Header {
position: absolute;
right: 10px;
top: 13px;
text-align: right;
color: white;
}
.RegattaAndRaceTime-Header .RegattaName-Anchor {
font-size: 15px;
color: white;
text-decoration: none;
padding-left: 25px;
background-image: url(images/home.png);
background-repeat: no-repeat;
background-size: 17px;
background-position: 4px 1px;
}
.RegattaAndRaceTime-Header .RegattaName-Anchor:hover {
text-decoration: underline;
}
.RegattaAndRaceTime-Header .RaceTime-Label {
font-size: 15px;
margin-top: 5px;
}
.VideoPopup-Close-Button {
border: none;
}
.Media-Select-Button {
font-size: 15px;
font-size: 1rem;
display: inline-block;
font-weight: 400;
color: #111;
border: none;
padding: 0.5em 0.3em 0.5em 0.8em;
background-color: #fff;
-webkit-transition: background-color 0.2s;
-moz-transition: background-color 0.2s;
-o-transition: background-color 0.2s;
-ms-transition: background-color 0.2s;
transition: background-color 0.2s;
width: 100%;
max-width: 25em;
text-align: left;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.Media-Select-Button:hover, .Media-Select-Button:focus {
background-color: #f0ab00;
}
.Media-Select-Button-playing {
color: #999;
}
.Media-Select-Button-playing:hover, .Media-Select-Button-playing:focus {
color: #fff;
background-color: #ccc;
}
.Media-Select-Popup .dialogMiddleCenterInner {
padding: 0;
}
.Media-Select-Popup .Caption {
padding: 4px 10px;
}
@@ -0,0 +1,41 @@
<!doctype html>
<html>
<head>
<!--[if lt IE 9]>
<meta http-equiv="REFRESH" content="0; url=http://www.sapsailing.com/browser-info.html">
<![endif]-->
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>SAP Sailing Analytics Race Board</title>
<meta content='width = device-width, initial-scale = 1.0, user-scalable = yes' name='viewport'>
<meta content='yes' name='apple-mobile-web-app-capable'>
<meta content='black' name='apple-mobile-web-app-status-bar-style'>
<!-- <link href='iphone-splash-screen.png' rel='apple-touch-startup-image'> -->
<link href='images/sap-sailing-app-icon.png' rel='apple-touch-icon'>
<link rel="shortcut icon" type="image/x-icon" href="images/sap.ico" />
<!--<link href='http://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700,300italic,400italic,500italic,700italic' rel='stylesheet' type='text/css'>-->
<!-- <link href='http://fonts.googleapis.com/css?family=Open+Sans+Condensed:700,300,300italic' rel='stylesheet' type='text/css'>-->
<link rel="stylesheet" type="text/css" href="/sailing-reset-2.0.cache.css">
<link rel="stylesheet" type="text/css" href="/sailing-fontface-1.0.cache.css">
<link rel="stylesheet" type="text/css" href="EmbeddedMapAndWindChart.css">
<script type="text/javascript" src="js/jquery-1.5.2.min.js"></script>
<script type="text/javascript" language="javascript" src="com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart/com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart.nocache.js"></script>
</head>
<body>
<iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe>
<!-- RECOMMENDED if your web app will not function without JavaScript enabled -->
<noscript>
<div style="width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; background-color: white; border: 1px solid red; padding: 4px; font-family: sans-serif">
Your web browser must have JavaScript enabled
in order for this application to display correctly.
</div>
</noscript>
</body>
</html>
@@ -54,7 +54,7 @@
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-nosuperDevMode -war &quot;${project_loc:com.sap.sailing.gwt.ui}&quot; -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -logLevel INFO -codeServerPort 9997 -startupUrl /gwt/Home.html com.sap.sailing.gwt.ui.Search -startupUrl /gwt/Home.html com.sap.sailing.gwt.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/PolarSheets.html com.sap.sailing.gwt.ui.PolarSheets -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.ui.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.VideoPopup"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-nosuperDevMode -war &quot;${project_loc:com.sap.sailing.gwt.ui}&quot; -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -logLevel INFO -codeServerPort 9997 -startupUrl /gwt/Home.html com.sap.sailing.gwt.ui.Search -startupUrl /gwt/Home.html com.sap.sailing.gwt.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/EmbeddedMapAndWindChart.html com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/PolarSheets.html com.sap.sailing.gwt.ui.PolarSheets -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.ui.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.VideoPopup"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx2048m -XX:MaxPermSize=512m -Xdebug -Xrunjdwp:transport=dt_socket,address=7999,server=y"/>
</launchConfiguration>
@@ -1,76 +1,77 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="com.google.gdt.eclipse.suite.webapp">
<booleanAttribute key="com.google.gdt.eclipse.core.RUN_SERVER" value="false"/>
<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/>
<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/>
<listAttribute key="com.google.gwt.eclipse.core.ENTRY_POINT_MODULES">
<listEntry value="com.sap.sailing.gwt.ui.RaceBoard"/>
<listEntry value="com.sap.sailing.gwt.ui.DataMining"/>
<listEntry value="com.sap.sailing.gwt.ui.LeaderboardEditing"/>
<listEntry value="com.sap.sailing.gwt.ui.Spectator"/>
<listEntry value="com.sap.sailing.gwt.regattaoverview.RegattaOverview"/>
<listEntry value="com.sap.sailing.gwt.ui.PolarSheets"/>
<listEntry value="com.sap.sailing.gwt.ui.Leaderboard"/>
<listEntry value="com.sap.sailing.gwt.ui.Simulator"/>
<listEntry value="com.sap.sailing.gwt.ui.YoutubePopup"/>
<listEntry value="com.sap.sailing.gwt.AutoPlay"/>
<listEntry value="com.sap.sailing.gwt.ui.AdminConsole"/>
<listEntry value="com.sap.sailing.gwt.home.Home"/>
<listEntry value="com.sap.sailing.gwt.ui.VideoPopup"/>
</listAttribute>
<booleanAttribute key="com.google.gwt.eclipse.core.SUPERDEVMODE_ENABLED" value="true"/>
<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/gwt/Home.html"/>
<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>
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
</listAttribute>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="false"/>
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6&quot; javaProject=&quot;com.sap.sailing.gwt.ui&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.gwt.ui/src/main/resources&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.gwt.ui/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.gwt.theme/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.googlecode.java-diff-utils/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/org.json.simple/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.server/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.tractracadapter/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.expeditionconnector/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.declination/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.declination/resources&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.udpconnector/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.mongodb/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.swisstimingadapter/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.persistence/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.swisstimingadapter.persistence/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.operationaltransformation/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.replication/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.tractracadapter.persistence/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/org.moxieapps.gwt.highcharts/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.geocoding/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.datamining.shared/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.datamining.shared/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.gwt/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.google.gwt.osgi/lib/gwt-user.jar&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#13;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;com.sap.sailing.gwt.ui&quot;/&gt;&#13;&#10;&lt;/runtimeClasspathEntry&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.security/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.security.ui/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.gwt.adminconsole/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.security.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.google.gwt.eclipse.core.moduleClasspathProvider"/>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-superDevMode -incremental -workDir &quot;${project_loc:com.sap.sailing.gwt.ui}/.tmp/gwt-work&quot; -war &quot;${project_loc:com.sap.sailing.gwt.ui}&quot; -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -logLevel INFO -codeServerPort 9997 -startupUrl /gwt/Home.html com.sap.sailing.gwt.home.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/PolarSheets.html com.sap.sailing.gwt.ui.PolarSheets -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup com.sap.sailing.gwt.home.Desktop com.sap.sailing.gwt.home.Home com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.ui.PolarSheets com.sap.sailing.gwt.regattaoverview.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.ui.RaceBoard"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms1024m -Xmx3072m"/>
</launchConfiguration>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="com.google.gdt.eclipse.suite.webapp">
<booleanAttribute key="com.google.gdt.eclipse.core.RUN_SERVER" value="false"/>
<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/>
<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/>
<listAttribute key="com.google.gwt.eclipse.core.ENTRY_POINT_MODULES">
<listEntry value="com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart"/>
<listEntry value="com.sap.sailing.gwt.ui.RaceBoard"/>
<listEntry value="com.sap.sailing.gwt.ui.DataMining"/>
<listEntry value="com.sap.sailing.gwt.ui.LeaderboardEditing"/>
<listEntry value="com.sap.sailing.gwt.ui.Spectator"/>
<listEntry value="com.sap.sailing.gwt.regattaoverview.RegattaOverview"/>
<listEntry value="com.sap.sailing.gwt.ui.PolarSheets"/>
<listEntry value="com.sap.sailing.gwt.ui.Leaderboard"/>
<listEntry value="com.sap.sailing.gwt.ui.Simulator"/>
<listEntry value="com.sap.sailing.gwt.ui.YoutubePopup"/>
<listEntry value="com.sap.sailing.gwt.AutoPlay"/>
<listEntry value="com.sap.sailing.gwt.ui.AdminConsole"/>
<listEntry value="com.sap.sailing.gwt.home.Home"/>
<listEntry value="com.sap.sailing.gwt.ui.VideoPopup"/>
</listAttribute>
<booleanAttribute key="com.google.gwt.eclipse.core.SUPERDEVMODE_ENABLED" value="true"/>
<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/gwt/Home.html"/>
<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>
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
</listAttribute>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="false"/>
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6&quot; javaProject=&quot;com.sap.sailing.gwt.ui&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.gwt.ui/src/main/resources&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.gwt.ui/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.gwt.theme/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.googlecode.java-diff-utils/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/org.json.simple/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.server/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.tractracadapter/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.expeditionconnector/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.declination/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.declination/resources&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.udpconnector/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.mongodb/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.swisstimingadapter/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.persistence/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.swisstimingadapter.persistence/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.operationaltransformation/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.replication/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.tractracadapter.persistence/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/org.moxieapps.gwt.highcharts/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.geocoding/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.datamining.shared/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.datamining.shared/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.gwt/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.google.gwt.osgi/lib/gwt-user.jar&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#13;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;com.sap.sailing.gwt.ui&quot;/&gt;&#13;&#10;&lt;/runtimeClasspathEntry&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.security/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.security.ui/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.gwt.adminconsole/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.security.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.google.gwt.eclipse.core.moduleClasspathProvider"/>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-superDevMode -incremental -workDir &quot;${project_loc:com.sap.sailing.gwt.ui}/.tmp/gwt-work&quot; -war &quot;${project_loc:com.sap.sailing.gwt.ui}&quot; -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -logLevel INFO -codeServerPort 9997 -startupUrl /gwt/Home.html com.sap.sailing.gwt.home.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/EmbeddedMapAndWindChart com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/PolarSheets.html com.sap.sailing.gwt.ui.PolarSheets -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup com.sap.sailing.gwt.home.Desktop com.sap.sailing.gwt.home.Home com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.ui.PolarSheets com.sap.sailing.gwt.regattaoverview.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.ui.RaceBoard com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms1024m -Xmx3072m"/>
</launchConfiguration>
+76 -76
View File
@@ -1,76 +1,76 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="com.google.gdt.eclipse.suite.webapp">
<booleanAttribute key="com.google.gdt.eclipse.core.RUN_SERVER" value="false"/>
<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/>
<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/>
<booleanAttribute key="com.google.gwt.eclipse.core.CODE_SERVER_PORT_AUTO" value="true"/>
<listAttribute key="com.google.gwt.eclipse.core.ENTRY_POINT_MODULES">
<listEntry value="com.sap.sailing.gwt.ui.RaceBoard"/>
<listEntry value="com.sap.sailing.gwt.ui.DataMining"/>
<listEntry value="com.sap.sailing.gwt.ui.LeaderboardEditing"/>
<listEntry value="com.sap.sailing.gwt.ui.Spectator"/>
<listEntry value="com.sap.sailing.gwt.regattaoverview.RegattaOverview"/>
<listEntry value="com.sap.sailing.gwt.ui.PolarSheets"/>
<listEntry value="com.sap.sailing.gwt.ui.Leaderboard"/>
<listEntry value="com.sap.sailing.gwt.ui.Simulator"/>
<listEntry value="com.sap.sailing.gwt.ui.YoutubePopup"/>
<listEntry value="com.sap.sailing.gwt.AutoPlay"/>
<listEntry value="com.sap.sailing.gwt.ui.AdminConsole"/>
<listEntry value="com.sap.sailing.gwt.home.Home"/>
<listEntry value="com.sap.sailing.gwt.ui.VideoPopup"/>
</listAttribute>
<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/gwt/Home.html"/>
<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>
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
</listAttribute>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="false"/>
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6&quot; javaProject=&quot;com.sap.sailing.gwt.ui&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.gwt.ui/src/main/resources&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.gwt.ui/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.gwt.theme/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.googlecode.java-diff-utils/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/org.json.simple/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.server/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.tractracadapter/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.expeditionconnector/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.declination/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.declination/resources&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.udpconnector/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.mongodb/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.swisstimingadapter/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.persistence/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.swisstimingadapter.persistence/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.operationaltransformation/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.replication/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.tractracadapter.persistence/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/org.moxieapps.gwt.highcharts/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.geocoding/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.datamining.shared/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.datamining.shared/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.gwt/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.google.gwt.osgi/lib/gwt-user.jar&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#13;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;com.sap.sailing.gwt.ui&quot;/&gt;&#13;&#10;&lt;/runtimeClasspathEntry&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.security/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.security.ui/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.gwt.adminconsole/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.security.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.google.gwt.eclipse.core.moduleClasspathProvider"/>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-nosuperDevMode -incremental -war &quot;${project_loc:com.sap.sailing.gwt.ui}&quot; -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -logLevel INFO -codeServerPort auto -startupUrl /gwt/Home.html com.sap.sailing.gwt.home.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/PolarSheets.html com.sap.sailing.gwt.ui.PolarSheets -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup com.sap.sailing.gwt.home.Home com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.ui.PolarSheets com.sap.sailing.gwt.regattaoverview.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.ui.RaceBoard"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx2048m -Dgwt-usearchives=false -Dgwt.persistentunitcache=false"/>
</launchConfiguration>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="com.google.gdt.eclipse.suite.webapp">
<booleanAttribute key="com.google.gdt.eclipse.core.RUN_SERVER" value="false"/>
<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/>
<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/>
<booleanAttribute key="com.google.gwt.eclipse.core.CODE_SERVER_PORT_AUTO" value="true"/>
<listAttribute key="com.google.gwt.eclipse.core.ENTRY_POINT_MODULES">
<listEntry value="com.sap.sailing.gwt.ui.RaceBoard"/>
<listEntry value="com.sap.sailing.gwt.ui.DataMining"/>
<listEntry value="com.sap.sailing.gwt.ui.LeaderboardEditing"/>
<listEntry value="com.sap.sailing.gwt.ui.Spectator"/>
<listEntry value="com.sap.sailing.gwt.regattaoverview.RegattaOverview"/>
<listEntry value="com.sap.sailing.gwt.ui.PolarSheets"/>
<listEntry value="com.sap.sailing.gwt.ui.Leaderboard"/>
<listEntry value="com.sap.sailing.gwt.ui.Simulator"/>
<listEntry value="com.sap.sailing.gwt.ui.YoutubePopup"/>
<listEntry value="com.sap.sailing.gwt.AutoPlay"/>
<listEntry value="com.sap.sailing.gwt.ui.AdminConsole"/>
<listEntry value="com.sap.sailing.gwt.home.Home"/>
<listEntry value="com.sap.sailing.gwt.ui.VideoPopup"/>
</listAttribute>
<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/gwt/Home.html"/>
<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>
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
</listAttribute>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="false"/>
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6&quot; javaProject=&quot;com.sap.sailing.gwt.ui&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.gwt.ui/src/main/resources&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.gwt.ui/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.gwt.theme/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.googlecode.java-diff-utils/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/org.json.simple/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.server/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.tractracadapter/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.expeditionconnector/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.declination/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.declination/resources&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.udpconnector/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.mongodb/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.swisstimingadapter/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.persistence/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.swisstimingadapter.persistence/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.operationaltransformation/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.replication/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.tractracadapter.persistence/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/org.moxieapps.gwt.highcharts/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.geocoding/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.datamining.shared/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.datamining.shared/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.gwt/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.google.gwt.osgi/lib/gwt-user.jar&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#13;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;com.sap.sailing.gwt.ui&quot;/&gt;&#13;&#10;&lt;/runtimeClasspathEntry&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.security/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.security.ui/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.gwt.adminconsole/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.security.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.google.gwt.eclipse.core.moduleClasspathProvider"/>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-nosuperDevMode -incremental -war &quot;${project_loc:com.sap.sailing.gwt.ui}&quot; -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -logLevel INFO -codeServerPort auto -startupUrl /gwt/Home.html com.sap.sailing.gwt.home.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/PolarSheets.html com.sap.sailing.gwt.ui.PolarSheets -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup com.sap.sailing.gwt.home.Home com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.ui.PolarSheets com.sap.sailing.gwt.regattaoverview.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.ui.RaceBoard"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx2048m -Dgwt-usearchives=false -Dgwt.persistentunitcache=false"/>
</launchConfiguration>
+4 -1
View File
@@ -50,5 +50,8 @@ bin.includes = META-INF/,\
Home.html,\
HomeDesktop.html,\
HomeMobile.html,\
SettingsDialog.css
SettingsDialog.css,\
EmbeddedMapAndWindChart.css,\
EmbeddedMapAndWindChart.html,\
com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart/
output.. = WEB-INF/classes/
+1
View File
@@ -130,6 +130,7 @@
<module>com.sap.sailing.gwt.ui.Leaderboard</module>
<module>com.sap.sailing.gwt.ui.LeaderboardEditing</module>
<module>com.sap.sailing.gwt.ui.RaceBoard</module>
<module>com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart</module>
<module>com.sap.sailing.gwt.ui.Spectator</module>
<module>com.sap.sailing.gwt.ui.DataMining</module>
<module>com.sap.sailing.gwt.ui.VideoPopup</module>
@@ -1,26 +0,0 @@
package com.sap.sailing.gwt.ui.actions;
import java.util.Date;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.shared.CoursePositionsDTO;
import com.sap.sse.gwt.client.async.AsyncAction;
public class GetCoursePositionsAction implements AsyncAction<CoursePositionsDTO> {
private final SailingServiceAsync sailingService;
private final RegattaAndRaceIdentifier raceIdentifier;
private final Date date;
public GetCoursePositionsAction(SailingServiceAsync sailingService, RegattaAndRaceIdentifier raceIdentifier, Date date) {
this.sailingService = sailingService;
this.raceIdentifier = raceIdentifier;
this.date = date;
}
@Override
public void execute(AsyncCallback<CoursePositionsDTO> callback) {
sailingService.getCoursePositions(raceIdentifier, date, callback);
}
}
@@ -157,7 +157,7 @@ public class EventDetailsComposite extends Composite {
}
videoURLList.setValues(videoURLStringsAsList);
List<String> leaderboardGroupNamesAsList = new ArrayList<>();
for(LeaderboardGroupDTO leaderboardGroupDTO: event.getLeaderboardGroups()) {
for (LeaderboardGroupDTO leaderboardGroupDTO : event.getLeaderboardGroups()) {
leaderboardGroupNamesAsList.add(leaderboardGroupDTO.getName());
}
leaderboardGroupList.setValues(leaderboardGroupNamesAsList);
@@ -21,6 +21,13 @@ public class RaceTimePanel extends TimePanel<RaceTimePanelSettings> implements R
private RegattaAndRaceIdentifier selectedRace;
private boolean autoAdjustPlayMode;
private RaceTimesInfoDTO lastRaceTimesInfo;
/**
* When a marker update is required but min/max are not yet initialized, this flag is set. If later
* {@link #setMinMax(Date, Date, boolean)} is invoked and this flag is set, a {@link #redrawAllMarkers(RaceTimesInfoDTO)}
* will be issued and the flag is cleared.
*/
private boolean redrawAllMarkersPendingForMinMaxBeingInitialized;
public RaceTimePanel(Timer timer, TimeRangeWithZoomProvider timeRangeProvider, StringMessages stringMessages,
RaceTimesInfoProvider raceTimesInfoProvider, boolean canReplayWhileLiveIsPossible) {
@@ -105,7 +112,7 @@ public class RaceTimePanel extends TimePanel<RaceTimePanelSettings> implements R
// maybe show a special state for this like "Race did not start yet"
}
}
lastRaceTimesInfo = raceTimesInfo;
lastRaceTimesInfo = raceTimesInfo; // TODO bug 3122: when not redrawn yet because min/max not initialized yet, further redraw is disabled by this.
}
@Override
@@ -181,6 +188,15 @@ public class RaceTimePanel extends TimePanel<RaceTimePanelSettings> implements R
}
}
@Override
public void setMinMax(Date min, Date max, boolean fireEvent) {
super.setMinMax(min, max, fireEvent);
if (redrawAllMarkersPendingForMinMaxBeingInitialized && timeSlider.isMinMaxInitialized()) {
redrawAllMarkers(lastRaceTimesInfo);
redrawAllMarkersPendingForMinMaxBeingInitialized = false;
}
}
/**
* When in {@link PlayModes#Replay} mode, tries to put the {@link #timer} to the time point when the last leg was
* finished first. If this time point is not (yet?) known, tries to put the {@link #timer} to the
@@ -239,8 +255,12 @@ public class RaceTimePanel extends TimePanel<RaceTimePanelSettings> implements R
requiresMarkerUpdate = true;
}
}
if (requiresMarkerUpdate && timeSlider.isMinMaxInitialized()) {
redrawAllMarkers(newRaceTimesInfo);
if (requiresMarkerUpdate) {
if (timeSlider.isMinMaxInitialized()) { // TODO bug 3122 later, the lastRaceTimesInfo will be updated even if not redrawn because min/max not initialized
redrawAllMarkers(newRaceTimesInfo);
} else {
redrawAllMarkersPendingForMinMaxBeingInitialized = true;
}
}
}
@@ -9,7 +9,7 @@ package com.sap.sailing.gwt.ui.client;
*/
public interface RequiresDataInitialization {
public void initializeData(boolean showMapControls);
public void initializeData(boolean showMapControls, boolean showHeaderPanel);
public boolean isDataInitialized();
}
@@ -614,4 +614,6 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
ArrayList<LeaderboardGroupDTO> getLeaderboardGroupsByEventId(UUID id);
boolean doesRegattaLogContainCompetitors(String name) throws DoesNotHaveRegattaLogException;
RegattaAndRaceIdentifier getRaceIdentifier(String regattaLikeName, String raceColumnName, String fleetName);
}
@@ -719,4 +719,6 @@ public interface SailingServiceAsync extends BuildVersionRetriever, FileStorageM
void getLeaderboardGroupsByEventId(UUID id, AsyncCallback<ArrayList<LeaderboardGroupDTO>> callback);
void doesRegattaLogContainCompetitors(String name, AsyncCallback<Boolean> regattaLogCallBack);
void getRaceIdentifier(String regattaLikeName, String raceColumnName, String fleetName, AsyncCallback<RegattaAndRaceIdentifier> asyncCallback);
}
@@ -1340,5 +1340,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String selectCompetitor();
String points();
String numberOfRacesShort();
String courseGeometry();
String degreesToWind(String diff);
String miniLeeaderboardLegendText();
}
@@ -881,7 +881,7 @@ errorRunningDataMiningQuery=An error occured running the query
hideToolbar=Hide toolbar
showSeriesLeaderboards=Show series leaderboards
showOverallLeaderboard=Show overall leaderboard
lineAngleToWindAndAdvantage=length: {0}m; angle to wind: {1}deg; {2} side has {3}m advantage
lineAngleToWindAndAdvantage=length: {0}m\nangle to wind: {1}deg\n{2} side has {3}m advantage
doYouReallyWantToRemoveEvents=Do you really want to remove the events?
doYouReallyWantToRemoveEvent=Do you really want to remove event {0}?
line=Line
@@ -1254,7 +1254,7 @@ sampleURL=Sample URL: {0}
sapSportsOn=SAP Sports on
followSapSports=Follow SAP Sports
liveNow=Live now
analyseRace=Analyse race
analyseRace=Analyze race
nextRaceStartingIn=Next race starts in
startingIn={0} starts in
raceIsPlanned=Planned
@@ -1309,4 +1309,6 @@ hoursAgo={0} h ago
selectCompetitor=Please select one competitor
points=Points
numberOfRacesShort=# Races
courseGeometry=Course Geometry
degreesToWind={0}° to wind
miniLeeaderboardLegendText=Shows the points along with the number of races per competitor
@@ -877,7 +877,7 @@ errorRunningDataMiningQuery=Es ist ein Felher bei der Datenabfrage aufgetreten
hideToolbar=Toolbar ausblenden
showSeriesLeaderboards=Ergebnisse der Serie anzeigen
showOverallLeaderboard=Gesamtergebnisse anzeigen
lineAngleToWindAndAdvantage=Länge: {0}m; Winkel zum Wind: {1}°; {2}-Seite ist {3}m bevorteilt
lineAngleToWindAndAdvantage=Länge: {0}m\nWinkel zum Wind: {1}°\n{2}-Seite ist {3}m bevorteilt
doYouReallyWantToRemoveEvents=Möchten Sie diese Veranstaltungen wirklich entfernen?
doYouReallyWantToRemoveEvent=Möchten Sie wirklich die Veranstaltung {0} entfernen?
line=Linie
@@ -1299,4 +1299,6 @@ hoursAgo=vor {0} h
selectCompetitor=Bitte einen Teilnehmer auswählen
points=Punkte
numberOfRacesShort=# Rennen
courseGeometry=Kursgeometrie
degreesToWind={0}° zum Wind
miniLeeaderboardLegendText=Es werden die Punkte und die Anzahl Rennen je Team angezeigt
@@ -870,7 +870,7 @@ errorRunningDataMiningQuery=Ошибка при выполнении запро
hideToolbar=Скрыть панель инструментов
showSeriesLeaderboards=Показать таблицу лидеров серии
showOverallLeaderboard=Показать общую таблицу лидеров
lineAngleToWindAndAdvantage=длина: {0}м; угол к ветру: {1}градус; {2} борт {3}м имеет преимущество
lineAngleToWindAndAdvantage=длина: {0}м\nугол к ветру: {1}градус\n{2} борт {3}м имеет преимущество
doYouReallyWantToRemoveEvents=Вы действительно хотите удалить все события?
doYouReallyWantToRemoveEvent=Вы действительно хотите удалить событие {0}?
line=Строка
@@ -1246,4 +1246,6 @@ hoursAgo={0} h часов назад
selectCompetitor=Please select one competitor
points=Points
numberOfRacesShort=# Races
courseGeometry=Course Geometry
degreesToWind={0}° to wind
miniLeeaderboardLegendText=Shows points along with the number of races per competitor
@@ -391,7 +391,7 @@ listRaces=List Races
dropReplicaConnection=Drop connection
errorTryingToObtainOverallLeaderboards=Error trying to obtain overall leaderboards: {0}
distanceTraveled=行驶距离
lineAngleToWindAndAdvantage=length: {0}m; angle to wind: {1}deg; {2} side has {3}m advantage
lineAngleToWindAndAdvantage=length: {0}m\nangle to wind: {1}deg\n{2} side has {3}m advantage
mapDevices=Map Devices to Competitors and Marks
scoringSchemeHighPointFirstGetsTenOrEight=High Point, winner gets 10 points (or 8)
playModeLive=Live
@@ -1244,7 +1244,7 @@ sampleURL=Sample URL: {0}
sapSportsOn=SAP Sports on
followSapSports=Follow SAP Sports
liveNow=Live now
analyseRace=Analyse race
analyseRace=Analyze race
nextRaceStartingIn=Next race starts in
startingIn={0} starts in
raceIsPlanned=Planned
@@ -1295,4 +1295,6 @@ openLeaderboard=Open Leaderboard
selectCompetitor=Please select one competitor
points=Points
numberOfRacesShort=# Races
courseGeometry=Course Geometry
degreesToWind={0}° to wind
miniLeeaderboardLegendText=Shows points along with the number of races per competitor
@@ -20,6 +20,9 @@ import com.google.gwt.user.client.ui.RequiresResize;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.ui.client.TimePanelCssResources.TimePanelCss;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.gwt.client.controls.slider.SliderBar;
import com.sap.sse.gwt.client.controls.slider.TimeSlider;
import com.sap.sse.gwt.client.player.PlayStateListener;
@@ -331,9 +334,13 @@ public class TimePanel<T extends TimePanelSettings> extends SimplePanel implemen
if (timeRangeProvider.isZoomed()) {
timeSlider.setCurrentValue(new Double(newTime.getTime()), false);
} else {
if (getFromTime() == null || getToTime() == null) {
initializeTimeRange(oldTime, newTime);
}
if (getFromTime() != null && getToTime() != null) {
// handle the case where time advances beyond slider's end.
if (newTime.after(getToTime())) {
// in live mode, expand the range
switch (timer.getPlayMode()) {
case Live:
Date newMaxTime = new Date(newTime.getTime());
@@ -343,6 +350,7 @@ public class TimePanel<T extends TimePanelSettings> extends SimplePanel implemen
setMinMax(getFromTime(), newMaxTime, /* fireEvent */ false); // no event because we guarantee that time is between min/max
break;
case Replay:
// in replay, stop playing when the end of the range has been reached
timer.pause();
break;
}
@@ -362,6 +370,22 @@ public class TimePanel<T extends TimePanelSettings> extends SimplePanel implemen
}
}
/**
* When the time range is not yet properly initialized and we get a time change, adjust the time range so that old and
* new time are in range. A margin of one minute is used before and after. This method assumes that at least one of the
* two time points passed as parameters has a value other than <code>null</code>. Should the other be <code>null</code>,
* it is ignored. No assumptions are made about the temporal relation of the two time points to each other; in other
* words, <code>oldTime</code> may also be after <code>newTime<code> which could, e.g., be the case for a timer running
* backwards.
*/
private void initializeTimeRange(Date oldTime, Date newTime) {
TimePoint from = Util.getEarliestOfTimePoints(getFromTime()==null?null:new MillisecondsTimePoint(getFromTime()), oldTime==null?null:new MillisecondsTimePoint(oldTime));
from = Util.getEarliestOfTimePoints(from, newTime==null?null:new MillisecondsTimePoint(newTime));
TimePoint to = Util.getEarliestOfTimePoints(getToTime()==null?null:new MillisecondsTimePoint(getToTime()), oldTime==null?null:new MillisecondsTimePoint(oldTime));
from = Util.getEarliestOfTimePoints(to, newTime==null?null:new MillisecondsTimePoint(newTime));
timeRangeProvider.setTimeRange(from==null?null:from.asDate(), to==null?null:to.asDate());
}
protected String getTimeToStartLabelText(Date time) {
return null;
}
@@ -396,16 +420,12 @@ public class TimePanel<T extends TimePanelSettings> extends SimplePanel implemen
assert min != null && max != null;
boolean changed = false;
if (!max.equals(timeRangeProvider.getToTime())) {
if (!max.equals(timeRangeProvider.getToTime()) || !min.equals(timeRangeProvider.getFromTime())) {
changed = true;
timeSlider.setMaxValue(new Double(max.getTime()), fireEvent);
}
if (!min.equals(timeRangeProvider.getFromTime())) {
changed = true;
timeSlider.setMinValue(new Double(min.getTime()), fireEvent);
timeSlider.setMinAndMaxValue(new Double(min.getTime()),new Double(max.getTime()), fireEvent);
}
if (changed) {
if(!timeRangeProvider.isZoomed()) {
if (!timeRangeProvider.isZoomed()) {
timeRangeProvider.setTimeRange(min, max, this);
}
@@ -595,4 +615,8 @@ public class TimePanel<T extends TimePanelSettings> extends SimplePanel implemen
public String getDependentCssClassName() {
return "timePanel";
}
public Button getBackToLiveButton() {
return backToLivePlayButton;
}
}
@@ -44,6 +44,7 @@ import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.common.impl.ColorMapImpl;
import com.sap.sailing.gwt.ui.actions.GetWindInfoAction;
import com.sap.sailing.gwt.ui.client.RaceSelectionChangeListener;
import com.sap.sailing.gwt.ui.client.RaceSelectionProvider;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
@@ -86,7 +87,9 @@ public class WindChart extends AbstractRaceChart implements Component<WindChartS
* @param raceSelectionProvider
* if <code>null</code>, this chart won't update its contents automatically upon race selection change;
* otherwise, whenever the selection changes, the wind data of the race selected now is loaded from the
* server and displayed in this chart. If no race is selected, the chart is cleared.
* server and displayed in this chart. If no race is selected, the chart is cleared. The caller of this
* constructor must ensure to trigger {@link RaceSelectionChangeListener#onRaceSelectionChange(List)} at
* least once to ensure that this chart sets its {@link AbstractRaceChart#selectedRaceIdentifier} field.
*/
public WindChart(SailingServiceAsync sailingService, RaceSelectionProvider raceSelectionProvider, Timer timer,
TimeRangeWithZoomProvider timeRangeWithZoomProvider, WindChartSettings settings, final StringMessages stringMessages,
@@ -518,38 +521,35 @@ public class WindChart extends AbstractRaceChart implements Component<WindChartS
*/
@Override
public void timeChanged(Date newTime, Date oldTime) {
if(!isVisible()) {
return;
}
updateTimePlotLine(newTime);
switch(timer.getPlayMode()) {
case Live:
{
// is date before first cache entry or is cache empty?
if (timeOfEarliestRequestInMillis == null || newTime.getTime() < timeOfEarliestRequestInMillis) {
loadData(timeRangeWithZoomProvider.getFromTime(), newTime, /* append */ true);
} else if (newTime.getTime() > timeOfLatestRequestInMillis) {
loadData(new Date(timeOfLatestRequestInMillis), timeRangeWithZoomProvider.getToTime(), /* append */true);
}
// otherwise the cache spans across date and so we don't need to load anything
break;
}
case Replay:
{
if (timeOfLatestRequestInMillis == null) {
// pure replay mode
loadData(timeRangeWithZoomProvider.getFromTime(), timeRangeWithZoomProvider.getToTime(), /* append */false);
} else {
// replay mode during live play
if (isVisible()) {
updateTimePlotLine(newTime);
switch (timer.getPlayMode()) {
case Live:
{
// is date before first cache entry or is cache empty?
if (timeOfEarliestRequestInMillis == null || newTime.getTime() < timeOfEarliestRequestInMillis) {
loadData(timeRangeWithZoomProvider.getFromTime(), newTime, /* append */ true);
} else if (newTime.getTime() > timeOfLatestRequestInMillis) {
loadData(new Date(timeOfLatestRequestInMillis), newTime, /* append */true);
}
loadData(new Date(timeOfLatestRequestInMillis), timeRangeWithZoomProvider.getToTime(), /* append */true);
}
// otherwise the cache spans across date and so we don't need to load anything
break;
}
case Replay:
{
if (timeOfLatestRequestInMillis == null) {
// pure replay mode
loadData(timeRangeWithZoomProvider.getFromTime(), timeRangeWithZoomProvider.getToTime(), /* append */false);
} else {
// replay mode during live play
if (timeOfEarliestRequestInMillis == null || newTime.getTime() < timeOfEarliestRequestInMillis) {
loadData(timeRangeWithZoomProvider.getFromTime(), newTime, /* append */ true);
} else if (newTime.getTime() > timeOfLatestRequestInMillis) {
loadData(new Date(timeOfLatestRequestInMillis), newTime, /* append */true);
}
}
break;
}
break;
}
}
}
@@ -100,16 +100,19 @@ import com.sap.sailing.gwt.ui.client.shared.filter.QuickRankProvider;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapHelpLinesSettings.HelpLineTypes;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapZoomSettings.ZoomTypes;
import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil;
import com.sap.sailing.gwt.ui.shared.ControlPointDTO;
import com.sap.sailing.gwt.ui.shared.CoursePositionsDTO;
import com.sap.sailing.gwt.ui.shared.GPSFixDTO;
import com.sap.sailing.gwt.ui.shared.LegInfoDTO;
import com.sap.sailing.gwt.ui.shared.ManeuverDTO;
import com.sap.sailing.gwt.ui.shared.MarkDTO;
import com.sap.sailing.gwt.ui.shared.QuickRankDTO;
import com.sap.sailing.gwt.ui.shared.RaceCourseDTO;
import com.sap.sailing.gwt.ui.shared.RaceMapDataDTO;
import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO;
import com.sap.sailing.gwt.ui.shared.SidelineDTO;
import com.sap.sailing.gwt.ui.shared.SpeedWithBearingDTO;
import com.sap.sailing.gwt.ui.shared.WaypointDTO;
import com.sap.sailing.gwt.ui.shared.WindDTO;
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
import com.sap.sailing.gwt.ui.shared.WindTrackInfoDTO;
@@ -118,6 +121,7 @@ import com.sap.sailing.gwt.ui.shared.racemap.GoogleMapStyleHelper;
import com.sap.sailing.gwt.ui.shared.racemap.RaceSimulationOverlay;
import com.sap.sailing.gwt.ui.shared.racemap.WindStreamletsRaceboardOverlay;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.Util.Triple;
import com.sap.sse.common.filter.Filter;
import com.sap.sse.common.filter.FilterSet;
@@ -209,11 +213,24 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
private AdvantageLineMouseOverMapHandler advantageLineMouseOverHandler;
/**
* Polyline for the course middle line.
* Polylines for the course middle lines; keys are the two control points delimiting the leg for which the
* {@link Polyline} value shows the course middle line. As only one course middle line is shown even if there
* are multiple legs using the same control points in different directions, using a {@link Set} makes this
* independent of the order of the two control points. If no course middle line is currently being shown for
* a pair of control points, the map will not contain a value for this pair.
*/
private Polyline courseMiddleLine;
private final Map<Set<ControlPointDTO>, Polyline> courseMiddleLines;
private Map<SidelineDTO, Polygon> courseSidelines;
private final Map<SidelineDTO, Polygon> courseSidelines;
/**
* When the {@link HelpLineTypes#COURSEGEOMETRY} option is selected, little markers will be displayed on the
* lines that show the tooltip text in a little info box linked to the line. When the line is removed by
* {@link #showOrRemoveOrUpdateLine(Polyline, boolean, Position, Position, LineInfoProvider, String)}, these
* overlays need to be removed as well. Also, when the {@link HelpLineTypes#COURSEGEOMETRY} setting is
* deactivated, all these overlays need to go.
*/
private final Map<Polyline, SmallTransparentInfoOverlay> infoOverlaysForLinesForCourseGeometry;
/**
* Wind data used to display the advantage line. Retrieved by a {@link GetWindInfoAction} execution and used in
@@ -382,7 +399,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
public RaceMap(SailingServiceAsync sailingService, AsyncActionsExecutor asyncActionsExecutor,
ErrorReporter errorReporter, Timer timer, CompetitorSelectionProvider competitorSelection,
StringMessages stringMessages, boolean showMapControls, boolean showViewStreamlets, boolean showViewSimulation,
RegattaAndRaceIdentifier raceIdentifier, CombinedWindPanelStyle combinedWindPanelStyle) {
RegattaAndRaceIdentifier raceIdentifier, CombinedWindPanelStyle combinedWindPanelStyle, boolean showHeaderPanel) {
this.setSize("100%", "100%");
this.showMapControls = showMapControls;
this.stringMessages = stringMessages;
@@ -394,7 +411,9 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
timer.addTimeListener(this);
raceMapImageManager = new RaceMapImageManager();
markDTOs = new HashMap<String, MarkDTO>();
courseSidelines = new HashMap<SidelineDTO, Polygon>();
courseSidelines = new HashMap<>();
courseMiddleLines = new HashMap<>();
infoOverlaysForLinesForCourseGeometry = new HashMap<>();
boatOverlays = new HashMap<CompetitorDTO, BoatOverlay>();
competitorInfoOverlays = new HashMap<CompetitorDTO, CompetitorInfoOverlay>();
windSensorOverlays = new HashMap<WindSource, WindSensorOverlay>();
@@ -414,7 +433,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
headerPanel.setStyleName("RaceMap-HeaderPanel");
panelForLeftHeaderLabels = new AbsolutePanel();
panelForRightHeaderLabels = new AbsolutePanel();
initializeData(showMapControls);
initializeData(showMapControls, showHeaderPanel);
combinedWindPanel = new CombinedWindPanel(raceMapImageManager, combinedWindPanelStyle, stringMessages, coordinateSystem);
combinedWindPanel.setVisible(false);
trueNorthIndicatorPanel = new TrueNorthIndicatorPanel(this, raceMapImageManager, combinedWindPanelStyle, stringMessages, coordinateSystem);
@@ -483,8 +502,8 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
public void execute() {
if (map != null) {
map.setOptions(mapOptions);
final LatLngBounds newBounds = getDefaultZoomBounds();
zoomMapToNewBounds(newBounds);
// ensure zooming to what the settings tell, or defaults if what the settings tell isn't possible right now
mapFirstZoomDone = false;
trueNorthIndicatorPanel.redraw();
orientationChangeInProgress = false;
}
@@ -492,7 +511,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
});
}
private void loadMapsAPIV3(final boolean showMapControls) {
private void loadMapsAPIV3(final boolean showMapControls, final boolean showHeaderPanel) {
boolean sensor = true;
// load all the libs for use in the maps
@@ -506,8 +525,10 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
MapOptions mapOptions = getMapOptions(showMapControls, /* wind up */ false);
map = new MapWidget(mapOptions);
RaceMap.this.add(map, 0, 0);
Image sapLogo = createSAPLogo();
RaceMap.this.add(sapLogo);
if (showHeaderPanel) {
Image sapLogo = createSAPLogo();
RaceMap.this.add(sapLogo);
}
map.setControls(ControlPosition.LEFT_TOP, combinedWindPanel);
combinedWindPanel.getParent().addStyleName("CombinedWindPanelParentDiv");
map.setControls(ControlPosition.LEFT_TOP, trueNorthIndicatorPanel);
@@ -592,19 +613,26 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
simulationOverlay.addToMap();
simulationOverlay.setVisible(false);
}
createHeaderPanel(map);
if (showHeaderPanel) {
createHeaderPanel(map);
}
createSettingsButton(map);
// Data has been initialized
RaceMap.this.isMapInitialized = true;
RaceMap.this.redraw();
trueNorthIndicatorPanel.redraw();
showAdditionalControls(map);
}
};
LoadApi.go(onLoad, loadLibraries, sensor, "key="+GoogleMapAPIKey.V3_APIKey);
}
/**
* Subclasses may define additional stuff to be shown on the map.
*/
protected void showAdditionalControls(MapWidget map) {
}
private void setHasPolar() {
GetPolarAction getPolar = new GetPolarAction(sailingService, raceIdentifier);
@@ -753,7 +781,6 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
getRaceMapDataCallback(oldTime, newTime, fromAndToAndOverlap.getC(), competitorsToShow, requestID));
// draw the wind into the map, get the combined wind
// TODO bug2057 also fetch wind for LEG_MIDDLE for all legs because this needs to be the basis for the advantage line display
List<String> windSourceTypeNames = new ArrayList<String>();
windSourceTypeNames.add(WindSourceType.EXPEDITION.name());
windSourceTypeNames.add(WindSourceType.COMBINED.name());
@@ -879,7 +906,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
updateCoordinateSystemFromSettings();
}
showCourseSidelinesOnMap(raceMapDataDTO.courseSidelines);
showStartAndFinishLines(raceMapDataDTO.coursePositions);
showStartAndFinishAndCourseMiddleLines(raceMapDataDTO.coursePositions);
showStartLineToFirstMarkTriangle(raceMapDataDTO.coursePositions);
// even though the wind data is retrieved by a separate call, re-draw the advantage line because it needs to
// adjust to new boat positions
@@ -1297,254 +1324,268 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
private final StringBuilder leewardStartLineMarkToFirstMarkLineText = new StringBuilder();
private void showStartLineToFirstMarkTriangle(final CoursePositionsDTO courseDTO){
if (settings.getHelpLinesSettings().isVisible(HelpLineTypes.STARTLINETOFIRSTMARKTRIANGLE)
&& courseDTO.startMarkPositions.size() > 1 && courseDTO.waypointPositions.size() > 1) {
LatLng windwardStartLinePoint = coordinateSystem.toLatLng(courseDTO.startMarkPositions.get(0));
LatLng leewardStartLinePoint = coordinateSystem.toLatLng(courseDTO.startMarkPositions.get(1));
LatLng firstMarkPoint = coordinateSystem.toLatLng(courseDTO.waypointPositions.get(1));
windwardStartLineMarkToFirstMarkLineText.replace(0, windwardStartLineMarkToFirstMarkLineText.length(),
stringMessages.startLineToFirstMarkTriangle(numberFormatOneDecimal
.format(courseDTO.startMarkPositions.get(0).getDistance(courseDTO.waypointPositions.get(1))
.getMeters())));
leewardStartLineMarkToFirstMarkLineText.replace(0, leewardStartLineMarkToFirstMarkLineText.length(),
stringMessages.startLineToFirstMarkTriangle(numberFormatOneDecimal
.format(courseDTO.startMarkPositions.get(1).getDistance(courseDTO.waypointPositions.get(1))
.getMeters())));
if (windwardStartLineMarkToFirstMarkLine == null && leewardStartLineMarkToFirstMarkLine == null) {
PolylineOptions options = PolylineOptions.newInstance();
options.setGeodesic(true);
options.setStrokeColor("grey");
options.setStrokeWeight(1);
options.setStrokeOpacity(1.0);
MVCArray<LatLng> windwardLinePoints = MVCArray.newInstance();
windwardLinePoints.insertAt(0, windwardStartLinePoint);
windwardLinePoints.insertAt(1, firstMarkPoint);
MVCArray<LatLng> leewardLinePoints = MVCArray.newInstance();
leewardLinePoints.insertAt(0, leewardStartLinePoint);
leewardLinePoints.insertAt(1, firstMarkPoint);
windwardStartLineMarkToFirstMarkLine = Polyline.newInstance(options);
windwardStartLineMarkToFirstMarkLine.setPath(windwardLinePoints);
windwardStartLineMarkToFirstMarkLine.addMouseOverHandler(new MouseOverMapHandler() {
@Override
public void onEvent(MouseOverMapEvent event) {
map.setTitle(windwardStartLineMarkToFirstMarkLineText.toString());
}
});
windwardStartLineMarkToFirstMarkLine.addMouseOutMoveHandler(new MouseOutMapHandler() {
@Override
public void onEvent(MouseOutMapEvent event) {
map.setTitle("");
}
});
leewardStartLineMarkToFirstMarkLine = Polyline.newInstance(options);
leewardStartLineMarkToFirstMarkLine.setPath(leewardLinePoints);
leewardStartLineMarkToFirstMarkLine.addMouseOverHandler(new MouseOverMapHandler() {
@Override
public void onEvent(MouseOverMapEvent event) {
map.setTitle(leewardStartLineMarkToFirstMarkLineText.toString());
}
});
leewardStartLineMarkToFirstMarkLine.addMouseOutMoveHandler(new MouseOutMapHandler() {
@Override
public void onEvent(MouseOutMapEvent event) {
map.setTitle("");
}
});
windwardStartLineMarkToFirstMarkLine.setMap(map);
leewardStartLineMarkToFirstMarkLine.setMap(map);
} else {
windwardStartLineMarkToFirstMarkLine.getPath().removeAt(1);
windwardStartLineMarkToFirstMarkLine.getPath().removeAt(0);
windwardStartLineMarkToFirstMarkLine.getPath().insertAt(0, windwardStartLinePoint);
windwardStartLineMarkToFirstMarkLine.getPath().insertAt(1, firstMarkPoint);
leewardStartLineMarkToFirstMarkLine.getPath().removeAt(1);
leewardStartLineMarkToFirstMarkLine.getPath().removeAt(0);
leewardStartLineMarkToFirstMarkLine.getPath().insertAt(0, leewardStartLinePoint);
leewardStartLineMarkToFirstMarkLine.getPath().insertAt(1, firstMarkPoint);
final List<Position> startMarkPositions = courseDTO.getStartMarkPositions();
final Position windwardStartLinePosition = startMarkPositions.get(0);
final Position leewardStartLinePosition = startMarkPositions.get(1);
final Position firstMarkPosition = courseDTO.waypointPositions.get(1);
windwardStartLineMarkToFirstMarkLineText.replace(0, windwardStartLineMarkToFirstMarkLineText.length(),
stringMessages.startLineToFirstMarkTriangle(numberFormatOneDecimal
.format(windwardStartLinePosition.getDistance(firstMarkPosition)
.getMeters())));
leewardStartLineMarkToFirstMarkLineText.replace(0, leewardStartLineMarkToFirstMarkLineText.length(),
stringMessages.startLineToFirstMarkTriangle(numberFormatOneDecimal
.format(leewardStartLinePosition.getDistance(firstMarkPosition)
.getMeters())));
final LineInfoProvider windwardStartLineMarkToFirstMarkLineInfoProvider = new LineInfoProvider() {
@Override
public String getLineInfo() {
return windwardStartLineMarkToFirstMarkLineText.toString();
}
} else {
if (windwardStartLineMarkToFirstMarkLine != null) {
windwardStartLineMarkToFirstMarkLine.setMap(null);
windwardStartLineMarkToFirstMarkLine = null;
};
final LineInfoProvider leewardStartLineMarkToFirstMarkLineInfoProvider = new LineInfoProvider() {
@Override
public String getLineInfo() {
return leewardStartLineMarkToFirstMarkLineText.toString();
}
if (leewardStartLineMarkToFirstMarkLine != null) {
leewardStartLineMarkToFirstMarkLine.setMap(null);
leewardStartLineMarkToFirstMarkLine = null;
}
}
};
windwardStartLineMarkToFirstMarkLine = showOrRemoveOrUpdateLine(windwardStartLineMarkToFirstMarkLine, /* showLine */
(settings.getHelpLinesSettings().isVisible(HelpLineTypes.STARTLINETOFIRSTMARKTRIANGLE))
&& startMarkPositions.size() > 1 && courseDTO.waypointPositions.size() > 1,
windwardStartLinePosition, firstMarkPosition, windwardStartLineMarkToFirstMarkLineInfoProvider,
"grey");
leewardStartLineMarkToFirstMarkLine = showOrRemoveOrUpdateLine(leewardStartLineMarkToFirstMarkLine, /* showLine */
(settings.getHelpLinesSettings().isVisible(HelpLineTypes.STARTLINETOFIRSTMARKTRIANGLE))
&& startMarkPositions.size() > 1 && courseDTO.waypointPositions.size() > 1,
leewardStartLinePosition, firstMarkPosition, leewardStartLineMarkToFirstMarkLineInfoProvider,
"grey");
}
private final StringBuilder startLineAdvantageText = new StringBuilder();
private final StringBuilder finishLineAdvantageText = new StringBuilder();
final LineInfoProvider startLineInfoProvider = new LineInfoProvider() {
@Override
public String getLineInfo() {
return stringMessages.startLine()+startLineAdvantageText;
}
};
final LineInfoProvider finishLineInfoProvider = new LineInfoProvider() {
@Override
public String getLineInfo() {
return stringMessages.finishLine()+finishLineAdvantageText;
}
};
private void showStartAndFinishLines(final CoursePositionsDTO courseDTO) {
if (map != null && courseDTO != null && lastRaceTimesInfo != null) {
private void showStartAndFinishAndCourseMiddleLines(final CoursePositionsDTO courseDTO) {
if (map != null && courseDTO != null && courseDTO.course != null && courseDTO.course.waypoints != null &&
!courseDTO.course.waypoints.isEmpty()) {
com.sap.sse.common.Util.Pair<Integer, CompetitorDTO> leadingVisibleCompetitorInfo = getFarthestAheadVisibleCompetitorWithOneBasedLegNumber(getCompetitorsToShow());
int legOfLeadingCompetitor = leadingVisibleCompetitorInfo == null ? -1 : leadingVisibleCompetitorInfo.getA();
int numberOfLegs = lastRaceTimesInfo.legInfos.size();
int oneBasedLegOfLeadingCompetitor = leadingVisibleCompetitorInfo == null ? -1 : leadingVisibleCompetitorInfo.getA();
int numberOfLegs = courseDTO.course.waypoints.size()-1;
// draw the start line
updateCountdownCanvas(courseDTO.startMarkPositions);
if (legOfLeadingCompetitor <= 1 &&
settings.getHelpLinesSettings().isVisible(HelpLineTypes.STARTLINE) && courseDTO.startMarkPositions != null && courseDTO.startMarkPositions.size() == 2) {
LatLng startLinePoint1 = coordinateSystem.toLatLng(courseDTO.startMarkPositions.get(0));
LatLng startLinePoint2 = coordinateSystem.toLatLng(courseDTO.startMarkPositions.get(1));
if (courseDTO.startLineAngleToCombinedWind != null) {
startLineAdvantageText.replace(0, startLineAdvantageText.length(), " "+stringMessages.lineAngleToWindAndAdvantage(
NumberFormat.getFormat("0.0").format(courseDTO.startLineLengthInMeters),
NumberFormat.getFormat("0.0").format(Math.abs(courseDTO.startLineAngleToCombinedWind)),
courseDTO.startLineAdvantageousSide.name().charAt(0)+courseDTO.startLineAdvantageousSide.name().substring(1).toLowerCase(),
NumberFormat.getFormat("0.0").format(courseDTO.startLineAdvantageInMeters)));
} else {
startLineAdvantageText.delete(0, startLineAdvantageText.length());
}
if (startLine == null) {
PolylineOptions options = PolylineOptions.newInstance();
options.setClickable(true);
options.setGeodesic(true);
options.setStrokeColor("#FFFFFF");
options.setStrokeWeight(1);
options.setStrokeOpacity(1.0);
MVCArray<LatLng> pointsAsArray = MVCArray.newInstance();
pointsAsArray.insertAt(0, startLinePoint1);
pointsAsArray.insertAt(1, startLinePoint2);
startLine = Polyline.newInstance(options);
startLine.setPath(pointsAsArray);
startLine.addMouseOverHandler(new MouseOverMapHandler() {
@Override
public void onEvent(MouseOverMapEvent event) {
map.setTitle(stringMessages.startLine()+startLineAdvantageText);
}
});
startLine.addMouseOutMoveHandler(new MouseOutMapHandler() {
@Override
public void onEvent(MouseOutMapEvent event) {
map.setTitle("");
}
});
startLine.setMap(map);
} else {
startLine.getPath().removeAt(1);
startLine.getPath().removeAt(0);
startLine.getPath().insertAt(0, startLinePoint1);
startLine.getPath().insertAt(1, startLinePoint2);
}
final WaypointDTO startWaypoint = courseDTO.course.waypoints.get(0);
updateCountdownCanvas(startWaypoint);
final Position startLineLeftPosition = courseDTO.getStartMarkPositions().get(0);
final Position startLineRightPosition = courseDTO.getStartMarkPositions().get(1);
if (courseDTO.startLineAngleToCombinedWind != null) {
startLineAdvantageText.replace(0, startLineAdvantageText.length(), " "+stringMessages.lineAngleToWindAndAdvantage(
NumberFormat.getFormat("0.0").format(courseDTO.startLineLengthInMeters),
NumberFormat.getFormat("0.0").format(Math.abs(courseDTO.startLineAngleToCombinedWind)),
courseDTO.startLineAdvantageousSide.name().charAt(0)+courseDTO.startLineAdvantageousSide.name().substring(1).toLowerCase(),
NumberFormat.getFormat("0.0").format(courseDTO.startLineAdvantageInMeters)));
} else {
if (startLine != null) {
startLine.setMap(null);
startLine = null;
}
startLineAdvantageText.delete(0, startLineAdvantageText.length());
}
startLine = showOrRemoveOrUpdateLine(startLine, /* showLine */ courseDTO.getStartMarkPositions() != null &&
courseDTO.getStartMarkPositions().size() == 2 &&
((oneBasedLegOfLeadingCompetitor <= 1 &&
settings.getHelpLinesSettings().isVisible(HelpLineTypes.STARTLINE)) ||
settings.getHelpLinesSettings().isVisible(HelpLineTypes.COURSEGEOMETRY)),
startLineLeftPosition, startLineRightPosition, startLineInfoProvider, "#ffffff");
// TODO bug3027: show SmallTransparentInfoOverlay in addition to tooltip if course geometry option is true; remove it if option is false
// TODO bug3027: show *all* course middle lines if course geometry option is true
// draw the finish line
if (legOfLeadingCompetitor > 0 && legOfLeadingCompetitor == numberOfLegs &&
settings.getHelpLinesSettings().isVisible(HelpLineTypes.FINISHLINE) && courseDTO.finishMarkPositions != null && courseDTO.finishMarkPositions.size() == 2) {
LatLng finishLinePoint1 = coordinateSystem.toLatLng(courseDTO.finishMarkPositions.get(0));
LatLng finishLinePoint2 = coordinateSystem.toLatLng(courseDTO.finishMarkPositions.get(1));
if (courseDTO.startLineAngleToCombinedWind != null) {
finishLineAdvantageText.replace(0, finishLineAdvantageText.length(), " "+stringMessages.lineAngleToWindAndAdvantage(
NumberFormat.getFormat("0.0").format(courseDTO.finishLineLengthInMeters),
NumberFormat.getFormat("0.0").format(Math.abs(courseDTO.finishLineAngleToCombinedWind)),
courseDTO.finishLineAdvantageousSide.name().charAt(0)+courseDTO.finishLineAdvantageousSide.name().substring(1).toLowerCase(),
NumberFormat.getFormat("0.0").format(courseDTO.finishLineAdvantageInMeters)));
} else {
finishLineAdvantageText.delete(0, finishLineAdvantageText.length());
}
if (finishLine == null) {
PolylineOptions options = PolylineOptions.newInstance();
options.setClickable(true);
options.setGeodesic(true);
options.setStrokeColor("#000000");
options.setStrokeWeight(1);
options.setStrokeOpacity(1.0);
MVCArray<LatLng> pointsAsArray = MVCArray.newInstance();
pointsAsArray.insertAt(0, finishLinePoint1);
pointsAsArray.insertAt(1, finishLinePoint2);
finishLine = Polyline.newInstance(options);
finishLine.setPath(pointsAsArray);
finishLine.addMouseOverHandler(new MouseOverMapHandler() {
@Override
public void onEvent(MouseOverMapEvent event) {
map.setTitle(stringMessages.finishLine()+finishLineAdvantageText);
}
});
finishLine.addMouseOutMoveHandler(new MouseOutMapHandler() {
@Override
public void onEvent(MouseOutMapEvent event) {
map.setTitle("");
}
});
finishLine.setMap(map);
} else {
finishLine.getPath().removeAt(1);
finishLine.getPath().removeAt(0);
finishLine.getPath().insertAt(0, finishLinePoint1);
finishLine.getPath().insertAt(1, finishLinePoint2);
}
final Position finishLineLeftPosition = courseDTO.getFinishMarkPositions().get(0);
final Position finishLineRightPosition = courseDTO.getFinishMarkPositions().get(1);
if (courseDTO.startLineAngleToCombinedWind != null) {
finishLineAdvantageText.replace(0, finishLineAdvantageText.length(), " "+stringMessages.lineAngleToWindAndAdvantage(
NumberFormat.getFormat("0.0").format(courseDTO.finishLineLengthInMeters),
NumberFormat.getFormat("0.0").format(Math.abs(courseDTO.finishLineAngleToCombinedWind)),
courseDTO.finishLineAdvantageousSide.name().charAt(0)+courseDTO.finishLineAdvantageousSide.name().substring(1).toLowerCase(),
NumberFormat.getFormat("0.0").format(courseDTO.finishLineAdvantageInMeters)));
} else {
finishLineAdvantageText.delete(0, finishLineAdvantageText.length());
}
else {
if (finishLine != null) {
finishLine.setMap(null);
finishLine = null;
}
finishLine = showOrRemoveOrUpdateLine(finishLine, /* showLine */ courseDTO.getFinishMarkPositions() != null && courseDTO.getFinishMarkPositions().size() == 2 &&
(oneBasedLegOfLeadingCompetitor > 0 && oneBasedLegOfLeadingCompetitor == numberOfLegs && settings.getHelpLinesSettings().isVisible(HelpLineTypes.FINISHLINE))
|| settings.getHelpLinesSettings().isVisible(HelpLineTypes.COURSEGEOMETRY),
finishLineLeftPosition, finishLineRightPosition, finishLineInfoProvider, "#000000");
// the control point pairs for which we already decided whether or not
// to show a course middle line for; values tell whether to show the line and for which zero-based
// start waypoint index to do so; when for an equal control point pair multiple decisions with different
// outcome are made, a decision to show the line overrules the decision to not show it (OR-semantics)
final Map<Set<ControlPointDTO>, Pair<Boolean, Integer>> keysAlreadyHandled = new HashMap<>();
for (int zeroBasedIndexOfStartWaypoint = 0; zeroBasedIndexOfStartWaypoint<courseDTO.waypointPositions.size()-1; zeroBasedIndexOfStartWaypoint++) {
final Set<ControlPointDTO> key = getCourseMiddleLinesKey(courseDTO, zeroBasedIndexOfStartWaypoint);
boolean showCourseMiddleLine = keysAlreadyHandled.containsKey(key) && keysAlreadyHandled.get(key).getA() ||
settings.getHelpLinesSettings().isVisible(HelpLineTypes.COURSEGEOMETRY) ||
(settings.getHelpLinesSettings().isVisible(HelpLineTypes.COURSEMIDDLELINE)
&& oneBasedLegOfLeadingCompetitor > 0
&& oneBasedLegOfLeadingCompetitor-1 == zeroBasedIndexOfStartWaypoint);
keysAlreadyHandled.put(key, new Pair<>(showCourseMiddleLine, zeroBasedIndexOfStartWaypoint));
}
// draw the course middle line
if (legOfLeadingCompetitor > 0 && courseDTO.waypointPositions.size() > legOfLeadingCompetitor &&
settings.getHelpLinesSettings().isVisible(HelpLineTypes.COURSEMIDDLELINE)) {
Position position1DTO = courseDTO.waypointPositions.get(legOfLeadingCompetitor-1);
Position position2DTO = courseDTO.waypointPositions.get(legOfLeadingCompetitor);
LatLng courseMiddleLinePoint1 = coordinateSystem.toLatLng(position1DTO);
LatLng courseMiddleLinePoint2 = coordinateSystem.toLatLng(position2DTO);
if (courseMiddleLine == null) {
PolylineOptions options = PolylineOptions.newInstance();
options.setClickable(true);
options.setGeodesic(true);
options.setStrokeColor("#2268a0");
options.setStrokeWeight(1);
options.setStrokeOpacity(1.0);
MVCArray<LatLng> pointsAsArray = MVCArray.newInstance();
pointsAsArray.insertAt(0, courseMiddleLinePoint1);
pointsAsArray.insertAt(1, courseMiddleLinePoint2);
courseMiddleLine = Polyline.newInstance(options);
courseMiddleLine.setPath(pointsAsArray);
courseMiddleLine.addMouseOverHandler(new MouseOverMapHandler() {
@Override
public void onEvent(MouseOverMapEvent event) {
map.setTitle(stringMessages.courseMiddleLine());
}
});
courseMiddleLine.addMouseOutMoveHandler(new MouseOutMapHandler() {
@Override
public void onEvent(MouseOutMapEvent event) {
map.setTitle("");
}
});
courseMiddleLine.setMap(map);
} else {
courseMiddleLine.getPath().removeAt(1);
courseMiddleLine.getPath().removeAt(0);
courseMiddleLine.getPath().insertAt(0, courseMiddleLinePoint1);
courseMiddleLine.getPath().insertAt(1, courseMiddleLinePoint2);
}
Set<Set<ControlPointDTO>> keysToConsider = new HashSet<>(keysAlreadyHandled.keySet());
keysToConsider.addAll(courseMiddleLines.keySet());
for (final Set<ControlPointDTO> key : keysToConsider) {
final int zeroBasedIndexOfStartWaypoint = keysAlreadyHandled.containsKey(key) ?
keysAlreadyHandled.get(key).getB() : 0; // if not handled, the line will be removed, so the waypoint index doesn't matter
final Pair<Boolean, Integer> showLineAndZeroBasedIndexOfStartWaypoint = keysAlreadyHandled.get(key);
final boolean showCourseMiddleLine = showLineAndZeroBasedIndexOfStartWaypoint != null && showLineAndZeroBasedIndexOfStartWaypoint.getA();
courseMiddleLines.put(key, showOrRemoveCourseMiddleLine(courseDTO, courseMiddleLines.get(key), zeroBasedIndexOfStartWaypoint, showCourseMiddleLine));
}
else {
if (courseMiddleLine != null) {
courseMiddleLine.setMap(null);
courseMiddleLine = null;
}
}
/**
* Given a zero-based index into <code>courseDTO</code>'s {@link RaceCourseDTO#waypoints waypoints list} that denotes the start
* waypoint of the leg in question, returns a key that can be used for the {@link #courseMiddleLines} map, consisting of a set
* that holds the two {@link ControlPointDTO}s representing the start and finish control point of that leg.
*/
private Set<ControlPointDTO> getCourseMiddleLinesKey(final CoursePositionsDTO courseDTO,
final int zeroBasedIndexOfStartWaypoint) {
ControlPointDTO startControlPoint = courseDTO.course.waypoints.get(zeroBasedIndexOfStartWaypoint).controlPoint;
ControlPointDTO endControlPoint = courseDTO.course.waypoints.get(zeroBasedIndexOfStartWaypoint+1).controlPoint;
final Set<ControlPointDTO> key = new HashSet<>();
key.add(startControlPoint);
key.add(endControlPoint);
return key;
}
/**
* @param showLine
* tells whether or not to show the line; if the <code>lineToShowOrRemoveOrUpdate</code> references a
* line but the line shall not be shown, the line is removed from the map; conversely, if the line is not
* yet shown but shall be, a new line is created, added to the map and returned. If the line is shown and
* shall continue to be shown, the line is returned after updating its vertex coordinates.
* @return <code>null</code> if the line is not shown; the polyline object representing the line being displayed
* otherwise
*/
private Polyline showOrRemoveCourseMiddleLine(final CoursePositionsDTO courseDTO, Polyline lineToShowOrRemoveOrUpdate,
final int zeroBasedIndexOfStartWaypoint, final boolean showLine) {
final Position position1DTO = courseDTO.waypointPositions.get(zeroBasedIndexOfStartWaypoint);
final Position position2DTO = courseDTO.waypointPositions.get(zeroBasedIndexOfStartWaypoint+1);
final LineInfoProvider lineInfoProvider = new LineInfoProvider() {
@Override
public String getLineInfo() {
final StringBuilder sb = new StringBuilder();
sb.append(stringMessages.courseMiddleLine());
sb.append('\n');
sb.append(NumberFormat.getFormat("0").format(
Math.abs(position1DTO.getDistance(position2DTO).getMeters()))+stringMessages.metersUnit());
if (lastCombinedWindTrackInfoDTO != null) {
final WindTrackInfoDTO windTrackAtLegMiddle = lastCombinedWindTrackInfoDTO.getCombinedWindOnLegMiddle(zeroBasedIndexOfStartWaypoint);
if (windTrackAtLegMiddle != null && windTrackAtLegMiddle.windFixes != null && !windTrackAtLegMiddle.windFixes.isEmpty()) {
WindDTO windAtLegMiddle = windTrackAtLegMiddle.windFixes.get(0);
final double legBearingDeg = position1DTO.getBearingGreatCircle(position2DTO).getDegrees();
final String diff = NumberFormat.getFormat("0.0").format(
Math.min(Math.abs(windAtLegMiddle.dampenedTrueWindBearingDeg-legBearingDeg),
Math.abs(windAtLegMiddle.dampenedTrueWindFromDeg-legBearingDeg)));
sb.append(", ");
sb.append(stringMessages.degreesToWind(diff));
}
}
return sb.toString();
}
};
return showOrRemoveOrUpdateLine(lineToShowOrRemoveOrUpdate, showLine, position1DTO, position2DTO, lineInfoProvider, "#2268a0");
}
private interface LineInfoProvider {
String getLineInfo();
}
/**
* @param showLine
* tells whether or not to show the line; if the <code>lineToShowOrRemoveOrUpdate</code> references a
* line but the line shall not be shown, the line is removed from the map; conversely, if the line is not
* yet shown but shall be, a new line is created, added to the map and returned. If the line is shown and
* shall continue to be shown, the line is returned after updating its vertex coordinates.
* @return <code>null</code> if the line is not shown; the polyline object representing the line being displayed
* otherwise
*/
private Polyline showOrRemoveOrUpdateLine(Polyline lineToShowOrRemoveOrUpdate, final boolean showLine,
final Position position1DTO, final Position position2DTO, final LineInfoProvider lineInfoProvider, String lineColorRGB) {
if (showLine) {
LatLng courseMiddleLinePoint1 = coordinateSystem.toLatLng(position1DTO);
LatLng courseMiddleLinePoint2 = coordinateSystem.toLatLng(position2DTO);
final MVCArray<LatLng> pointsAsArray;
if (lineToShowOrRemoveOrUpdate == null) {
PolylineOptions options = PolylineOptions.newInstance();
options.setClickable(true);
options.setGeodesic(true);
options.setStrokeColor(lineColorRGB);
options.setStrokeWeight(1);
options.setStrokeOpacity(1.0);
pointsAsArray = MVCArray.newInstance();
lineToShowOrRemoveOrUpdate = Polyline.newInstance(options);
lineToShowOrRemoveOrUpdate.setPath(pointsAsArray);
lineToShowOrRemoveOrUpdate.addMouseOverHandler(new MouseOverMapHandler() {
@Override
public void onEvent(MouseOverMapEvent event) {
map.setTitle(lineInfoProvider.getLineInfo());
}
});
lineToShowOrRemoveOrUpdate.addMouseOutMoveHandler(new MouseOutMapHandler() {
@Override
public void onEvent(MouseOutMapEvent event) {
map.setTitle("");
}
});
lineToShowOrRemoveOrUpdate.setMap(map);
} else {
pointsAsArray = lineToShowOrRemoveOrUpdate.getPath();
pointsAsArray.removeAt(1);
pointsAsArray.removeAt(0);
}
adjustInfoOverlayForVisibleLine(lineToShowOrRemoveOrUpdate, position1DTO, position2DTO, lineInfoProvider);
pointsAsArray.insertAt(0, courseMiddleLinePoint1);
pointsAsArray.insertAt(1, courseMiddleLinePoint2);
} else {
if (lineToShowOrRemoveOrUpdate != null) {
lineToShowOrRemoveOrUpdate.setMap(null);
adjustInfoOverlayForRemovedLine(lineToShowOrRemoveOrUpdate);
lineToShowOrRemoveOrUpdate = null;
}
}
return lineToShowOrRemoveOrUpdate;
}
private void adjustInfoOverlayForRemovedLine(Polyline lineToShowOrRemoveOrUpdate) {
SmallTransparentInfoOverlay infoOverlay = infoOverlaysForLinesForCourseGeometry.remove(lineToShowOrRemoveOrUpdate);
if (infoOverlay != null) {
infoOverlay.removeFromMap();
}
}
private void adjustInfoOverlayForVisibleLine(Polyline lineToShowOrRemoveOrUpdate, final Position position1DTO,
final Position position2DTO, final LineInfoProvider lineInfoProvider) {
SmallTransparentInfoOverlay infoOverlay = infoOverlaysForLinesForCourseGeometry.get(lineToShowOrRemoveOrUpdate);
if (getSettings().getHelpLinesSettings().isVisible(HelpLineTypes.COURSEGEOMETRY)) {
if (infoOverlay == null) {
infoOverlay = new SmallTransparentInfoOverlay(map, RaceMapOverlaysZIndexes.INFO_OVERLAY_ZINDEX, lineInfoProvider.getLineInfo(), coordinateSystem);
infoOverlaysForLinesForCourseGeometry.put(lineToShowOrRemoveOrUpdate, infoOverlay);
infoOverlay.addToMap();
} else {
infoOverlay.setInfoText(lineInfoProvider.getLineInfo());
}
infoOverlay.setPosition(position1DTO.translateGreatCircle(position1DTO.getBearingGreatCircle(position2DTO),
position1DTO.getDistance(position2DTO).scale(0.5)), /* transition time */ -1);
infoOverlay.draw();
} else {
if (infoOverlay != null) {
infoOverlay.removeFromMap();
infoOverlaysForLinesForCourseGeometry.remove(lineToShowOrRemoveOrUpdate);
}
}
}
@@ -1554,9 +1595,9 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
* still in the pre-start phase, show a {@link SmallTransparentInfoOverlay} at the
* start line that shows the count down.
*/
private void updateCountdownCanvas(List<Position> startMarkPositions) {
if (!settings.isShowSelectedCompetitorsInfo() || startMarkPositions == null || startMarkPositions.isEmpty()
|| lastRaceTimesInfo.startOfRace == null || timer.getTime().after(lastRaceTimesInfo.startOfRace)) {
private void updateCountdownCanvas(WaypointDTO startWaypoint) {
if (!settings.isShowSelectedCompetitorsInfo() || startWaypoint == null || Util.isEmpty(startWaypoint.controlPoint.getMarks())
|| lastRaceTimesInfo == null || lastRaceTimesInfo.startOfRace == null || timer.getTime().after(lastRaceTimesInfo.startOfRace)) {
if (countDownOverlay != null) {
countDownOverlay.removeFromMap();
countDownOverlay = null;
@@ -1572,7 +1613,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
} else {
countDownOverlay.setInfoText(countDownText);
}
countDownOverlay.setPosition(startMarkPositions.get(startMarkPositions.size() - 1), -1);
countDownOverlay.setPosition(startWaypoint.controlPoint.getMarks().iterator().next().position, /* transition time */ -1);
countDownOverlay.draw();
}
}
@@ -1610,7 +1651,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|| !BoundsUtil.contains((currentMapBounds = map.getBounds()), newBounds)
|| graticuleAreaRatio(currentMapBounds, newBounds) > 10) {
// only change bounds if the new bounds don't fit into the current map zoom
List<ZoomTypes> oldZoomSettings = settings.getZoomSettings().getTypesToConsiderOnZoom();
Iterable<ZoomTypes> oldZoomSettings = settings.getZoomSettings().getTypesToConsiderOnZoom();
setAutoZoomInProgress(true);
autoZoomLatLngBounds = newBounds;
int newZoomLevel = getZoomLevel(autoZoomLatLngBounds);
@@ -2358,8 +2399,8 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
}
@Override
public void initializeData(boolean showMapControls) {
loadMapsAPIV3(showMapControls);
public void initializeData(boolean showMapControls, boolean showHeaderPanel) {
loadMapsAPIV3(showMapControls, showHeaderPanel);
}
@Override
@@ -1,16 +1,18 @@
package com.sap.sailing.gwt.ui.client.shared.racemap;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import com.sap.sse.common.Util;
public class RaceMapHelpLinesSettings {
/**
* Types of help lines on the map
*/
public enum HelpLineTypes {
STARTLINE, FINISHLINE, ADVANTAGELINE, COURSEMIDDLELINE, BUOYZONE, BOATTAILS, STARTLINETOFIRSTMARKTRIANGLE
STARTLINE, FINISHLINE, ADVANTAGELINE, COURSEMIDDLELINE, BUOYZONE, BOATTAILS, STARTLINETOFIRSTMARKTRIANGLE, COURSEGEOMETRY
}
private final Set<HelpLineTypes> visibleHelpLines;
@@ -27,14 +29,19 @@ public class RaceMapHelpLinesSettings {
visibleHelpLines.add(HelpLineTypes.BOATTAILS);
}
public RaceMapHelpLinesSettings(Collection<HelpLineTypes> visibleHelpLines) {
this.visibleHelpLines = new HashSet<HelpLineTypes>(visibleHelpLines);
public RaceMapHelpLinesSettings(Iterable<HelpLineTypes> visibleHelpLines) {
this.visibleHelpLines = new HashSet<>();
Util.addAll(visibleHelpLines, this.visibleHelpLines);
}
public boolean isVisible(HelpLineTypes helpLineType) {
return visibleHelpLines.contains(helpLineType);
}
public Iterable<HelpLineTypes> getVisibleHelpLineTypes() {
return Collections.unmodifiableCollection(visibleHelpLines);
}
@Override
public int hashCode() {
final int prime = 31;
@@ -47,6 +47,23 @@ public class RaceMapSettings extends AbstractSettings {
this.helpLinesSettings = new RaceMapHelpLinesSettings();
}
/**
* "Copy constructor" that produces a new settings object that equals the one passed as argument
*/
public RaceMapSettings(RaceMapSettings settings) {
this.buoyZoneRadiusInMeters = settings.buoyZoneRadiusInMeters;
this.helpLinesSettings = new RaceMapHelpLinesSettings(settings.getHelpLinesSettings().getVisibleHelpLineTypes());
this.maneuverTypesToShow = settings.maneuverTypesToShow;
this.showDouglasPeuckerPoints = settings.showDouglasPeuckerPoints;
this.showOnlySelectedCompetitors = settings.showOnlySelectedCompetitors;
this.showSelectedCompetitorsInfo = settings.showSelectedCompetitorsInfo;
this.showSimulationOverlay = settings.showSimulationOverlay;
this.showWindStreamletOverlay = settings.showWindStreamletOverlay;
this.tailLengthInMilliseconds = settings.tailLengthInMilliseconds;
this.windUp = settings.windUp;
this.zoomSettings = new RaceMapZoomSettings(settings.zoomSettings.getTypesToConsiderOnZoom(), settings.zoomSettings.isZoomToSelectedCompetitors());
}
/**
* @return 0 if the tails are not visible {@link #getTailLengthInMilliseconds()} otherwise
*/
@@ -98,7 +98,7 @@ public class RaceMapSettingsDialogComponent implements SettingsDialogComponent<R
for (ZoomTypes zoomType : ZoomTypes.values()) {
if (zoomType != ZoomTypes.NONE) {
CheckBox cb = dialog.createCheckbox(RaceMapSettingsTypeFormatter.formatZoomType(zoomType, stringMessages));
cb.setValue(initialSettings.getZoomSettings().getTypesToConsiderOnZoom().contains(zoomType), false);
cb.setValue(Util.contains(initialSettings.getZoomSettings().getTypesToConsiderOnZoom(), zoomType), false);
checkboxAndZoomType.add(new Util.Pair<CheckBox, ZoomTypes>(cb, zoomType));
zoomSettingsBoxesPanel.add(cb);
@@ -195,6 +195,7 @@ public class RaceMapSettingsDialogComponent implements SettingsDialogComponent<R
vp.add(createHelpLineCheckBox(dialog, HelpLineTypes.ADVANTAGELINE));
vp.add(createHelpLineCheckBox(dialog, HelpLineTypes.COURSEMIDDLELINE));
vp.add(createHelpLineCheckBox(dialog, HelpLineTypes.STARTLINETOFIRSTMARKTRIANGLE));
vp.add(createHelpLineCheckBox(dialog, HelpLineTypes.COURSEGEOMETRY));
return vp;
}
@@ -37,6 +37,8 @@ public class RaceMapSettingsTypeFormatter {
return stringConstants.boatTails();
case STARTLINETOFIRSTMARKTRIANGLE:
return stringConstants.startFirstMarkTriangle();
case COURSEGEOMETRY:
return stringConstants.courseGeometry();
}
return null;
}
@@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.List;
import com.google.gwt.maps.client.base.LatLngBounds;
import com.sap.sse.common.Util;
/**
* @author Lennart Hensler (D054527)
@@ -29,7 +30,7 @@ public class RaceMapZoomSettings {
}
};
private ArrayList<ZoomTypes> typesToConsiderOnZoom;
private Iterable<ZoomTypes> typesToConsiderOnZoom;
private boolean zoomToSelectedCompetitors;
/**
@@ -37,13 +38,14 @@ public class RaceMapZoomSettings {
* The attribute <code>zoomToSelectedCompetitors</code> will be <code>false</code>.
*/
public RaceMapZoomSettings() {
typesToConsiderOnZoom = new ArrayList<ZoomTypes>();
final List<ZoomTypes> myTypesToConsiderOnZoom = new ArrayList<>();
typesToConsiderOnZoom = myTypesToConsiderOnZoom;
// Other zoom types such as BOATS, TAILS or WINDSENSORS are not currently used as default zoom types.
typesToConsiderOnZoom.add(ZoomTypes.BUOYS);
myTypesToConsiderOnZoom.add(ZoomTypes.BUOYS);
zoomToSelectedCompetitors = false;
}
public RaceMapZoomSettings(ArrayList<ZoomTypes> typesToConsiderOnZoom, boolean zoomToSelected) {
public RaceMapZoomSettings(Iterable<ZoomTypes> typesToConsiderOnZoom, boolean zoomToSelected) {
this.typesToConsiderOnZoom = typesToConsiderOnZoom;
this.zoomToSelectedCompetitors = zoomToSelected;
}
@@ -67,12 +69,14 @@ public class RaceMapZoomSettings {
return newBounds;
}
public List<ZoomTypes> getTypesToConsiderOnZoom() {
public Iterable<ZoomTypes> getTypesToConsiderOnZoom() {
return typesToConsiderOnZoom;
}
public void setTypesToConsiderOnZoom(List<ZoomTypes> typesToConsiderOnZoom) {
this.typesToConsiderOnZoom = new ArrayList<ZoomTypes>(typesToConsiderOnZoom);
public void setTypesToConsiderOnZoom(Iterable<ZoomTypes> typesToConsiderOnZoom) {
List<ZoomTypes> newTypesToConsiderOnZoom = new ArrayList<>();
Util.addAll(typesToConsiderOnZoom, newTypesToConsiderOnZoom);
this.typesToConsiderOnZoom = newTypesToConsiderOnZoom;
}
public void setZoomToSelectedCompetitors(boolean zoomToSelectedCompetitors) {
@@ -84,7 +88,7 @@ public class RaceMapZoomSettings {
}
public boolean containsZoomType(ZoomTypes zoomType) {
return typesToConsiderOnZoom.contains(zoomType);
return Util.contains(typesToConsiderOnZoom, zoomType);
}
@Override
@@ -42,32 +42,45 @@ public class SmallTransparentInfoOverlay extends CanvasOverlayV3 {
infoBoxWidth = 20;
infoBoxHeight = 20;
cornerRadius = 4;
if (getCanvas() != null) {
getCanvas().setWidth(String.valueOf(canvasWidth));
getCanvas().setHeight(String.valueOf(canvasHeight));
getCanvas().setCoordinateSpaceWidth(canvasWidth);
getCanvas().setCoordinateSpaceHeight(canvasHeight);
}
// setCanvasSize(canvasWidth, canvasHeight);
}
@Override
protected void draw() {
final int LINE_SPACING = 3;
final int BOTTOM_MARGIN = 8;
final int LEFT_MARGIN = 8;
final int RIGHT_MARGIN = 9;
final int POLE_LENGTH = 25;
if (mapProjection != null && position != null) {
LatLng latLngPosition = coordinateSystem.toLatLng(position);
Context2d context2d = getCanvas().getContext2d();
CssColor grayTransparentColor = CssColor.make("rgba(255,255,255,0.75)");
context2d.setFont("12px bold Verdana sans-serif");
TextMetrics measureText = context2d.measureText(infoText);
double textWidth = measureText.getWidth();
canvasWidth = (int) textWidth + 17;
final int fontSizeInPx = 12+2*Math.max(0, map.getZoom()-15);
final int LINE_HEIGHT = fontSizeInPx+LINE_SPACING;
context2d.setFont(""+fontSizeInPx+"px Roboto, Arial, sans-serif");
// context2d.setFont(""+fontSizeInPx+"px bold Verdana sans-serif");
double textWidth = 0;
infoBoxHeight = BOTTOM_MARGIN;
for (final String line : infoText.split("\n")) {
TextMetrics measureText = context2d.measureText(line);
if (measureText.getWidth() > textWidth) {
textWidth = measureText.getWidth();
}
infoBoxHeight += LINE_HEIGHT;
}
canvasWidth = (int) textWidth + LEFT_MARGIN + RIGHT_MARGIN;
infoBoxWidth = canvasWidth;
canvasHeight = infoBoxHeight + POLE_LENGTH;
getCanvas().setWidth(String.valueOf(canvasWidth));
getCanvas().setCoordinateSpaceWidth(canvasWidth);
getCanvas().setHeight(String.valueOf(canvasHeight));
getCanvas().setCoordinateSpaceHeight(canvasHeight);
// Change origin and dimensions to match true size (a stroke makes the shape a bit larger)
context2d.setFillStyle(grayTransparentColor);
@@ -86,7 +99,13 @@ public class SmallTransparentInfoOverlay extends CanvasOverlayV3 {
context2d.beginPath();
context2d.setFillStyle("black");
context2d.fillText(infoText, 8, 14);
// context2d.setFont(""+fontSizeInPx+"px bold Verdana sans-serif");
context2d.setFont(""+fontSizeInPx+"px Roboto, Arial, sans-serif");
int y = LINE_HEIGHT;
for (final String line : infoText.split("\n")) {
context2d.fillText(line, LEFT_MARGIN, y);
y += LINE_HEIGHT;
}
context2d.stroke();
Point objectPositionInPx = mapProjection.fromLatLngToDivPixel(latLngPosition);
@@ -0,0 +1,216 @@
package com.sap.sailing.gwt.ui.raceboard;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.maps.client.MapWidget;
import com.google.gwt.maps.client.controls.ControlPosition;
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.DockLayoutPanel;
import com.google.gwt.user.client.ui.DockLayoutPanel.Direction;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootLayoutPanel;
import com.sap.sailing.domain.common.LeaderboardNameConstants;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.gwt.ui.client.AbstractSailingEntryPoint;
import com.sap.sailing.gwt.ui.client.CompetitorSelectionModel;
import com.sap.sailing.gwt.ui.client.CompetitorSelectionProvider;
import com.sap.sailing.gwt.ui.client.LogoAndTitlePanel;
import com.sap.sailing.gwt.ui.client.RaceSelectionModel;
import com.sap.sailing.gwt.ui.client.TimePanel;
import com.sap.sailing.gwt.ui.client.TimePanelSettings;
import com.sap.sailing.gwt.ui.client.shared.charts.WindChart;
import com.sap.sailing.gwt.ui.client.shared.charts.WindChartSettings;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMap;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapHelpLinesSettings;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapHelpLinesSettings.HelpLineTypes;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapResources;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapSettings;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapZoomSettings;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapZoomSettings.ZoomTypes;
import com.sap.sailing.gwt.ui.shared.EventDTO;
import com.sap.sse.common.Duration;
import com.sap.sse.common.Util;
import com.sap.sse.common.filter.Filter;
import com.sap.sse.common.filter.FilterSet;
import com.sap.sse.gwt.client.async.AsyncActionsExecutor;
import com.sap.sse.gwt.client.player.TimeRangeWithZoomModel;
import com.sap.sse.gwt.client.player.TimeRangeWithZoomProvider;
import com.sap.sse.gwt.client.player.Timer;
import com.sap.sse.gwt.client.player.Timer.PlayModes;
import com.sap.sse.gwt.shared.GwtHttpRequestUtils;
public class EmbeddedMapAndWindChartEntryPoint extends AbstractSailingEntryPoint {
private static final String PARAM_REGATTA_LIKE_NAME = "regattaLikeName";
private static final String PARAM_RACE_COLUMN_NAME = "raceColumnName";
private static final String PARAM_FLEET_NAME = "fleetName";
private static final String PARAM_EVENT_ID = "eventId";
private String regattaLikeName;
private String raceColumnName;
private String fleetName;
private UUID eventId;
private static final RaceMapResources raceMapResources = GWT.create(RaceMapResources.class);
private static final int DEFAULT_WIND_CHART_HEIGHT = 200;
@Override
protected void doOnModuleLoad() {
super.doOnModuleLoad();
// read mandatory parameters
regattaLikeName = Window.Location.getParameter(PARAM_REGATTA_LIKE_NAME);
raceColumnName = Window.Location.getParameter(PARAM_RACE_COLUMN_NAME);
fleetName = Window.Location.getParameter(PARAM_FLEET_NAME);
String eventIdParamValue = Window.Location.getParameter(PARAM_EVENT_ID);
if (eventIdParamValue != null && !eventIdParamValue.isEmpty()) {
eventId = UUID.fromString(eventIdParamValue);
}
if (regattaLikeName == null || regattaLikeName.isEmpty() || raceColumnName == null || raceColumnName.isEmpty() ||
fleetName == null || fleetName.isEmpty()) {
createErrorPage("This page requires a valid regatta, race column and fleet name to identify the race to show.");
return;
}
// read optional parameters
final boolean showWindChart = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_WINDCHART, true /* default*/);
final boolean showViewStreamlets = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_STREAMLETS, false /* default*/);
final boolean showViewSimulation = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_SIMULATION, true /* default*/);
final boolean showMapControls = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_MAPCONTROLS, true /* default*/);
if (eventId != null) {
sailingService.getEventById(eventId, /* withStatisticalData */ false, new AsyncCallback<EventDTO>() {
@Override
public void onSuccess(EventDTO eventDTO) {
checkUrlParameters(eventDTO, showWindChart, showMapControls, showViewStreamlets, showViewSimulation);
}
@Override
public void onFailure(Throwable t) {
reportError("Error trying to create the raceboard: " + t.getMessage());
}
});
} else {
checkUrlParameters(/* event */ null, showWindChart, showMapControls, showViewStreamlets, showViewSimulation);
}
}
private void createErrorPage(String message) {
final DockLayoutPanel vp = new DockLayoutPanel(Unit.PX);
LogoAndTitlePanel logoAndTitlePanel = new LogoAndTitlePanel(getStringMessages(), this, getUserService());
logoAndTitlePanel.addStyleName("LogoAndTitlePanel");
RootLayoutPanel.get().add(vp);
vp.addNorth(logoAndTitlePanel, 100);
vp.add(new Label(message));
}
private void checkUrlParameters(final EventDTO event, final boolean showWindChart,
final boolean showMapControls, final boolean showViewStreamlets, final boolean showViewSimulation) {
if (eventId != null && event == null) {
createErrorPage(getStringMessages().noSuchEvent());
}
sailingService.getRaceIdentifier(regattaLikeName, raceColumnName, fleetName, new AsyncCallback<RegattaAndRaceIdentifier>() {
@Override
public void onFailure(Throwable caught) {
createErrorPage("Could not obtain a race with name " + raceColumnName + " for fleet "+fleetName+" for a regatta with name " + regattaLikeName+
": "+caught.getMessage());
}
@Override
public void onSuccess(final RegattaAndRaceIdentifier selectedRaceIdentifier) {
if (selectedRaceIdentifier == null) {
createErrorPage("Could not obtain a race with name " + raceColumnName + " for fleet "+fleetName+" for a regatta with name " + regattaLikeName);
} else {
final StringBuilder title = new StringBuilder(regattaLikeName);
title.append('/');
title.append(raceColumnName);
if (!fleetName.equals(LeaderboardNameConstants.DEFAULT_FLEET_NAME)) {
title.append('/');
title.append(fleetName);
}
Window.setTitle(title.toString());
final RaceSelectionModel raceSelectionModel = new RaceSelectionModel();
final List<RegattaAndRaceIdentifier> raceList = Collections.singletonList(selectedRaceIdentifier);
raceSelectionModel.setSelection(raceList);
final long refreshInterval = Duration.ONE_SECOND.times(3).asMillis();
final Timer timer = new Timer(PlayModes.Live);
AsyncActionsExecutor asyncActionsExecutor = new AsyncActionsExecutor();
final TimeRangeWithZoomProvider timeRangeWithZoomProvider = new TimeRangeWithZoomModel();
// Use a TimePanel to manage wind chart zoom, although the TimePanel itself is not being displayed;
// let the time panel always return to "live" mode if the user wants that
final TimePanel<TimePanelSettings> timePanel = new TimePanel<TimePanelSettings>(
timer, timeRangeWithZoomProvider, getStringMessages(), /* canReplayWhileLive */ false) {
protected boolean isLiveModeToBeMadePossible() {
return true;
}
};
final Button backToLivePlayButton = timePanel.getBackToLiveButton();
final TimePanelSettings timePanelSettings = timePanel.getSettings();
timePanelSettings.setRefreshInterval(refreshInterval);
timePanel.updateSettings(timePanelSettings);
raceMapResources.combinedWindPanelStyle().ensureInjected();
final CompetitorSelectionProvider competitorSelection = createEmptyFilterCompetitorModel(); // show no competitors
final RaceMap raceMap = new RaceMap(sailingService, asyncActionsExecutor, /* errorReporter */ EmbeddedMapAndWindChartEntryPoint.this, timer,
competitorSelection, getStringMessages(), showMapControls, showViewStreamlets,
showViewSimulation, selectedRaceIdentifier, raceMapResources.combinedWindPanelStyle(), /* showHeaderPanel */ false) {
@Override
protected void showAdditionalControls(MapWidget map) {
backToLivePlayButton.removeFromParent();
map.setControls(ControlPosition.RIGHT_BOTTOM, backToLivePlayButton);
}
};
final RaceMapSettings mapSettings = new RaceMapSettings(raceMap.getSettings());
mapSettings.setZoomSettings(new RaceMapZoomSettings(Arrays.asList(ZoomTypes.BUOYS), /* zoom to selection */ false));
Set<HelpLineTypes> helpLineTypes = new HashSet<>();
Util.addAll(mapSettings.getHelpLinesSettings().getVisibleHelpLineTypes(), helpLineTypes);
helpLineTypes.add(HelpLineTypes.COURSEGEOMETRY);
mapSettings.setHelpLinesSettings(new RaceMapHelpLinesSettings(helpLineTypes));
mapSettings.setWindUp(true);
raceMap.updateSettings(mapSettings);
raceMap.onRaceSelectionChange(raceList);
final WindChart windChart;
if (showWindChart) {
windChart = new WindChart(sailingService, raceSelectionModel, timer,
timeRangeWithZoomProvider, new WindChartSettings(), getStringMessages(),
asyncActionsExecutor, /* errorReporter */
EmbeddedMapAndWindChartEntryPoint.this, /* compactChart */ true);
windChart.onRaceSelectionChange(raceList);
} else {
windChart = null;
}
createRaceBoardInOneScreenMode(raceMap, windChart);
}
}
});
}
private CompetitorSelectionProvider createEmptyFilterCompetitorModel() {
final CompetitorSelectionModel result = new CompetitorSelectionModel(/* hasMultiSelection */ true);
final FilterSet<CompetitorDTO, Filter<CompetitorDTO>> filterSet = result.getOrCreateCompetitorsFilterSet("Empty");
filterSet.addFilter(new Filter<CompetitorDTO>() {
@Override public boolean matches(CompetitorDTO object) { return false; }
@Override public String getName() { return "Never matching filter"; }
});
return result;
}
private void createRaceBoardInOneScreenMode(final RaceMap raceMap, final WindChart windChart) {
final TouchSplitLayoutPanel p = new TouchSplitLayoutPanel(/* horizontal splitter width */ 3, /* vertical splitter height */ 25);
RootLayoutPanel.get().add(p);
if (windChart != null) {
windChart.setVisible(true);
p.insert(windChart.getEntryWidget(), windChart, Direction.SOUTH, DEFAULT_WIND_CHART_HEIGHT);
p.setWidgetVisibility(windChart.getEntryWidget(), windChart, /* hidden */ false, DEFAULT_WIND_CHART_HEIGHT);
}
p.insert(raceMap.getEntryWidget(), raceMap, Direction.CENTER, 400);
p.addStyleName("dockLayoutPanel");
}
}
@@ -17,7 +17,6 @@ import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootLayoutPanel;
import com.google.gwt.user.client.ui.RootPanel;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.dto.RaceDTO;
import com.sap.sailing.gwt.ui.client.AbstractSailingEntryPoint;
@@ -138,10 +137,12 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
}
private void createErrorPage(String message) {
final DockLayoutPanel vp = new DockLayoutPanel(Unit.PX);
LogoAndTitlePanel logoAndTitlePanel = new LogoAndTitlePanel(getStringMessages(), this, getUserService());
logoAndTitlePanel.addStyleName("LogoAndTitlePanel");
RootPanel.get().add(logoAndTitlePanel);
RootPanel.get().add(new Label(message));
RootLayoutPanel.get().add(vp);
vp.addNorth(logoAndTitlePanel, 100);
vp.add(new Label(message));
}
private void checkUrlParameters(List<String> leaderboardNames, LeaderboardGroupDTO leaderboardGroup,
@@ -194,7 +195,6 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
RaceTimesInfoProvider raceTimesInfoProvider = new RaceTimesInfoProvider(sailingService, asyncActionsExecutor, this, singletonList, 5000l /* requestInterval*/);
RaceBoardPanel raceBoardPanel = new RaceBoardPanel(sailingService, mediaService, getUserService(), asyncActionsExecutor, timer, raceSelectionModel,
leaderboardName, leaderboardGroupName, event, raceboardViewConfig, RaceBoardEntryPoint.this, getStringMessages(), userAgent, raceTimesInfoProvider, showMapControls);
raceBoardPanel.fillRegattas(regattas);
createRaceBoardInOneScreenMode(raceBoardPanel, raceboardViewConfig);
}
@@ -35,7 +35,6 @@ import com.sap.sailing.gwt.ui.client.RaceSelectionChangeListener;
import com.sap.sailing.gwt.ui.client.RaceSelectionProvider;
import com.sap.sailing.gwt.ui.client.RaceTimePanel;
import com.sap.sailing.gwt.ui.client.RaceTimesInfoProvider;
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.sailing.gwt.ui.client.media.MediaPlayerManagerComponent;
@@ -54,7 +53,6 @@ import com.sap.sailing.gwt.ui.leaderboard.LeaderboardPanel;
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardSettings;
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardSettingsFactory;
import com.sap.sailing.gwt.ui.shared.EventDTO;
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
import com.sap.sse.common.filter.FilterSet;
import com.sap.sse.common.settings.AbstractSettings;
import com.sap.sse.gwt.client.ErrorReporter;
@@ -77,7 +75,7 @@ import com.sap.sse.security.ui.client.UserService;
* @author Frank Mittag, Axel Uhl (d043530)
*
*/
public class RaceBoardPanel extends SimplePanel implements RegattasDisplayer, RaceSelectionChangeListener, LeaderboardUpdateListener, PopupPositionProvider {
public class RaceBoardPanel extends SimplePanel implements RaceSelectionChangeListener, LeaderboardUpdateListener, PopupPositionProvider {
private final SailingServiceAsync sailingService;
private final MediaServiceAsync mediaService;
private final EventDTO event;
@@ -86,11 +84,6 @@ public class RaceBoardPanel extends SimplePanel implements RegattasDisplayer, Ra
private final RaceBoardViewConfiguration raceboardViewConfiguration;
private String raceBoardName;
/**
* Updated upon each {@link #fillRegattas(List)}
*/
private final Map<RaceIdentifier, RaceDTO> racesByIdentifier;
private final List<ComponentViewer> componentViewers;
private RaceTimePanel timePanel;
private final Timer timer;
@@ -146,7 +139,6 @@ public class RaceBoardPanel extends SimplePanel implements RegattasDisplayer, Ra
this.currentRaceHasBeenSelectedOnce = false;
this.leaderboardName = leaderboardName;
raceSelectionProvider.addRaceSelectionChangeListener(this);
racesByIdentifier = new HashMap<RaceIdentifier, RaceDTO>();
selectedRaceIdentifier = raceSelectionProvider.getSelectedRaces().iterator().next();
this.setRaceBoardName(selectedRaceIdentifier.getRaceName());
this.asyncActionsExecutor = asyncActionsExecutor;
@@ -163,7 +155,8 @@ public class RaceBoardPanel extends SimplePanel implements RegattasDisplayer, Ra
raceMapResources.combinedWindPanelStyle().ensureInjected();
raceMap = new RaceMap(sailingService, asyncActionsExecutor, errorReporter, timer,
competitorSelectionModel, stringMessages, showMapControls, getConfiguration().isShowViewStreamlets(), getConfiguration().isShowViewSimulation(), selectedRaceIdentifier, raceMapResources.combinedWindPanelStyle());
competitorSelectionModel, stringMessages, showMapControls, getConfiguration().isShowViewStreamlets(), getConfiguration().isShowViewSimulation(),
selectedRaceIdentifier, raceMapResources.combinedWindPanelStyle(), /* showHeaderPanel */ true);
CompetitorFilterPanel competitorSearchTextBox = new CompetitorFilterPanel(competitorSelectionModel, stringMessages, raceMap,
new LeaderboardFetcher() {
@Override
@@ -336,18 +329,6 @@ public class RaceBoardPanel extends SimplePanel implements RegattasDisplayer, Ra
return errorReporter;
}
@Override
public void fillRegattas(Iterable<RegattaDTO> regattas) {
racesByIdentifier.clear();
for (RegattaDTO regatta : regattas) {
for (RaceDTO race : regatta.races) {
if (race != null && race.getRaceIdentifier() != null) {
racesByIdentifier.put(race.getRaceIdentifier(), race);
}
}
}
}
@Override
public void onRaceSelectionChange(List<RegattaAndRaceIdentifier> selectedRaces) {
}
@@ -772,7 +772,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
private MarkDTO convertToMarkDTO(Mark mark, Position position) {
MarkDTO markDTO;
if(position != null) {
if (position != null) {
markDTO = new MarkDTO(mark.getId().toString(), mark.getName(), position.getLatDeg(), position.getLngDeg());
} else {
markDTO = new MarkDTO(mark.getId().toString(), mark.getName());
@@ -902,7 +902,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
CourseBase lastCourse = state.getCourseDesign();
if (lastCourse != null) {
raceInfoDTO.lastCourseDesign = convertCourseDesignToRaceCourseDTO(lastCourse);
raceInfoDTO.lastCourseDesign = convertToRaceCourseDTO(lastCourse, /* trackedRace */ null, /* timePoint */ null);
raceInfoDTO.lastCourseName = lastCourse.getName();
}
@@ -952,20 +952,6 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
raceInfoDTO.startProcedureDTO = info;
}
private RaceCourseDTO convertCourseDesignToRaceCourseDTO(CourseBase lastCourseDesign) {
RaceCourseDTO result = new RaceCourseDTO(Collections.<WaypointDTO> emptyList());
if (lastCourseDesign != null) {
List<WaypointDTO> waypointDTOs = new ArrayList<WaypointDTO>();
for (Waypoint waypoint : lastCourseDesign.getWaypoints()) {
ControlPointDTO controlPointDTO = convertToControlPointDTO(waypoint.getControlPoint());
WaypointDTO waypointDTO = new WaypointDTO(waypoint.getName(), controlPointDTO, waypoint.getPassingInstructions());
waypointDTOs.add(waypointDTO);
}
result = new RaceCourseDTO(waypointDTOs);
}
return result;
}
private List<RaceWithCompetitorsDTO> convertToRaceDTOs(Regatta regatta) {
List<RaceWithCompetitorsDTO> result = new ArrayList<RaceWithCompetitorsDTO>();
for (RaceDefinition r : regatta.getAllRaces()) {
@@ -1864,6 +1850,9 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
result.totalLegsCount = trackedRace.getRace().getCourse().getLegs().size();
result.currentLegNumber = trackedRace.getLastLegStarted(dateAsTimePoint);
result.marks = new HashSet<MarkDTO>();
result.course = convertToRaceCourseDTO(trackedRace.getRace().getCourse(), trackedRace, dateAsTimePoint);
// now make sure we don't duplicate the MarkDTO objects but instead use the ones from the RaceCourseDTO
// object and amend them with the Position
result.waypointPositions = new ArrayList<>();
Set<Mark> marks = new HashSet<Mark>();
Course course = trackedRace.getRace().getCourse();
@@ -1876,11 +1865,11 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
marks.add(b);
}
}
for (Mark mark : marks) {
GPSFixTrack<Mark, GPSFix> track = trackedRace.getOrCreateTrack(mark);
Position positionAtDate = track.getEstimatedPosition(dateAsTimePoint, /* extrapolate */false);
if (positionAtDate != null) {
result.marks.add(convertToMarkDTO(mark, positionAtDate));
for (final WaypointDTO waypointDTO : result.course.waypoints) {
for (final MarkDTO markDTO : waypointDTO.controlPoint.getMarks()) {
if (markDTO.position != null) {
result.marks.add(markDTO);
}
}
}
@@ -1889,8 +1878,6 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
if (firstWaypoint != null && Util.size(firstWaypoint.getMarks()) == 2) {
final LineDetails markPositionDTOsAndLineAdvantage = trackedRace.getStartLine(dateAsTimePoint);
if (markPositionDTOsAndLineAdvantage != null) {
final List<Position> startMarkPositionDTOs = getMarkPositionDTOs(dateAsTimePoint, trackedRace, firstWaypoint);
result.startMarkPositions = startMarkPositionDTOs;
result.startLineLengthInMeters = markPositionDTOsAndLineAdvantage.getLength().getMeters();
Bearing absoluteAngleDifferenceToTrueWind = markPositionDTOsAndLineAdvantage
.getAbsoluteAngleDifferenceToTrueWind();
@@ -1906,8 +1893,6 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
if (lastWaypoint != null && Util.size(lastWaypoint.getMarks()) == 2) {
final LineDetails markPositionDTOsAndLineAdvantage = trackedRace.getFinishLine(dateAsTimePoint);
if (markPositionDTOsAndLineAdvantage != null) {
final List<Position> finishMarkPositionDTOs = getMarkPositionDTOs(dateAsTimePoint, trackedRace, lastWaypoint);
result.finishMarkPositions = finishMarkPositionDTOs;
result.finishLineLengthInMeters = markPositionDTOsAndLineAdvantage.getLength().getMeters();
Bearing absoluteAngleDifferenceToTrueWind = markPositionDTOsAndLineAdvantage
.getAbsoluteAngleDifferenceToTrueWind();
@@ -1952,32 +1937,22 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
private ControlPointDTO convertToControlPointDTO(ControlPoint controlPoint, TrackedRace trackedRace, TimePoint timePoint) {
ControlPointDTO result;
final TimePoint timePointToUse = trackedRace == null ? null :
timePoint == null ? MillisecondsTimePoint.now().minus(trackedRace.getDelayToLiveInMillis()) : timePoint;
if (controlPoint instanceof ControlPointWithTwoMarks) {
final Mark left = ((ControlPointWithTwoMarks) controlPoint).getLeft();
final Position leftPos = trackedRace.getOrCreateTrack(left).getEstimatedPosition(timePoint, /* extrapolate */ false);
final Position leftPos = timePointToUse == null ? null : trackedRace.getOrCreateTrack(left).getEstimatedPosition(timePointToUse, /* extrapolate */ false);
final Mark right = ((ControlPointWithTwoMarks) controlPoint).getRight();
final Position rightPos = trackedRace.getOrCreateTrack(right).getEstimatedPosition(timePoint, /* extrapolate */ false);
final Position rightPos = timePointToUse == null ? null : trackedRace.getOrCreateTrack(right).getEstimatedPosition(timePointToUse, /* extrapolate */ false);
result = new GateDTO(controlPoint.getId().toString(), controlPoint.getName(), convertToMarkDTO(left, leftPos), convertToMarkDTO(right, rightPos));
} else {
final Position posOfFirst = trackedRace.getOrCreateTrack(controlPoint.getMarks().iterator().next()).
getEstimatedPosition(timePoint, /* extrapolate */ false);
final Position posOfFirst = timePointToUse == null ? null : trackedRace.getOrCreateTrack(controlPoint.getMarks().iterator().next()).
getEstimatedPosition(timePointToUse, /* extrapolate */ false);
result = new MarkDTO(controlPoint.getId().toString(), controlPoint.getName(), posOfFirst == null ? -1 : posOfFirst.getLatDeg(), posOfFirst == null ? -1 : posOfFirst.getLngDeg());
}
return result;
}
private ControlPointDTO convertToControlPointDTO(ControlPoint controlPoint) {
ControlPointDTO result;
if (controlPoint instanceof ControlPointWithTwoMarks) {
final Mark left = ((ControlPointWithTwoMarks) controlPoint).getLeft();
final Mark right = ((ControlPointWithTwoMarks) controlPoint).getRight();
result = new GateDTO(controlPoint.getId().toString(), controlPoint.getName(), convertToMarkDTO(left, null), convertToMarkDTO(right, null));
} else {
result = new MarkDTO(controlPoint.getId().toString(), controlPoint.getName());
}
return result;
}
private ControlPoint getOrCreateControlPoint(ControlPointDTO dto) {
String idAsString = dto.getIdAsString();
if (idAsString == null) {
@@ -2017,19 +1992,6 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
}
}
private List<Position> getMarkPositionDTOs(
TimePoint timePoint, TrackedRace trackedRace, Waypoint waypoint) {
List<Position> markPositionDTOs = new ArrayList<>();
for (Mark startMark : waypoint.getMarks()) {
final Position estimatedMarkPosition = trackedRace.getOrCreateTrack(startMark)
.getEstimatedPosition(timePoint, /* extrapolate */false);
if (estimatedMarkPosition != null) {
markPositionDTOs.add(estimatedMarkPosition);
}
}
return markPositionDTOs;
}
/**
* @param timePoint
* <code>null</code> means "live" and is then replaced by "now" minus the tracked race's
@@ -5090,36 +5052,56 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
raceLog.add(event);
}
private WaypointDTO convertToWaypointDTO(Waypoint waypoint, Map<Serializable, ControlPointDTO> controlPointCache) {
/**
* @param trackedRace
* if <code>null</code>, no position data will be attached to the {@link MarkDTO}s
* @param timePoint
* if <code>trackedRace</code> is not <code>null</code>, specifies the time point for which to determine
* the mark positions and attach to the {@link MarkDTO}s. If <code>null<c/code>, the current time point
* will be used as default.
*/
private WaypointDTO convertToWaypointDTO(Waypoint waypoint, Map<Serializable, ControlPointDTO> controlPointCache, TrackedRace trackedRace, TimePoint timePoint) {
ControlPointDTO cp = controlPointCache.get(waypoint.getControlPoint().getId());
if (cp == null) {
cp = convertToControlPointDTO(waypoint.getControlPoint());
cp = convertToControlPointDTO(waypoint.getControlPoint(), trackedRace, timePoint);
controlPointCache.put(waypoint.getControlPoint().getId(), cp);
}
return new WaypointDTO(waypoint.getName(), cp, waypoint.getPassingInstructions());
}
private RaceCourseDTO convertToRaceCourseDTO(CourseBase course) {
List<WaypointDTO> waypointDTOs = new ArrayList<WaypointDTO>();
Map<Serializable, ControlPointDTO> controlPointCache = new HashMap<>();
RaceCourseDTO result = new RaceCourseDTO(waypointDTOs);
for (Waypoint waypoint : course.getWaypoints()) {
waypointDTOs.add(convertToWaypointDTO(waypoint, controlPointCache));
/**
* @param course
* the course to convert
* @param trackedRace
* if <code>null</code>, no position data will be attached to the {@link MarkDTO}s
* @param timePoint
* if <code>trackedRace</code> is not <code>null</code>, specifies the time point for which to determine
* the mark positions and attach to the {@link MarkDTO}s. If <code>null<c/code>, the current time point
* will be used as default.
*/
private RaceCourseDTO convertToRaceCourseDTO(CourseBase course, TrackedRace trackedRace, TimePoint timePoint) {
final RaceCourseDTO result;
if (course != null) {
List<WaypointDTO> waypointDTOs = new ArrayList<WaypointDTO>();
Map<Serializable, ControlPointDTO> controlPointCache = new HashMap<>();
for (Waypoint waypoint : course.getWaypoints()) {
waypointDTOs.add(convertToWaypointDTO(waypoint, controlPointCache, trackedRace, timePoint));
}
result = new RaceCourseDTO(waypointDTOs);
} else {
result = new RaceCourseDTO(Collections.<WaypointDTO> emptyList());
}
return result;
}
@Override
public RaceCourseDTO getLastCourseDefinitionInRaceLog(String leaderboardName, String raceColumnName,
String fleetName) {
public RaceCourseDTO getLastCourseDefinitionInRaceLog(String leaderboardName, String raceColumnName, String fleetName) {
RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName);
CourseBase lastPublishedCourse = new LastPublishedCourseDesignFinder(raceLog).analyze();
if (lastPublishedCourse == null) {
lastPublishedCourse = new CourseDataImpl("");
}
return convertToRaceCourseDTO(lastPublishedCourse);
return convertToRaceCourseDTO(lastPublishedCourse, /* trackedRace */ null, /* timePoint */ null);
}
@Override
@@ -5765,4 +5747,23 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
return true;
}
}
@Override
public RegattaAndRaceIdentifier getRaceIdentifier(String regattaLikeName, String raceColumnName, String fleetName) {
RegattaAndRaceIdentifier result = null;
final Leaderboard leaderboard = getService().getLeaderboardByName(regattaLikeName);
if (leaderboard != null) {
final RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName);
if (raceColumn != null) {
final Fleet fleet = raceColumn.getFleetByName(fleetName);
if (fleet != null) {
final TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
if (trackedRace != null) {
result = trackedRace.getRaceIdentifier();
}
}
}
}
return result;
}
}
@@ -1,5 +1,6 @@
package com.sap.sailing.gwt.ui.shared;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -8,9 +9,8 @@ import com.sap.sailing.domain.common.NauticalSide;
import com.sap.sailing.domain.common.Position;
public class CoursePositionsDTO implements IsSerializable {
public RaceCourseDTO course;
public List<Position> waypointPositions;
public List<Position> startMarkPositions;
public List<Position> finishMarkPositions;
public Set<MarkDTO> marks;
public int totalLegsCount;
@@ -35,4 +35,24 @@ public class CoursePositionsDTO implements IsSerializable {
public NauticalSide finishLineAdvantageousSide;
public Double finishLineAdvantageInMeters;
public Double finishLineLengthInMeters;
public List<Position> getStartMarkPositions() {
final List<Position> result = new ArrayList<>();
if (course != null && course.waypoints != null && !course.waypoints.isEmpty()) {
for (final MarkDTO mark : course.waypoints.get(0).controlPoint.getMarks()) {
result.add(mark.position);
}
}
return result;
}
public List<Position> getFinishMarkPositions() {
final List<Position> result = new ArrayList<>();
if (course != null && course.waypoints != null && !course.waypoints.isEmpty()) {
for (final MarkDTO mark : course.waypoints.get(course.waypoints.size()-1).controlPoint.getMarks()) {
result.add(mark.position);
}
}
return result;
}
}
@@ -27,4 +27,45 @@ public class GateDTO extends ControlPointDTO {
public Iterable<MarkDTO> getMarks() {
return Arrays.asList(left, right);
}
@Override
public int hashCode() {
final int prime = 31;
int result = prime * getIdAsString().hashCode() * getName().hashCode();
result = prime * result + ((left == null) ? 0 : left.hashCode());
result = prime * result + ((right == null) ? 0 : right.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (getClass() != obj.getClass())
return false;
GateDTO other = (GateDTO) obj;
if (getIdAsString() == null) {
if (other.getIdAsString() != null)
return false;
} else if (!getIdAsString().equals(other.getIdAsString()))
return false;
if (getName() == null) {
if (other.getName() != null)
return false;
} else if (!getName().equals(other.getName()))
return false;
if (left == null) {
if (other.left != null)
return false;
} else if (!left.equals(other.left))
return false;
if (right == null) {
if (other.right != null)
return false;
} else if (!right.equals(other.right))
return false;
return true;
}
}
@@ -3,6 +3,7 @@ package com.sap.sailing.gwt.ui.shared;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
@@ -21,7 +22,21 @@ public class RaceCourseDTO implements IsSerializable {
}
public RaceCourseDTO(List<WaypointDTO> waypoints) {
this(waypoints, null);
this(waypoints, getMarksFromWaypoints(waypoints));
}
private static List<MarkDTO> getMarksFromWaypoints(List<WaypointDTO> waypoints) {
final LinkedHashSet<MarkDTO> marks = new LinkedHashSet<>();
for (final WaypointDTO waypoint : waypoints) {
for (final MarkDTO m : waypoint.controlPoint.getMarks()) {
marks.add(m);
}
}
final List<MarkDTO> result = new ArrayList<>();
for (final MarkDTO m : marks) {
result.add(m);
}
return result;
}
public RaceCourseDTO(List<WaypointDTO> waypoints, List<MarkDTO> allMarks) {
@@ -360,7 +360,7 @@ public class SimulatorMap extends AbsolutePanel implements RequiresDataInitializ
this.replayPathCanvasOverlays = null;
this.raceCourseCanvasOverlay = null;
this.timeListeners = new LinkedList<TimeListenerWithStoppingCriteria>();
this.initializeData(showMapControls);
this.initializeData(showMapControls, /* showHeaderPanel */ true);
this.parent = parent;
}
@@ -1000,7 +1000,7 @@ public class SimulatorMap extends AbsolutePanel implements RequiresDataInitializ
}
@Override
public void initializeData(boolean showMapControls) {
public void initializeData(boolean showMapControls, boolean showHeaderPanel) {
loadMapsAPIV3();
}
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Could not determine the version of your GWT SDK; using the module DTD from GWT 1.6.4. You may want to change this. -->
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.7.0//EN" "http://gwtproject.org/doctype/2.7.0/gwt-module.dtd">
<module>
<inherits name='com.sap.sailing.gwt.ui.CommonConfigs'/>
<!-- Other module inherits -->
<inherits name="com.sap.sse.gwt.SSESharedGWT" />
<inherits name="com.sap.sse.SSECommon" />
<inherits name="com.sap.sailing.domain.SailingDomain" />
<inherits name="com.sap.sse.gwt.AdminConsole" />
<inherits name="com.sap.sse.security.ui.LoginPanel" />
<!-- Google Maps API -->
<inherits name='com.google.gwt.ajaxloader.AjaxLoader' />
<inherits name='com.google.gwt.maps.Maps' />
<!-- Highcharts API -->
<inherits name="com.sap.sse.gwt.Highcharts_Autoinject" />
<!-- Bootstrap API -->
<inherits name="com.github.gwtbootstrap.BootstrapNoResources" />
<inherits name='com.github.gwtbootstrap.datetimepicker.DatetimepickerNoResources' />
<!-- Specify the app entry point class. -->
<entry-point class='com.sap.sailing.gwt.ui.raceboard.EmbeddedMapAndWindChartEntryPoint'/>
<!-- Specify the paths for translatable code -->
<extend-property name="locale" values="de"/>
<extend-property name="locale" values="ru"/>
<inherits name='com.sap.sailing.gwt.ui.SourceCommon' />
<inherits name='com.sap.sailing.gwt.ui.SourceClient' />
<inherits name='com.sap.sailing.gwt.ui.SourceShared' />
<inherits name='com.sap.sailing.gwt.ui.SourceControl' />
<inherits name="com.sap.sailing.gwt.ui.SourceRaceboard"/>
<inherits name="com.sap.sailing.gwt.ui.SourceLeaderboard" />
<inherits name="com.sap.sailing.gwt.ui.SourceAdminConsole" />
<inherits name='com.sap.sse.gwt.CommonControlCSS_Autoinject'/>
</module>
@@ -43,7 +43,7 @@ public class Manage2SailEventResultsParserImpl implements Manage2SailEventResult
result.setName((String) jsonRoot.get("Name"));
result.setXrrUrl(parseURL(jsonRoot, "XrrUrl"));
JSONObject jsonTracking = (JSONObject) jsonRoot.get("Tracking");
if(jsonTracking != null) {
if (jsonTracking != null) {
result.setTrackingDataHost((String) jsonTracking.get("Host"));
result.setTrackingDataPort(parseInteger(jsonTracking, "Port"));
}
@@ -77,12 +77,16 @@ public class LeaderboardData extends ExportAction {
private static final String STRONG_WIND_DESCRIPTION = "Strong";
private static final String VERY_STRONG_WIND_DESCRIPTION = "Very Strong";
private final Map<RaceColumn, List<Competitor>> raceColumnToCompetitors;
public LeaderboardData(HttpServletRequest req, HttpServletResponse res, RacingEventService service) {
super(req, res, service);
this.raceColumnToCompetitors = new HashMap<>();
}
public LeaderboardData(Leaderboard leaderboard) {
super(leaderboard);
this.raceColumnToCompetitors = new HashMap<>();
}
/**
@@ -218,24 +222,36 @@ public class LeaderboardData extends ExportAction {
addNamedElementWithValue(raceElement, "same_day_index", sameDayGroupIndex);
addNamedElementWithValue(raceElement, "is_live", "false");
TimePoint timepointToBeUsed = MillisecondsTimePoint.now();
List<Competitor> competitorsForColumn = this.raceColumnToCompetitors.get(column);
if (competitorsForColumn == null) {
competitorsForColumn = new ArrayList<>();
}
List<Competitor> competitors = leaderboard.getCompetitorsFromBestToWorst(column, timepointToBeUsed);
for (Competitor competitorInLeaderboard : competitors) {
MaxPointsReason mpr = leaderboard.getScoreCorrection().getMaxPointsReason(competitorInLeaderboard, column, timepointToBeUsed);
if (mpr != null && !mpr.equals(MaxPointsReason.NONE)) {
// add this competitor to the list to have him evaluated
Element competitorElement = createCompetitorXML(competitorInLeaderboard, leaderboard, /*shortVersion*/ true, null);
Element competitorRaceDataElement = new Element("competitor_race_data");
MaxPointsReason maxPointsReason = leaderboard.getMaxPointsReason(competitorInLeaderboard, column, timepointToBeUsed);
addNamedElementWithValue(competitorRaceDataElement, "max_points_reason", maxPointsReason.toString());
boolean isDiscardedForCompetitor = leaderboard.isDiscarded(competitorInLeaderboard, column, timepointToBeUsed);
addNamedElementWithValue(competitorRaceDataElement, "is_discarded", isDiscardedForCompetitor == true ? "true" : "false");
Double finalRaceScore = leaderboard.getTotalPoints(competitorInLeaderboard, column, timepointToBeUsed);
addNamedElementWithValue(competitorRaceDataElement, "final_race_score", finalRaceScore);
competitorElement.addContent(competitorRaceDataElement);
raceElement.addContent(competitorElement);
raceConfidenceAndErrorMessages = updateConfidence("Competitor " + competitorInLeaderboard.getName() + " has no valid data for this race!", 0.2, raceConfidenceAndErrorMessages);
// we must keep track of competitors that we are associated to fleets
// in order to not export the score correction twice. This is needed
// because the score correction does not know about fleets and we do not
// know to which fleet the competitor belongs because no races are linked
if (!competitorsForColumn.contains(competitorInLeaderboard)) {
MaxPointsReason mpr = leaderboard.getScoreCorrection().getMaxPointsReason(competitorInLeaderboard, column, timepointToBeUsed);
if (mpr != null && !mpr.equals(MaxPointsReason.NONE)) {
// add this competitor to the list to have him evaluated
Element competitorElement = createCompetitorXML(competitorInLeaderboard, leaderboard, /*shortVersion*/ true, null);
Element competitorRaceDataElement = new Element("competitor_race_data");
MaxPointsReason maxPointsReason = leaderboard.getMaxPointsReason(competitorInLeaderboard, column, timepointToBeUsed);
addNamedElementWithValue(competitorRaceDataElement, "max_points_reason", maxPointsReason.toString());
boolean isDiscardedForCompetitor = leaderboard.isDiscarded(competitorInLeaderboard, column, timepointToBeUsed);
addNamedElementWithValue(competitorRaceDataElement, "is_discarded", isDiscardedForCompetitor == true ? "true" : "false");
Double finalRaceScore = leaderboard.getTotalPoints(competitorInLeaderboard, column, timepointToBeUsed);
addNamedElementWithValue(competitorRaceDataElement, "final_race_score", finalRaceScore);
competitorElement.addContent(competitorRaceDataElement);
raceElement.addContent(competitorElement);
raceConfidenceAndErrorMessages = updateConfidence("Competitor " + competitorInLeaderboard.getName() + " has no valid data for this race!", 0.2, raceConfidenceAndErrorMessages);
competitorsForColumn.add(competitorInLeaderboard);
}
}
}
this.raceColumnToCompetitors.put(column, competitorsForColumn);
return raceElement;
}
@@ -332,6 +348,10 @@ public class LeaderboardData extends ExportAction {
competitorToDistanceRank.put(competitorSorted, raceRankSorted);
}
List<Competitor> competitorsForColumn = this.raceColumnToCompetitors.get(column);
if (competitorsForColumn == null) {
competitorsForColumn = new ArrayList<>();
}
// it can happen that there are competitors that did not race but got points
int additionalCompetitorCount = 0;
for (Competitor competitorInLeaderboard : leaderboard.getAllCompetitors()) {
@@ -340,7 +360,7 @@ public class LeaderboardData extends ExportAction {
// check if he has an overwritten score for that race
MaxPointsReason mpr = leaderboard.getScoreCorrection().getMaxPointsReason(competitorInLeaderboard, column, race.getEndOfRace());
Fleet fleetCompetitorIsSailingIn = column.getFleetOfCompetitor(competitorInLeaderboard);
if (fleetCompetitorIsSailingIn != null && fleetCompetitorIsSailingIn.equals(fleet)) {
if (fleetCompetitorIsSailingIn != null && fleetCompetitorIsSailingIn.equals(fleet) && !competitorsForColumn.contains(competitorInLeaderboard)) {
if (mpr != null && !mpr.equals(MaxPointsReason.NONE)) {
// add this competitor to the list to have him evaluated
Element competitorElement = createCompetitorXML(competitorInLeaderboard, leaderboard, /*shortVersion*/ true, null);
@@ -355,6 +375,7 @@ public class LeaderboardData extends ExportAction {
raceElement.addContent(competitorElement);
raceConfidenceAndErrorMessages = updateConfidence("Competitor " + competitorInLeaderboard.getName() + " has no valid data for this race!", 0.2, raceConfidenceAndErrorMessages);
additionalCompetitorCount++;
competitorsForColumn.add(competitorInLeaderboard);
}
}
}
@@ -366,6 +387,9 @@ public class LeaderboardData extends ExportAction {
Element competitorElement = createCompetitorXML(competitor, leaderboard, /*shortVersion*/ true, null);
Element competitorRaceDataElement = new Element("competitor_race_data");
MaxPointsReason maxPointsReason = leaderboard.getMaxPointsReason(competitor, column, race.getEndOfRace());
if (maxPointsReason != null && !maxPointsReason.equals(MaxPointsReason.NONE)) {
competitorsForColumn.add(competitor);
}
addNamedElementWithValue(competitorRaceDataElement, "max_points_reason", maxPointsReason.toString());
boolean isDiscardedForCompetitor = leaderboard.isDiscarded(competitor, column, race.getEndOfRace());
addNamedElementWithValue(competitorRaceDataElement, "is_discarded", isDiscardedForCompetitor == true ? "true" : "false");
@@ -550,6 +574,7 @@ public class LeaderboardData extends ExportAction {
raceElement.addContent(competitorElement);
}
this.raceColumnToCompetitors.put(column, competitorsForColumn);
raceElement.addContent(createDataConfidenceXML(raceConfidenceAndErrorMessages));
raceElement.addContent(legs);
return raceElement;
@@ -45,6 +45,7 @@ import com.google.gwt.user.client.ui.FocusPanel;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.RequiresResize;
import com.sap.sse.common.Util;
/**
* A widget that allows the user to select a value within a range of possible values using a sliding bar that responds
@@ -704,9 +705,10 @@ public class SliderBar extends FocusPanel implements RequiresResize, HasValue<Do
* the current value
*/
public void setMaxValue(Double maxValue, boolean fireEvent) {
this.maxValue = maxValue;
drawTickLabels();
resetCurrentValue(fireEvent);
if (!Util.equalsWithNull(maxValue, this.maxValue)) {
this.maxValue = maxValue;
onMinMaxValueChanged(fireEvent);
}
}
/**
@@ -716,8 +718,40 @@ public class SliderBar extends FocusPanel implements RequiresResize, HasValue<Do
* the current value
*/
public void setMinValue(Double minValue, boolean fireEvent) {
this.minValue = minValue;
drawTickLabels();
if (!Util.equalsWithNull(minValue, this.minValue)) {
this.minValue = minValue;
onMinMaxValueChanged(fireEvent);
}
}
/**
* Set the minimum and maximum value
*
* @param minValue
* the current value for min
* @param maxValue
* the current valuefor max
*/
public void setMinAndMaxValue(Double minValue, Double maxValue, boolean fireEvent) {
boolean changed = false;
if (!Util.equalsWithNull(minValue, this.minValue)) {
this.minValue = minValue;
changed = true;
}
if (!Util.equalsWithNull(maxValue, this.maxValue)) {
this.maxValue = maxValue;
changed = true;
}
if (changed) {
onMinMaxValueChanged(fireEvent);
}
}
/**
* Handle value changes of min and/or max value
*/
protected void onMinMaxValueChanged(boolean fireEvent) {
redraw();
resetCurrentValue(fireEvent);
}
@@ -1037,6 +1071,7 @@ public class SliderBar extends FocusPanel implements RequiresResize, HasValue<Do
int lineWidth = lineElement.getOffsetWidth();
if (numMarkers > 0) {
Element lastMarkerLabel = null;
Marker lastMarker = null;
int lastMarkerLabelOffsetLeft = 0;
// Create the labels or make them visible
for (int i = 0; i < numMarkers; i++) {
@@ -1076,9 +1111,9 @@ public class SliderBar extends FocusPanel implements RequiresResize, HasValue<Do
// hide last marker label if it is too close to the one just created
if (lastMarkerLabelOffsetLeft > 0 && (labelLeftOffset-lastMarkerLabelOffsetLeft) <= 20) {
if (lastMarkerLabel != null) {
if (lastMarkerLabel != null && lastMarker != null) {
lastMarkerLabel.setPropertyString("className", "gwt-SliderBar-markerlabel-tooClose");
lastMarkerLabel.setPropertyString("innerHTML", "M"); // no space for more
lastMarkerLabel.setPropertyString("innerHTML", lastMarker.name); // no space for more
int currentMarkerOffsetLeft = labelLeftOffset;
try {
currentMarkerOffsetLeft = Integer.parseInt(markerElements.get(i).getStyle().getLeft().replace("px", ""));
@@ -1088,6 +1123,7 @@ public class SliderBar extends FocusPanel implements RequiresResize, HasValue<Do
lastMarkerLabel.getStyle().setLeft(currentMarkerOffsetLeft-8, Unit.PX);
}
}
lastMarker = marker;
lastMarkerLabel = label;
lastMarkerLabelOffsetLeft = labelLeftOffset;
}
@@ -3,12 +3,12 @@ package com.sap.sse.gwt.client.controls.slider;
import java.util.ArrayList;
import java.util.List;
import com.google.gwt.user.client.DOM;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.dom.client.Style.Visibility;
import com.google.gwt.user.client.DOM;
import com.sap.sse.gwt.client.controls.slider.TimeTicksCalculator.NormalizedInterval;
import com.sap.sse.gwt.client.controls.slider.TimeTicksCalculator.TickPosition;
@@ -182,7 +182,7 @@ public class TimeSlider extends SliderBar {
return;
Element knobElement = knobImage.getElement();
if(curValue >= minValue && curValue <= maxValue) {
if (curValue != null && minValue != null && maxValue != null && curValue >= minValue && curValue <= maxValue) {
// Move the knob to the correct position
int lineWidth = lineElement.getOffsetWidth();
int knobWidth = knobElement.getOffsetWidth();
@@ -199,21 +199,35 @@ public class TimeSlider extends SliderBar {
}
public void setMaxValue(Double maxValue, boolean fireEvent) {
if(!isZoomed) {
if (!isZoomed) {
super.setMaxValue(maxValue, fireEvent);
} else {
this.maxValue = maxValue;
}
calculateTicks();
}
public void setMinValue(Double minValue, boolean fireEvent) {
if(!isZoomed) {
public void setMinValue(Double minValue, boolean fireEvent) {
if (!isZoomed) {
super.setMinValue(minValue, fireEvent);
} else {
this.minValue = minValue;
}
}
@Override
public void setMinAndMaxValue(Double minValue, Double maxValue, boolean fireEvent) {
if (!isZoomed) {
super.setMinAndMaxValue(minValue, maxValue, fireEvent);
} else {
this.minValue = minValue;
this.maxValue = maxValue;
}
}
@Override
protected void onMinMaxValueChanged(boolean fireEvent) {
calculateTicks();
super.onMinMaxValueChanged(fireEvent);
}
public void setStepSize(double stepSize, boolean fireEvent) {
@@ -10,7 +10,7 @@
android:orientation="vertical">
<RelativeLayout
android:id="@+id/header"
android:id="@+id/header_layout"
android:layout_width="match_parent"
android:layout_height="@dimen/selector_header_height"
android:background="?sap_gray">
@@ -54,8 +54,9 @@
android:src="?wind_on"
android:visibility="gone"/>
<LinearLayout
<TextView
android:id="@+id/header_text"
android:drawableLeft="?chevron_left_24dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
@@ -65,28 +66,18 @@
android:layout_marginStart="@dimen/default_margin"
android:layout_toLeftOf="@id/wind_off"
android:layout_toStartOf="@id/wind_off"
android:orientation="horizontal">
android:layout_gravity="center_vertical"
android:orientation="horizontal"
android:text="@string/wind"
android:textAppearance="?textNormal" />
<ImageView
android:id="@+id/header_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="?chevron_left_24dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/wind"
android:textAppearance="?textNormal"/>
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:id="@+id/content_layout"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_below="@id/header"
android:layout_below="@id/header_layout"
android:background="?sap_gray_black_30"
android:orientation="vertical"
android:paddingLeft="@dimen/default_padding"
@@ -140,10 +131,11 @@
android:visibility="visible"/>
<com.sap.sailing.racecommittee.app.ui.views.CompassView
android:id="@+id/compassView"
android:id="@+id/compass_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"/>
</RelativeLayout>
<RelativeLayout
@@ -175,9 +167,14 @@
</RelativeLayout>
<RelativeLayout
android:id="@+id/layout_map"
android:id="@+id/layout_position"
android:layout_width="wrap_content"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:layout_marginEnd="@dimen/default_margin"
android:layout_marginLeft="@dimen/default_margin"
android:layout_marginRight="@dimen/default_margin"
android:layout_marginStart="@dimen/default_margin"
android:orientation="vertical">
<TextView
android:id="@+id/position_header"
@@ -189,77 +186,119 @@
android:textAppearance="?textSmall"/>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/position_header">
android:layout_below="@+id/position_header">
<FrameLayout
android:id="@+id/windMap"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout="@layout/welcome"/>
<RelativeLayout
android:id="@+id/address"
<TextView
android:id="@+id/position_latitude"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/default_margin"
android:background="?white"
android:orientation="horizontal"
android:visibility="gone"
tools:visibility="visible">
android:text="@string/wind_latitude"
android:textAppearance="?textSmall"/>
<ImageButton
android:id="@+id/address_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:background="@android:color/transparent"
android:padding="@dimen/default_padding_half"
android:src="?search_24dp_invert"/>
<EditText
android:id="@+id/address_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/default_margin_half"
android:layout_marginStart="@dimen/default_margin_half"
android:layout_toLeftOf="@id/address_search"
android:layout_toStartOf="@id/address_search"
android:hint="@string/wind_address_hint"
android:padding="@dimen/default_padding_half"
android:singleLine="true"
android:textAppearance="?textNormal"
android:textColor="?white_invert"
android:textColorHint="?sap_light_gray"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/dark_layer"
<TextView
android:id="@+id/position_longitude"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="wrap_content"
android:layout_margin="@dimen/default_margin"
android:layout_below="@+id/position_latitude"
android:text="@string/wind_longitude"
android:textAppearance="?textSmall"/>
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/constant_black_transparent"/>
<TextView
android:id="@+id/position_accuracy"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/default_margin"
android:layout_below="@+id/position_longitude"
android:text="@string/wind_accuracy"
android:textAppearance="?textSmall"/>
<Button
android:id="@+id/position_show"
style="?attr/buttonSolidNormal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/position_accuracy"
android:layout_centerHorizontal="true"
android:text="@string/wind_map_button_show"/>
<Button
android:id="@+id/enter_position"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="@drawable/button_border_light"
android:padding="@dimen/default_padding"
android:text="@string/wind_enter_position"
android:textAllCaps="true"
android:textAppearance="?textNormal"
android:textColor="?white"/>
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:id="@+id/map_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/content_layout"
android:visibility="gone">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<WebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<!-- the following layout is for a future implementation -->
<!--<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="horizontal"
android:visibility="gone">
<Button
style="?attr/buttonSolidNormal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Overall"/>
<Button
style="?attr/buttonSolidNormal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="#1"/>
<Button
style="?attr/buttonSolidNormal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="#2"/>
<Button
style="?attr/buttonSolidNormal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="#3"/>
</LinearLayout>-->
</LinearLayout>
<Button
android:id="@+id/position_hide"
style="?attr/buttonSolidNormal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_marginRight="@dimen/wind_hide_button_right_margin"
android:layout_marginEnd="@dimen/wind_hide_button_right_margin"
android:layout_marginTop="@dimen/wind_hide_button_top_margin"
android:text="@string/wind_map_button_hide"/>
</RelativeLayout>
</RelativeLayout>
@@ -430,10 +430,16 @@
<string name="error_finishing_time">Die ausgewählte Zeit is vor dem Rennstart. Bitte überprüfe die Uhrzeit.</string>
<string name="error_time_in_future">Die ausgewählte Zeit liegt in der Zukunft. Bitte überprüfe die Uhrzeit.</string>
<string name="error_wrong_race_state">Der RaceState hat nicht den korrekten Status (benötigt: %1$s - aktuell: %2$s)</string>
<string name="wind_map_button_show">Windkarte</string>
<string name="wind_map_button_hide">Schließen</string>
<string name="wind_latitude">Breite</string>
<string name="wind_longitude">Länge</string>
<string name="wind_accuracy">Genauigkeit</string>
<string name="dependent_races_absolute">Absolute Startzeit</string>
<string name="dependent_races_relative">Relative Startzeit</string>
<string name="dependent_races_prompt">Bitte Rennen auswählen</string>
<string name="minutes_after">Minuten nach</string>
<string name="minutes_after_long">%1$.0f Minuten nach %2$s</string>
<string name="wind_accuracy_ago">alt</string>
</resources>
@@ -48,6 +48,9 @@
<dimen name="bigger_over_flow_width">64dp</dimen>
<dimen name="bigger_over_flow_height">32dp</dimen>
<dimen name="wind_hide_button_right_margin">76dp</dimen>
<dimen name="wind_hide_button_top_margin">20dp</dimen>
<item name="picker_scale" format="float" type="integer">1.55</item>
@@ -450,10 +450,16 @@
<string name="error_finishing_time">The selected time is before the race start.</string>
<string name="error_time_in_future">The given time is in future. Please recheck the time.</string>
<string name="error_wrong_race_state">The RaceState isn\'t in the correct state (needed: %1$s - current: %2$s)</string>
<string name="wind_map_button_show">Wind Map</string>
<string name="wind_map_button_hide">Hide</string>
<string name="wind_latitude">Latitude</string>
<string name="wind_longitude">Longitude</string>
<string name="wind_accuracy">Accuracy</string>
<string name="dependent_races_absolute">Absolute Start Time</string>
<string name="dependent_races_relative">Relative Start Time</string>
<string name="dependent_races_prompt">Please select the race</string>
<string name="minutes_after">Minutes after</string>
<string name="minutes_after_long">%1$.0f Minutes after %2$s</string>
<string name="wind_accuracy_ago">ago</string>
</resources>
@@ -70,4 +70,7 @@ public class AppConstants {
public final static String INTENT_ACTION_SHOW_SUMMARY_CONTENT = PACKAGE_NAME + ".action.show.summary";
public final static String INTENT_ACTION_SHOW_PROTEST = PACKAGE_NAME + ".action.show.protest";
public final static String INTENT_ACTION_IS_TRACKING = PACKAGE_NAME + "action.is.tracking";
public final static String INTENT_ACTION_IS_TRACKING_EXTRA = PACKAGE_NAME + "action.is.tracking.extra";
}
@@ -47,8 +47,6 @@ import com.sap.sailing.racecommittee.app.ui.fragments.dialogs.ProtestTimeDialogF
import com.sap.sailing.racecommittee.app.utils.*;
import com.sap.sse.common.TimePoint;
import java.util.*;
public class RaceListFragment extends LoggableFragment implements OnItemClickListener, OnItemSelectedListener, TickListener, OnScrollListener {
private final static String TAG = RaceListFragment.class.getName();
@@ -1,33 +1,27 @@
package com.sap.sailing.racecommittee.app.ui.fragments.raceinfo;
import android.annotation.TargetApi;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
import android.location.Location;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.view.KeyEvent;
import android.os.Handler;
import android.support.v4.content.LocalBroadcastManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.widget.*;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMapClickListener;
import com.google.android.gms.maps.GoogleMap.OnMarkerDragListener;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.UiSettings;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.sap.sailing.android.shared.logging.ExLog;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.Position;
@@ -41,71 +35,61 @@ import com.sap.sailing.racecommittee.app.AppConstants;
import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.domain.ManagedRace;
import com.sap.sailing.racecommittee.app.services.polling.RacePositionsPoller;
import com.sap.sailing.racecommittee.app.ui.fragments.maps.WindMap;
import com.sap.sailing.racecommittee.app.ui.utils.OnRaceUpdatedListener;
import com.sap.sailing.racecommittee.app.ui.views.CompassView;
import com.sap.sailing.racecommittee.app.ui.views.CompassView.CompassDirectionListener;
import com.sap.sailing.racecommittee.app.utils.ThemeHelper;
import com.sap.sailing.racecommittee.app.utils.TimeUtils;
import com.sap.sailing.racecommittee.app.utils.WindHelper;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
public class WindFragment extends BaseFragment
implements CompassDirectionListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener,
OnClickListener, OnMarkerDragListener, OnMapClickListener, OnRaceUpdatedListener, TextView.OnEditorActionListener, OnMapReadyCallback,
WindMap.OnResumeCallback {
implements CompassDirectionListener,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener,
OnRaceUpdatedListener {
private final static String TAG = WindFragment.class.getName();
private final static String START_MODE = "startMode";
private final static int FIVE_SEC = 5000;
private final static int EVERY_POSITION_CHANGE = 0;
private final static long ONE_SEC = 1000;
private final static long FIVE_SEC = 5000;
private final static long EVERY_POSITION_CHANGE = 0;
private final static int MIN_KTS = 3;
private final static int MAX_KTS = 30;
private final static float MAX_LOCATION_DRIFT_IN_METER = 25f; // 25 meter
private final static long MAX_LOCATION_DRIFT_IN_MILLIS = 8 * 60 * 60 * 1000; // 8 hours
private Context mContext;
private View mHeaderLayout;
private View mContentLayout;
private View mMapLayout;
private View mHeader;
private View mLayoutDirection;
private View mLayoutSpeed;
private View mLayoutAddress;
private View mPositionHeader;
private View mDarkLayer;
private View mWindOn;
private View mWindOff;
private View mAddressSearch;
private View mSetData;
private View mSetPosition;
private CompassView mCompassView;
private NumberPicker mWindSpeed;
private Button mEnterPosition;
private EditText mAddressInput;
private TextView mWindSensor;
private WindMap mWindMap;
private GoogleMap mGoogleMap;
private TextView mHeaderText;
private TextView mHeaderWindSensor;
// private View mWindOn;
// private View mWindOff;
private Button mContentSetData;
private CompassView mContentCompassView;
private NumberPicker mContentWindSpeed;
private TextView mContentLatitude;
private TextView mContentLongitude;
private TextView mContentAccuracy;
private Button mContentMapShow;
private WebView mMapWebView;
private Button mMapHide;
private GoogleApiClient apiClient;
private LocationRequest locationRequest;
private Location mCurrentLocation;
private Handler mRefreshUIHandler;
private Runnable mRefreshUIRunnable;
private RacePositionsPoller positionPoller;
// stuff to save during rotation/ ect
private boolean bigMap = false;
public WindFragment() {
}
public static WindFragment newInstance(int startMode) {
WindFragment fragment = new WindFragment();
Bundle args = new Bundle();
@@ -114,20 +98,13 @@ public class WindFragment extends BaseFragment
return fragment;
}
protected static float round(float number, int precision) {
BigDecimal decimal = new BigDecimal(number);
BigDecimal round = decimal.setScale(precision, BigDecimal.ROUND_UP);
return round.floatValue();
}
/**
* creates the string array that represents the numbers in the windspeed numberpicker
* creates the string array that represents the numbers in the wind speed number picker
*
* @return
* @return numbers for wind speed number picker
*/
private String[] generateNumbers() {
ArrayList<String> numbers = new ArrayList<>();
for (float i = MIN_KTS; i <= MAX_KTS; i += .5f) {
numbers.add(String.format("%.1f %s", i, getString(R.string.wind_kn)));
}
@@ -138,126 +115,196 @@ public class WindFragment extends BaseFragment
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
apiClient = new GoogleApiClient.Builder(getActivity()).addApi(LocationServices.API).addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build();
// initialize the googleApiClient for location requests
apiClient = new GoogleApiClient.Builder(getActivity()).addApi(LocationServices.API).build();
// create runnable for ui refreshing
mRefreshUIRunnable = createUIRefreshRunnable();
//register receiver to be notified if race is tracked
IntentFilter filter = new IntentFilter(AppConstants.INTENT_ACTION_IS_TRACKING);
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(new IsTrackedReceiver(), filter);
}
private Runnable createUIRefreshRunnable() {
return new Runnable() {
@Override
public void run() {
refreshUI();
mRefreshUIHandler.postDelayed(this, ONE_SEC);
}
};
}
/**
* refresh location data labels and highlight missing or inaccuracy gps data
* disable mContentSetData button if gps data is missing or inaccurate
*/
private void refreshUI() {
if (mCurrentLocation != null) {
double latitude = mCurrentLocation.getLatitude();
double longitude = mCurrentLocation.getLongitude();
float accuracy = mCurrentLocation.getAccuracy();
long timeDifference = System.currentTimeMillis() - mCurrentLocation.getTime();
mContentLatitude.setText(String.format("%s: %.5f", getString(R.string.wind_latitude), latitude));
mContentLatitude.setTextColor(Color.BLACK);
mContentLongitude.setText(String.format("%s: %.5f", getString(R.string.wind_longitude), longitude));
mContentLongitude.setTextColor(Color.BLACK);
String timeFormatted = TimeUtils.formatTimeAgo(timeDifference) + " " + getString(R.string.wind_accuracy_ago);
mContentAccuracy.setText(String.format("%s: ~%.0fm\n(%s)", getString(R.string.wind_accuracy), mCurrentLocation.getAccuracy(), timeFormatted));
mContentSetData.setEnabled(timeDifference <= MAX_LOCATION_DRIFT_IN_MILLIS && accuracy <= MAX_LOCATION_DRIFT_IN_METER);
// highlight accuracy problem if location is invalid
mContentAccuracy.setTextColor(mContentSetData.isEnabled() ? Color.BLACK : Color.RED);
} else {
mContentSetData.setEnabled(false);
// highlight location problem if no location is available
mContentLatitude.setTextColor(Color.RED);
mContentLongitude.setTextColor(Color.RED);
mContentAccuracy.setTextColor(Color.RED);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View layout = inflater.inflate(R.layout.wind_view, container, false);
mContext = inflater.getContext();
// the fragment is divided into three layouts
// header layout is optional and is used for back navigation
// content layout holds wind direction, wind speed and location controls
// map layout holds a lazy web view for map presentation
mHeaderLayout = layout.findViewById(R.id.header_layout);
mContentLayout = layout.findViewById(R.id.content_layout);
mMapLayout = layout.findViewById(R.id.map_layout);
mHeader = layout.findViewById(R.id.header_text);
mDarkLayer = layout.findViewById(R.id.dark_layer);
mLayoutDirection = layout.findViewById(R.id.layout_direction);
mLayoutSpeed = layout.findViewById(R.id.layout_speed);
mLayoutAddress = layout.findViewById(R.id.address);
mPositionHeader = layout.findViewById(R.id.position_header);
mHeaderText = (TextView) layout.findViewById(R.id.header_text);
mHeaderWindSensor = (TextView) layout.findViewById(R.id.wind_sensor);
// disabled, because of bug #2871
// mWindOff = layout.findViewById(R.id.wind_off);
// mWindOn = layout.findViewById(R.id.wind_on);
mAddressSearch = layout.findViewById(R.id.address_search);
mSetData = layout.findViewById(R.id.set_data);
mSetPosition = layout.findViewById(R.id.set_position);
mCompassView = (CompassView) layout.findViewById(R.id.compassView);
mWindSpeed = (NumberPicker) layout.findViewById(R.id.wind_speed);
mAddressInput = (EditText) layout.findViewById(R.id.address_input);
mWindSensor = (TextView) layout.findViewById(R.id.wind_sensor);
mEnterPosition = (Button) layout.findViewById(R.id.enter_position);
// mWindOff = layout.findViewById(R.id.wind_off);
// mWindOn = layout.findViewById(R.id.wind_on);
mContentSetData = (Button) layout.findViewById(R.id.set_data);
mContentCompassView = (CompassView) layout.findViewById(R.id.compass_view);
mContentWindSpeed = (NumberPicker) layout.findViewById(R.id.wind_speed);
mContentLatitude = (TextView) layout.findViewById(R.id.position_latitude);
mContentLongitude = (TextView) layout.findViewById(R.id.position_longitude);
mContentAccuracy = (TextView) layout.findViewById(R.id.position_accuracy);
mContentMapShow = (Button) layout.findViewById(R.id.position_show);
mMapWebView = (WebView) layout.findViewById(R.id.web_view);
mMapHide = (Button) layout.findViewById(R.id.position_hide);
return layout;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initialMapFragment();
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (getArguments() != null) {
switch (getArguments().getInt(START_MODE, 0)) {
case 1:
if (getView() != null) {
View header = getView().findViewById(R.id.header);
header.setVisibility(View.GONE);
}
break;
default:
break;
}
}
if (mWindSensor != null && getRace() != null && getRaceState() != null && getRaceState().getWindFix() != null) {
if (mHeaderWindSensor != null && getRace() != null && getRaceState() != null && getRaceState().getWindFix() != null) {
String sensorData = getString(R.string.wind_sensor);
SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm", getResources().getConfiguration().locale);
Wind wind = getRaceState().getWindFix();
sensorData = sensorData.replace("#AT#", dateFormat.format(wind.getTimePoint().asDate()));
sensorData = sensorData.replace("#FROM#", String.format("%.0f", wind.getFrom().getDegrees()));
sensorData = sensorData.replace("#SPEED#", String.format("%.1f", wind.getKnots()));
mWindSensor.setText(sensorData);
mHeaderWindSensor.setText(sensorData);
}
setupButtons();
setupWindSpeedPicker();
showElements(true);
setupLayouts(false);
}
setInstanceState(savedInstanceState);
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mRefreshUIHandler = new Handler();
}
/**
* starts the googleApiClient to get location updates
*/
public void setupLocationClient() {
private void tearUpApiClient() {
locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(FIVE_SEC);
locationRequest.setFastestInterval(EVERY_POSITION_CHANGE);
apiClient.registerConnectionCallbacks(this);
apiClient.registerConnectionFailedListener(this);
apiClient.connect();
}
private void tearDownApiClient() {
apiClient.unregisterConnectionFailedListener(this);
apiClient.unregisterConnectionCallbacks(this);
apiClient.disconnect();
}
/**
* adds the polling for buoy data to the polled races, also registers a callback
*/
private void tearUpPositionPoller() {
positionPoller = new RacePositionsPoller(getActivity());
positionPoller.register(getRace(), this);
ExLog.i(getActivity(), TAG, "registering race " + getRace().getRaceName());
}
private void tearDownPositionPoller() {
positionPoller.unregisterAllAndStop();
}
/**
* configures all the buttons in the view
*/
public void setupButtons() {
if (mHeader != null) {
mHeader.setOnClickListener(this);
if (mHeaderText != null) {
mHeaderText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openMainScheduleFragment();
}
});
}
if (mEnterPosition != null) {
mEnterPosition.setOnClickListener(this);
if (mContentSetData != null) {
mContentSetData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onSendClick();
}
});
}
if (mAddressInput != null) {
mAddressInput.setOnEditorActionListener(this);
if (mContentMapShow != null) {
// disable functionality at first. will be enabled after contacting the server if race is tracked
mContentMapShow.setEnabled(false);
mContentMapShow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setupLayouts(true);
}
});
}
if (mAddressSearch != null) {
mAddressSearch.setOnClickListener(this);
}
if (mSetData != null) {
mSetData.setOnClickListener(this);
}
if (mSetPosition != null) {
mSetPosition.setOnClickListener(this);
if (mMapHide != null) {
mMapHide.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setupLayouts(false);
}
});
}
}
/**
* configures the windspeedpicker views and attaches all relevant listener functions to them
* configures the wind speed picker views and attaches all relevant listener functions to them
*/
public void setupWindSpeedPicker() {
String nums[] = generateNumbers();
ThemeHelper.setPickerTextColor(getActivity(), mWindSpeed, ThemeHelper.getColor(getActivity(), R.attr.white));
mWindSpeed.setMaxValue(nums.length - 1);
mWindSpeed.setMinValue(0);
mWindSpeed.setWrapSelectorWheel(false);
mWindSpeed.setDisplayedValues(nums);
mWindSpeed.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);
ThemeHelper.setPickerTextColor(getActivity(), mContentWindSpeed, ThemeHelper.getColor(getActivity(), R.attr.white));
mContentWindSpeed.setMaxValue(nums.length - 1);
mContentWindSpeed.setMinValue(0);
mContentWindSpeed.setWrapSelectorWheel(false);
mContentWindSpeed.setDisplayedValues(nums);
mContentWindSpeed.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);
double enteredWindSpeed = preferences.getWindSpeed();
double enteredWindBearingFrom = preferences.getWindBearingFromDirection();
@@ -270,67 +317,66 @@ public class WindFragment extends BaseFragment
}
}
mCompassView.setDirection((float) enteredWindBearingFrom);
mWindSpeed.setValue(((int) ((enteredWindSpeed - MIN_KTS) * 2)));
mContentCompassView.setDirection((float) enteredWindBearingFrom);
mContentWindSpeed.setValue(((int) ((enteredWindSpeed - MIN_KTS) * 2)));
}
/**
* adds the polling for buoy data to the polled races, also registers a callback
*/
public void setupPositionPoller() {
positionPoller = new RacePositionsPoller(getActivity());
positionPoller.register(getRace(), this);
ExLog.i(getActivity(), TAG, "registering race " + getRace().getRaceName());
}
/**
* function to restore the instanceState via savedInstanceState bundle
*
* @param savedInstanceState said bundle
*/
public void setInstanceState(Bundle savedInstanceState) {
if (savedInstanceState != null) {
bigMap = savedInstanceState.getBoolean("bigMap", false);
double markerLat = savedInstanceState.getDouble("markerLat", -1);
if (bigMap) {
showBigMap();
if (mWindMap != null && savedInstanceState.getDouble("lat", -1) != -1) {
mWindMap.centerMap(savedInstanceState.getDouble("lat"), savedInstanceState.getDouble("lng"), savedInstanceState.getFloat("zoom"));
if (markerLat != -1) {
mWindMap.movePositionMarker(new LatLng(markerLat, savedInstanceState.getDouble("markerLng")));
}
}
// the map view needs java script
@SuppressLint("SetJavaScriptEnabled")
private void setupLayouts(boolean showMap) {
if (mHeaderLayout != null) {
if (getArguments() != null && getArguments().getInt(START_MODE, 0) == 1) {
mHeaderLayout.setVisibility(View.GONE);
} else {
mHeaderLayout.setVisibility(showMap ? View.GONE : View.VISIBLE);
}
}
if (mContentLayout != null) {
mContentLayout.setVisibility(showMap ? View.GONE : View.VISIBLE);
}
if (mMapLayout != null) {
WebSettings settings = mMapWebView.getSettings();
if (showMap) {
settings.setJavaScriptEnabled(true);
loadRaceMap(true, false, false, true);
mMapLayout.setVisibility(View.VISIBLE);
} else {
settings.setJavaScriptEnabled(false);
mMapLayout.setVisibility(View.GONE);
}
}
}
private boolean loadRaceMap(boolean showWindCharts, boolean showStreamlets, boolean showSimulation, boolean showMapControls) {
ManagedRace race = getRace();
if (race != null) {
// build complete race map url
String mapUrl = WindHelper.generateMapURL(getActivity(), race, showWindCharts, showStreamlets, showSimulation, showMapControls);
mMapWebView.loadUrl(mapUrl);
return true;
}
return false;
}
@Override
public void onStart() {
super.onStart();
mCompassView.setDirectionListener(this);
mContentCompassView.setDirectionListener(this);
// start ui refreshing
if (mRefreshUIHandler != null) {
mRefreshUIHandler.postDelayed(mRefreshUIRunnable, ONE_SEC);
}
}
@Override
public void onPause() {
super.onPause();
if (apiClient.isConnected()) {
apiClient.unregisterConnectionFailedListener(this);
apiClient.unregisterConnectionCallbacks(this);
}
apiClient.disconnect();
positionPoller.unregisterAllAndStop();
Fragment fragment = getFragmentManager().findFragmentById(R.id.windMap);
if (fragment != null) {
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.remove(fragment);
transaction.commit();
}
// disconnect googleApiClient and unregister position poller
tearDownApiClient();
tearDownPositionPoller();
sendIntent(AppConstants.INTENT_ACTION_TIME_SHOW);
}
@@ -339,63 +385,23 @@ public class WindFragment extends BaseFragment
public void onResume() {
super.onResume();
setupPositionPoller();
setupLocationClient();
initialMapFragment();
// connect googleApiClient and register position poller
tearUpApiClient();
tearUpPositionPoller();
// Contact server and ask if race is tracked and map is allowed to show.
WindHelper.isTrackedRace(getActivity(), getRace());
sendIntent(AppConstants.INTENT_ACTION_TIME_HIDE);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
public void onStop() {
super.onStop();
outState.putBoolean("bigMap", bigMap);
if (mWindMap != null) {
if (mGoogleMap != null) {
outState.putDouble("lat", mGoogleMap.getCameraPosition().target.latitude);
outState.putDouble("lng", mGoogleMap.getCameraPosition().target.longitude);
outState.putFloat("zoom", mGoogleMap.getCameraPosition().zoom);
}
if (mWindMap.windMarker != null) {
outState.putDouble("markerLat", mWindMap.windMarker.getPosition().latitude);
outState.putDouble("markerLng", mWindMap.windMarker.getPosition().longitude);
}
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.header_text:
if (bigMap) {
showElements(true);
bigMap = false;
} else {
openMainScheduleFragment();
}
break;
case R.id.enter_position:
showBigMap();
break;
case R.id.address_search:
if (mAddressInput != null) {
new GeoCodeTask().execute("" + mAddressInput.getText());
}
break;
case R.id.set_data: {
onSendClick();
break;
}
case R.id.set_position: {
onPositionSetClick();
break;
}
default: {
break;
}
// stop ui refreshing
if (mRefreshUIHandler != null) {
mRefreshUIHandler.removeCallbacks(mRefreshUIRunnable);
}
}
@@ -417,160 +423,19 @@ public class WindFragment extends BaseFragment
}
}
/**
* saves the boat position for later sendage of the entered windData
*/
private void onPositionSetClick() {
bigMap = false;
if (mWindMap != null && mWindMap.windMarker != null && mGoogleMap != null) {
mGoogleMap.getUiSettings().setAllGesturesEnabled(false);
mCurrentLocation = new Location("manual");
mCurrentLocation.setLatitude(mWindMap.windMarker.getPosition().latitude);
mCurrentLocation.setLongitude(mWindMap.windMarker.getPosition().longitude);
preferences.setWindPosition(mWindMap.windMarker.getPosition());
mWindMap.windMarker.setDraggable(false);
mWindMap.centerMap(mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude());
}
showElements(true);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private void initialMapFragment() {
mWindMap = WindMap.newInstance(mContext, this);
FragmentManager manager;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
manager = getChildFragmentManager();
} else {
manager = getFragmentManager();
}
if (manager.findFragmentByTag("googleMap") == null) {
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.windMap, mWindMap, "googleMap").commit();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
manager.executePendingTransactions();
mWindMap.getMapAsync(this);
}
}
}
/**
* expands the windMap , hides views where the map is supposed to go
*/
private void showBigMap() {
showElements(false);
if (mWindMap != null && mGoogleMap != null) {
mGoogleMap.getUiSettings().setAllGesturesEnabled(true);
if (mWindMap.windMarker != null) {
mWindMap.windMarker.setDraggable(true);
}
}
bigMap = true;
}
private void showElements(boolean show) {
if (mSetData != null) {
mSetData.setVisibility(show ? View.VISIBLE : View.INVISIBLE);
mSetData
.setEnabled(mWindMap != null && mWindMap.windMarker != null && mWindMap.windMarker.getPosition() != null && mCurrentLocation != null);
}
if (mSetPosition != null) {
mSetPosition.setVisibility(show ? View.INVISIBLE : View.VISIBLE);
}
if (mLayoutDirection != null) {
mLayoutDirection.setVisibility(show ? View.VISIBLE : View.GONE);
}
if (mLayoutSpeed != null) {
mLayoutSpeed.setVisibility(show ? View.VISIBLE : View.GONE);
}
if (mPositionHeader != null) {
mPositionHeader.setVisibility(show ? View.VISIBLE : View.GONE);
}
if (mDarkLayer != null) {
mDarkLayer.setVisibility(show ? View.VISIBLE : View.GONE);
}
if (mLayoutAddress != null) {
mLayoutAddress.setVisibility(show ? View.GONE : View.VISIBLE);
}
}
private void setWind(boolean on) {
if (mWindOn != null) {
mWindOn.setVisibility(on ? View.VISIBLE : View.GONE);
}
if (mWindOff != null) {
mWindOff.setVisibility(!on ? View.VISIBLE : View.GONE);
}
}
// private void setWind(boolean on) {
// if (mWindOn != null) {
// mWindOn.setVisibility(on ? View.VISIBLE : View.GONE);
// }
// if (mWindOff != null) {
// mWindOff.setVisibility(!on ? View.VISIBLE : View.GONE);
// }
// }
@Override
public void onLocationChanged(Location location) {
mCurrentLocation = location;
if (mWindMap != null) {
mWindMap.centerMap(location.getLatitude(), location.getLongitude());
if (mGoogleMap != null) {
UiSettings uiSettings = mGoogleMap.getUiSettings();
if (uiSettings != null) {
uiSettings.setAllGesturesEnabled(false);
}
}
mWindMap.addAccuracyCircle(location);
if (mWindMap.windMarker != null) {
mWindMap.windMarker.setDraggable(false);
}
}
if (mDarkLayer != null) {
mDarkLayer.setVisibility(View.GONE);
}
setWind(true);
showElements(true);
if (mDarkLayer != null) {
mDarkLayer.setVisibility(View.GONE);
}
}
/**
* function gets called after inputting the location where you want to the map to zoom to
*
* @param v the view where the location was entered
*/
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
switch (actionId) {
case EditorInfo.IME_ACTION_DONE:
new GeoCodeTask().execute("" + v.getText());
return true;
default:
return false;
}
}
@Override
public void onMarkerDragStart(Marker arg0) {
}
@Override
public void onMarkerDragEnd(Marker marker) {
mCurrentLocation = new Location("manual");
mCurrentLocation.setLatitude(marker.getPosition().latitude);
mCurrentLocation.setLongitude(marker.getPosition().longitude);
preferences.setWindPosition(marker.getPosition());
}
@Override
public void onMarkerDrag(Marker arg0) {
}
@Override
public void onMapClick(LatLng arg0) {
if (bigMap && mWindMap != null) {
mWindMap.movePositionMarker(arg0);
}
refreshUI();
}
@Override
@@ -585,18 +450,21 @@ public class WindFragment extends BaseFragment
@Override
public void onConnectionSuspended(int i) {
LocationServices.FusedLocationApi.removeLocationUpdates(apiClient, this);
}
@Override
public void onDirectionChanged(float degree) {
}
@Override
public void OnRaceUpdated(ManagedRace race) {
}
private Wind getResultingWindFix() throws NumberFormatException {
Position currentPosition = new DegreePosition(mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude());
double windSpeed = mWindSpeed.getValue() / 2 + MIN_KTS;
double windBearing = mCompassView.getDirection();
double windSpeed = mContentWindSpeed.getValue() / 2 + MIN_KTS;
double windBearing = mContentCompassView.getDirection();
Bearing bearing_from = new DegreeBearingImpl(windBearing);
SpeedWithBearing speedBearing = new KnotSpeedWithBearingImpl(windSpeed, bearing_from.reverse());
return new WindImpl(currentPosition, MillisecondsTimePoint.now(), speedBearing);
@@ -613,90 +481,13 @@ public class WindFragment extends BaseFragment
preferences.setWindSpeed(wind.getKnots());
}
@Override
public void OnRaceUpdated(ManagedRace race) {
if (mWindMap != null) {
mWindMap.onMapDataUpdated(race.getMapMarkers());
}
}
private class IsTrackedReceiver extends BroadcastReceiver {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void onMapReady(GoogleMap map) {
mGoogleMap = map;
if (mWindMap != null && mGoogleMap != null) {
mWindMap.setMap(mGoogleMap);
mGoogleMap.setOnMapClickListener(this);
mGoogleMap.setOnMarkerDragListener(this);
UiSettings uiSettings = mGoogleMap.getUiSettings();
uiSettings.setAllGesturesEnabled(false);
uiSettings.setCompassEnabled(false);
uiSettings.setMapToolbarEnabled(false);
// mWindMap.setData(mapItems);
// center the map
LatLng enteredWindLocation = preferences.getWindPosition();
if (enteredWindLocation.latitude != 0 && enteredWindLocation.longitude != 0) {
mWindMap.movePositionMarker(enteredWindLocation);
mWindMap.centerMap(enteredWindLocation);
}
}
}
@Override
public void afterResumed() {
mWindMap.getMapAsync(this);
}
/**
* Async call to googles geocoder web api
*/
private class GeoCodeTask extends AsyncTask<String, String, JSONObject> {
String location = "";
protected JSONObject doInBackground(String... urls) {
location = urls[0];
StringBuilder responseBody = new StringBuilder();
JSONObject locJSON = null;
try {
URL website = new URL(getString(R.string.url_google_geocoder) + URLEncoder.encode(location, "UTF-8")
+ getString(R.string.urlpart_google_geocoder_sensor));
ExLog.i(getActivity(), TAG, website.toString());
HttpURLConnection urlConnection = (HttpURLConnection) website.openConnection();
BufferedReader in;
try {
in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
responseBody.append(line);
}
JSONObject jObject = new JSONObject(responseBody + "");
locJSON = jObject.getJSONArray("results").getJSONObject(0).getJSONObject("geometry").getJSONObject("location");
} finally {
urlConnection.disconnect();
}
} catch (Exception e) {
ExLog.ex(WindFragment.this.getActivity(), TAG, e);
}
return (locJSON);
@Override
public void onReceive(Context context, Intent intent) {
mContentMapShow.setEnabled(intent.getBooleanExtra(AppConstants.INTENT_ACTION_IS_TRACKING_EXTRA, false));
}
protected void onPostExecute(JSONObject locJSON) {
if (locJSON == null) {
ExLog.i(getActivity(), TAG, "No Location found for " + location);
Toast.makeText(getActivity(), R.string.no_location_found, Toast.LENGTH_SHORT).show();
return;
}
try {
ExLog.i(getActivity(), TAG, "Location found for " + location + ": " + locJSON.getDouble("lat") + "," + locJSON.getDouble("lng"));
if (mWindMap != null) {
mWindMap.centerMap(locJSON.getDouble("lat"), locJSON.getDouble("lng"));
}
} catch (JSONException e) {
ExLog.ex(WindFragment.this.getActivity(), TAG, e);
}
}
}
}
@@ -12,6 +12,7 @@ import com.sap.sse.common.impl.MillisecondsTimePoint;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.TimeZone;
public class TimeUtils {
@@ -76,6 +77,21 @@ public class TimeUtils {
return formatDuration(secondsTillStart, emptyHours);
}
/**
* Formats milliseconds to a string like: 01h23'45''
*
* @return
*/
public static String formatTimeAgo(long milliseconds) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
calendar.setTimeInMillis(milliseconds);
String hours = String.format("%02d", calendar.get(Calendar.HOUR)) + "h";
String minutes = String.format("%02d", calendar.get(Calendar.MINUTE)) + "'";
String seconds = String.format("%02d", calendar.get(Calendar.SECOND)) + "''";
return hours + minutes + seconds;
}
public static String calcDuration(Calendar from, Calendar to) {
String retValue;
@@ -0,0 +1,119 @@
package com.sap.sailing.racecommittee.app.utils;
import android.content.Context;
import android.content.Intent;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import com.sap.sailing.android.shared.data.http.HttpGetRequest;
import com.sap.sailing.android.shared.util.NetworkHelper;
import com.sap.sailing.domain.abstractlog.race.SimpleRaceLogIdentifier;
import com.sap.sailing.domain.abstractlog.race.impl.SimpleRaceLogIdentifierImpl;
import com.sap.sailing.racecommittee.app.AppConstants;
import com.sap.sailing.racecommittee.app.AppPreferences;
import com.sap.sailing.racecommittee.app.data.DataManager;
import com.sap.sailing.racecommittee.app.data.DataStore;
import com.sap.sailing.racecommittee.app.domain.ManagedRace;
import com.sap.sailing.racecommittee.app.domain.impl.FleetIdentifierImpl;
import com.sap.sse.common.Util;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.net.MalformedURLException;
import java.net.URL;
public class WindHelper {
private static String TAG = WindHelper.class.getName();
private final static String GWT_MAP_AND_WIND_CHART_HTML = "gwt/EmbeddedMapAndWindChart.html";
public static void isTrackedRace(final Context context, final ManagedRace race){
try {
Util.Triple<String, String, String> triple = FleetIdentifierImpl.unescape(race.getId());
StringBuilder builder = new StringBuilder();
builder.append(getBaseUrl(context));
builder.append("/sailingserver/api/v1/events/");
builder.append(getEventId(context));
builder.append("/racestates");
builder.append("?filterByLeaderboard=" + triple.getA());
URL serverUrl = new URL(builder.toString());
HttpGetRequest request = new HttpGetRequest(serverUrl, context);
NetworkHelper.getInstance(context).executeHttpJsonRequestAsnchronously(request, new NetworkHelper.NetworkHelperSuccessListener() {
@Override
public void performAction(JSONObject response) {
LocalBroadcastManager manager = LocalBroadcastManager.getInstance(context);
Intent notifyTrackedIntent = new Intent();
notifyTrackedIntent.putExtra(AppConstants.INTENT_ACTION_IS_TRACKING_EXTRA, checkResponseForTracking(response, race));
notifyTrackedIntent.setAction(AppConstants.INTENT_ACTION_IS_TRACKING);
manager.sendBroadcast(notifyTrackedIntent);
}
}, new NetworkHelper.NetworkHelperFailureListener() {
@Override
public void performAction(NetworkHelper.NetworkHelperError e) {
Log.e(TAG, "Failed to contact server: " + e.getMessage());
}
});
}
catch (MalformedURLException e){
Log.e(TAG, "Failed to generate url for server call: " + e.getMessage());
}
}
private static String getBaseUrl(Context context){
return AppPreferences.on(context).getServerBaseURL();
}
private static String getEventId(Context context){
DataStore dataStore = DataManager.create(context).getDataStore();
return "" + dataStore.getEventUUID();
}
private static boolean checkResponseForTracking(JSONObject response, ManagedRace race){
boolean isTracked = false;
Util.Triple<String, String, String> triple = FleetIdentifierImpl.unescape(race.getId());
try {
JSONArray raceStates = response.getJSONArray("raceStates");
for(int index = 0; index < raceStates.length(); index++){
JSONObject raceState = raceStates.getJSONObject(index);
String leaderboardName = raceState.getString("leaderboardName");
String fleetName = raceState.getString("fleetName");
String raceName = raceState.getString("raceName");
boolean matchingLeaderboardName = leaderboardName != null && leaderboardName.equals(triple.getA());
boolean matchingFleetName = fleetName != null && fleetName.equals(triple.getC());
boolean matchingRaceName = raceName != null && raceName.equals(race.getRaceName());
if (matchingLeaderboardName && matchingFleetName && matchingRaceName){
String trackedRaceId = raceState.getString("trackedRaceId");
if (trackedRaceId != null){
isTracked = true;
break;
}
}
}
} catch (JSONException e) {
Log.e(TAG, "Failed to parse contents of the server response: " + e.getMessage());
}
return isTracked;
}
public static String generateMapURL(Context context, ManagedRace race ,boolean showWindCharts, boolean showStreamlets, boolean showSimulation, boolean showMapControls){
StringBuilder builder = new StringBuilder();
// get simple race log identifier
Util.Triple<String, String, String> triple = FleetIdentifierImpl.unescape(race.getId());
SimpleRaceLogIdentifier identifier = new SimpleRaceLogIdentifierImpl(triple.getA(), triple.getB(), triple.getC());
builder.append(getBaseUrl(context));
builder.append(GWT_MAP_AND_WIND_CHART_HTML);
builder.append("?regattaLikeName=" + identifier.getRegattaLikeParentName());
builder.append("&raceColumnName=" + identifier.getRaceColumnName());
builder.append("&fleetName=" + identifier.getFleetName());
builder.append("&eventId=" + getEventId(context));
builder.append("&viewShowWindChart=" + showWindCharts);
builder.append("&viewShowStreamlets=" + showStreamlets);
builder.append("&viewShowSimulation=" + showSimulation);
builder.append("&viewShowMapControls=" + showMapControls);
return builder.toString();
}
}