Merge commit 'd21d6ae84566964e31112c9be830398006ddc934' into design2015-races

* commit 'd21d6ae84566964e31112c9be830398006ddc934': (522 commits)
  Adapted Util for Iterable realated stuff in HomeService
  use PassingInstruction.None during TracTrac control point construction
  fixing SwissTimingAdapter DomainFactoryImpl which now has to use PassingInstruction.None to produce equal ControlPoint/PassingInstruction pairs
  trying to fix bug 2860 by first obtaining the course read lock before obtaining the mark passing lock
  Adapted current version of footer styling
  Adapted current version of social footer styling
  Adapted current version of main.gss
  fixing bug 2847 by issuing a UUID for new GateDTO objects already in the client-side editor thanks to Lennart's fix allowing us to issue random UUIDs on the client
  fixing bug 2858 by comparing ControlPoint *and* PassingInstruction
  fixed name for copied course
  added some null-safety to CandidateFinderImpl; see also bug 2857
  some aftermath to bug 2846, factoring the race log analysis of the "from" race log out of the loop that copies it to the other race logs
  Fixes broken build and bug 2684
  Fixes bug2684
  Fixes bug 2846
  Adapted styling of the current design for solutions page
  Fixed search icon styling
  Implemented current desing of socialFooter
  - Added filter logic to exclude media tracks not related to the scope of the current master data export. - Extended tests.
  Fix to implement sticky footer
  ...

Conflicts:
	java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch
	java/com.sap.sailing.gwt.ui/SailingGWT.launch
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties
	java/com.sap.sse.gwt.theme/src/main/java/com/sap/sse/gwt/theme/client/resources/main.gss
This commit is contained in:
Papick Garcia Taboada committed 2015-05-21 09:03:56 +02:00
commit b581abd346
974 files changed
+30331 -948

No files matched your search

+14
View File
@@ -19,3 +19,17 @@ build
.DS_Store
java/com.sap.sailing.simulator/bin/com/sap/sailing/simulator/Simulator.gwt.xml
/mobile/com.sap.sailing.racecommittee.app/res/values/keys.xml
java/com.sap.sailing.gwt.ui/SailingGWT Remote Profiling (Run-Mode only).launch
java/com.sap.sailing.gwt.ui/SailingGWT.launch
## Android Studio and Intellij and Android in general
gen/
.idea/
*.ipr
*.iws
*.iml
out/
.gradle
local.properties
git.xml
build.info
@@ -2,6 +2,8 @@
For wind measurements we're trying to consistently use Igtimi WindBot equipment. The AdminConsole has a tab "Igtimi Accounts" where accounts for the Igtimi YachtBot web site can be managed. WindBots associated with any of these accounts will feed their wind readings, when active, into races being tracked. Operations of the WindBots mainly needs to take care of charging the devices, turning them on when they leave the harbor and turning them off when they leave the race course. This can also be delegated to race officials carrying these devices on their vessels.
# Status LEDs
The devices have three LEDs whose status works as follows:
1. The three LED’s are “power”, “connection”, and “GPS” in order from top to bottom.
@@ -11,3 +13,15 @@ The devices have three LEDs whose status works as follows:
5. During sync, the “power” light blips and the “connection” LED should stay on until the sync has finished.
More information on running the WindBots can be found [here](https://igtimi.desk.com/customer/portal/articles/1494533-yachtbot-tracker-basic-operation?b_id=1690).
# Update Firmware
[How to update the firmware](https://igtimi.desk.com/customer/portal/articles/1122866-how-to-update-the-firmware-in-the-yachtbot-trackers?b_id=1690)
# WindBot User Guide (v. 1.0 R3)
[User Guide v. 1.0 R3](wiki/uploads/WindBot%20User%20Guide%201.0%20R3.pdf)
# Is the WindBot waterproof and does it sink if dropped it in the water?
Yes and yes.
+22
View File
@@ -0,0 +1,22 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.0.0'
}
}
allprojects {
repositories {
mavenCentral()
}
version = "1.0.0-SNAPSHOT"
tasks.withType(JavaCompile) {
sourceCompatibility = "1.7"
targetCompatibility = "1.7"
}
}
+25
View File
@@ -0,0 +1,25 @@
#!/bin/bash
# Originally written by Ralf Kistner <ralf@embarkmobile.com>, but placed in the public domain
set +e
bootanim=""
failcounter=0
timeout_in_sec=600
until [[ "$bootanim" =~ "stopped" ]]; do
bootanim=`adb -e shell getprop init.svc.bootanim 2>&1 &`
if [[ "$bootanim" =~ "device not found" || "$bootanim" =~ "device offline"
|| "$bootanim" =~ "running" ]]; then
let "failcounter += 1"
echo "Waiting for emulator to start"
if [[ $failcounter -gt timeout_in_sec ]]; then
echo "Timeout ($timeout_in_sec seconds) reached; failed to start emulator"
exit 1
fi
fi
sleep 1
done
echo "Emulator is ready"
+64 -3
View File
@@ -190,15 +190,20 @@ if [[ $@ == "" ]]; then
exit 2
fi
rm $START_DIR/build.log
if [[ "$@" == "clean" ]]; then
./gradlew clean
if [[ $? != 0 ]]; then
exit 100
fi
cd $PROJECT_HOME/java
rm -rf com.sap.$PROJECT_TYPE.gwt.ui/com.sap.$PROJECT_TYPE.*
rm -rf com.sap.sse.security.ui/com.sap.sse.security.ui.*
cd $PROJECT_HOME
echo "Using following command: mvn $extra -DargLine=\"$APP_PARAMETERS\" -fae -s $MAVEN_SETTINGS $clean"
echo "Maven version used: `mvn --version`"
mvn $extra -DargLine="$APP_PARAMETERS" -fae -s $MAVEN_SETTINGS $clean 2>&1 | tee $START_DIR/build.log
mvn $extra -DargLine="$APP_PARAMETERS" -fae -s $MAVEN_SETTINGS $clean 2>&1 | tee -a $START_DIR/build.log
MVN_EXIT_CODE=${PIPESTATUS[0]}
echo "Maven exit code is $MVN_EXIT_CODE"
exit 0
@@ -533,8 +538,10 @@ if [[ "$@" == "build" ]] || [[ "$@" == "all" ]]; then
echo "INFO: Activating proxy profile"
extra="$extra -P no-debug.with-proxy"
MAVEN_SETTINGS=$MAVEN_SETTINGS_PROXY
ANDROID_OPTIONS="--proxy-host proxy --proxy-port 8080"
else
extra="$extra -P no-debug.without-proxy"
ANDROID_OPTIONS=""
fi
cd $PROJECT_HOME/java
@@ -570,7 +577,7 @@ if [[ "$@" == "build" ]] || [[ "$@" == "all" ]]; then
#build local p2 repo
echo "Using following command (pwd: java/com.sap.sailing.targetplatform.base): mvn -fae -s $MAVEN_SETTINGS $clean compile"
echo "Maven version used: `mvn --version`"
(cd com.sap.$PROJECT_TYPE.targetplatform.base; mvn -fae -s $MAVEN_SETTINGS $clean compile 2>&1 | tee $START_DIR/build.log)
(cd com.sap.$PROJECT_TYPE.targetplatform.base; mvn -fae -s $MAVEN_SETTINGS $clean compile 2>&1 | tee -a $START_DIR/build.log)
# now get the exit status from mvn, and not that of tee which is what $? contains now
MVN_EXIT_CODE=${PIPESTATUS[0]}
echo "Maven exit code is $MVN_EXIT_CODE"
@@ -612,6 +619,10 @@ if [[ "$@" == "build" ]] || [[ "$@" == "all" ]]; then
echo "ANDROID_HOME=$ANDROID_HOME"
PATH=$PATH:$ANDROID_HOME/tools
PATH=$PATH:$ANDROID_HOME/platform-tools
ANDROID="$ANDROID_HOME/tools/android"
if [ \! -x "$ANDROID" ]; then
ANDROID="$ANDROID_HOME/tools/android.bat"
fi
RC_APP_VERSION=`grep "android:versionCode=" mobile/com.sap.$PROJECT_TYPE.racecommittee.app/AndroidManifest.xml | cut -d "\"" -f 2`
echo "RC_APP_VERSION=$RC_APP_VERSION"
@@ -620,6 +631,56 @@ if [[ "$@" == "build" ]] || [[ "$@" == "all" ]]; then
TRACKING_APP_VERSION=`grep "android:versionCode=" mobile/com.sap.$PROJECT_TYPE.android.tracking.app/AndroidManifest.xml | cut -d "\"" -f 2`
echo "TRACKING_APP_VERSION=$TRACKING_APP_VERSION"
extra="$extra -Dtracking-app-version=$TRACKING_APP_VERSION"
NOW=$(date +"%s")
BUILD_TOOLS=22.0.0
TARGET_API=22
TEST_API=18
ANDROID_ABI=armeabi-v7a
AVD_NAME="androidTest-${NOW}"
echo "Updating Android SDK (tools)..." | tee -a $START_DIR/build.log
echo yes | "$ANDROID" update sdk $ANDROID_OPTIONS --filter tools --no-ui --force --all > /dev/null
echo "Updating Android SDK (platform-tools)..." | tee -a $START_DIR/build.log
echo yes | "$ANDROID" update sdk $ANDROID_OPTIONS --filter platform-tools --no-ui --force --all > /dev/null
echo "Updating Android SDK (build-tools-${BUILD_TOOLS})..." | tee -a $START_DIR/build.log
echo yes | "$ANDROID" update sdk $ANDROID_OPTIONS --filter build-tools-${BUILD_TOOLS} --no-ui --force --all > /dev/null
echo "Updating Android SDK (android-${TARGET_API})..." | tee -a $START_DIR/build.log
echo yes | "$ANDROID" update sdk $ANDROID_OPTIONS --filter android-${TARGET_API} --no-ui --force --all > /dev/null
echo "Updating Android SDK (extra-android-m2repository)..." | tee -a $START_DIR/build.log
echo yes | "$ANDROID" update sdk $ANDROID_OPTIONS --filter extra-android-m2repository --no-ui --force --all > /dev/null
echo "Updating Android SDK (extra-google-m2repository)..." | tee -a $START_DIR/build.log
echo yes | "$ANDROID" update sdk $ANDROID_OPTIONS --filter extra-google-m2repository --no-ui --force --all > /dev/null
./gradlew clean build | tee -a $START_DIR/build.log
if [[ $? != 0 ]]; then
exit 100
fi
# testing deactivated due to errors in hudson
if [ $testing -eq 1 ]; then
adb emu kill
echo "Downloading image (sys-img-${ANDROID_ABI}-android-${TEST_API})..." | tee -a $START_DIR/build.log
echo yes | "$ANDROID" update sdk $ANDROID_OPTIONS --filter sys-img-${ANDROID_ABI}-android-${TEST_API} --no-ui --force --all > /dev/null
echo no | "$ANDROID" create avd --name ${AVD_NAME} --target android-${TEST_API} --abi ${ANDROID_ABI} --force -p ${START_DIR}/emulator
echo "Starting emulator..." | tee -a $START_DIR/build.log
emulator -avd ${AVD_NAME} -no-skin -no-audio -no-window &
echo "Waiting for startup..." | tee -a $START_DIR/build.log
adb wait-for-device
sleep 60
$PROJECT_HOME/configuration/androidWaitForEmulator.sh
if [[ $? != 0 ]]; then
adb emu kill
"$ANDROID" delete avd --name ${AVD_NAME}
exit 102
fi
adb shell input keyevent 82 &
./gradlew deviceCheck connectedCheck | tee -a $START_DIR/build.log
if [[ $? != 0 ]]; then
adb emu kill
"$ANDROID" delete avd --name ${AVD_NAME}
exit 101
fi
adb emu kill
"$ANDROID" delete avd --name ${AVD_NAME}
fi
else
echo "INFO: Deactivating mobile modules"
extra="$extra -P !with-mobile"
@@ -636,7 +697,7 @@ if [[ "$@" == "build" ]] || [[ "$@" == "all" ]]; then
echo "Using following command: mvn $extra -DargLine=\"$APP_PARAMETERS\" -fae -s $MAVEN_SETTINGS $clean install"
echo "Maven version used: `mvn --version`"
mvn $extra -DargLine="$APP_PARAMETERS" -fae -s $MAVEN_SETTINGS $clean install 2>&1 | tee $START_DIR/build.log
mvn $extra -DargLine="$APP_PARAMETERS" -fae -s $MAVEN_SETTINGS $clean install 2>&1 | tee -a $START_DIR/build.log
# now get the exit status from mvn, and not that of tee which is what $? contains now
MVN_EXIT_CODE=${PIPESTATUS[0]}
echo "Maven exit code is $MVN_EXIT_CODE"
+59
View File
@@ -0,0 +1,59 @@
#!/bin/sh
find_project_home ()
{
if [[ "$1" == '/' ]] || [[ "$1" == "" ]]; then
echo ""
return 0
fi
if [ ! -d "$1/.git" ]; then
PARENT_DIR="`cd "$1/..";pwd`"
OUTPUT=$(find_project_home "$PARENT_DIR")
if [ "$OUTPUT" = "" ] && [ -d "$PARENT_DIR/$CODE_DIRECTORY" ] && [ -d "$PARENT_DIR/$CODE_DIRECTORY/.git" ]; then
OUTPUT="$PARENT_DIR/$CODE_DIRECTORY"
fi
echo $OUTPUT
return 0
fi
echo $1 | sed -e 's/\/cygdrive\/\([a-zA-Z]\)/\1:/'
}
sign_apk()
{
ALIAS=$1
PROJECT_NAME=$2
PROJECT_UNALIGNED=$PROJECT_NAME-unaligned.apk
cd $PROJECT_HOME/mobile/$PROJECT_NAME/build/outputs/apk
rm $PROJECT_NAME.apk
cp $PROJECT_NAME-release-unsigned.apk $PROJECT_UNALIGNED
jarsigner -verbose -tsa -sigalg SHA1withRSA -digestalg SHA1 -keystore $PROJECT_HOME/mobile/android-keystore/STG.jks $PROJECT_UNALIGNED $ALIAS
$ANDROID_HOME/build-tools/$BUILD_TOOLS/zipalign -v 4 $PROJECT_UNALIGNED $PROJECT_NAME.apk
}
if [ $# -eq 0 ]; then
echo "Usage: $0 <key_alias>"
exit 2
fi
# this holds for default installation
BUILD_TOOLS="21.1.2"
USER_HOME=~
START_DIR="`pwd`"
if [ "$PROJECT_HOME" = "" ]; then
PROJECT_HOME=$(find_project_home "$START_DIR")
fi
# if project_home is still empty we could not determine any suitable directory
if [[ "$PROJECT_HOME" == "" ]]; then
echo "Could neither determine nor get PROJECT_HOME. Please provide it by setting an environment variable with this name."
exit 1
fi
sign_apk $1 com.sap.sailing.android.tracking.app
sign_apk $1 com.sap.sailing.racecommittee.app
+18
View File
@@ -0,0 +1,18 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
Binary file not shown.
+6
View File
@@ -0,0 +1,6 @@
#Wed Apr 10 15:27:10 PDT 2013
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
Vendored Executable
+164
View File
@@ -0,0 +1,164 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
Vendored
+90
View File
@@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
@@ -0,0 +1,7 @@
apply plugin: "java"
sourceSets {
main {
java.srcDirs = ["src"]
}
}
@@ -43,5 +43,5 @@
<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.dashboards.gwt}&quot; -startupUrl /dashboards/RibDashboard.html -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -logLevel INFO -codeServerPort auto com.sap.sailing.dashboards.gwt.RibDashboard"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.dashboards.gwt"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-XstartOnFirstThread -Xmx2048m"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx2048m"/>
</launchConfiguration>
@@ -0,0 +1,14 @@
apply plugin: "java"
sourceSets {
main {
java.srcDirs = ["src"]
}
}
dependencies {
/* local dependencies */
compile project(":java:com.sap.sse.common")
compile project(":java:com.sap.sse.security.common")
compile project(":java:com.sap.sse.datamining.shared")
}
@@ -190,4 +190,48 @@ public class AbstractPosition implements Position {
return "(" + getLatDeg() + "," + getLngDeg() + ")";
}
@Override
public Position getIntersection(Bearing thisBearing, Position to, Bearing toBearing) {
/*
* See http://www.movable-type.co.uk/scripts/latlong-vectors.html#intersection for explanation
*/
double radBearing1 = thisBearing.getRadians();
double radLatPos1 = getLatRad();
double radLngPos1 = getLngRad();
double[] greatCircle1 = createGreatCircleVector(radBearing1, radLatPos1, radLngPos1);
double radBearing2 = toBearing.getRadians();
double radLatPos2 = to.getLatRad();
double radLngPos2 = to.getLngRad();
double[] greatCircle2 = createGreatCircleVector(radBearing2, radLatPos2, radLngPos2);
double[] intersection1 = computeCrossProductOf3PartVectors(greatCircle1, greatCircle2);
double[] intersection2 = computeCrossProductOf3PartVectors(greatCircle2, greatCircle1);
Position intersectionPosition1 = cartesianVectorToPosition(intersection1);
Position intersectionPosition2 = cartesianVectorToPosition(intersection2);
Distance sumOfDistances1 = getDistance(intersectionPosition1).add(intersectionPosition1.getDistance(to));
Distance sumOfDistances2 = getDistance(intersectionPosition2).add(intersectionPosition2.getDistance(to));
return sumOfDistances1.compareTo(sumOfDistances2) < 0 ? intersectionPosition1 : intersectionPosition2;
}
private Position cartesianVectorToPosition(double[] vector) {
double lat = Math.atan2(vector[2], Math.sqrt(vector[0]*vector[0] + vector[1]*vector[1]));
double lng = Math.atan2(vector[1], vector[0]);
return new RadianPosition(lat, lng);
}
private double[] computeCrossProductOf3PartVectors(double[] vec1, double[] vec2) {
double[] crossProduct= new double[3];
crossProduct[0] = vec1[1]*vec2[2] - vec1[2]*vec2[1];
crossProduct[1] = vec1[2]*vec2[0] - vec1[0]*vec2[2];
crossProduct[2] = vec1[0]*vec2[1] - vec1[1]*vec2[0];
return crossProduct;
}
private double[] createGreatCircleVector(double radBearing, double radLatPos, double radLngPos) {
double[] greatCircle = new double[3];
greatCircle[0] = Math.sin(radLngPos) * Math.cos(radBearing) - Math.sin(radLatPos) * Math.cos(radLngPos) * Math.sin(radBearing);
greatCircle[1] = -Math.cos(radLngPos) * Math.cos(radBearing) - Math.sin(radLatPos) * Math.sin(radLngPos) * Math.sin(radBearing);
greatCircle[2] = Math.cos(radLatPos) * Math.sin(radBearing);
return greatCircle;
}
}
@@ -43,6 +43,7 @@ public enum BoatClassMasterdata {
NACRA_17 ("Nacra 17", true, 5.25, 2.59, BoatHullType.CATAMARAN, true, "N17", "Nacra-17"),
OK ("OK Dinghy", true, 5.25, 2.59, BoatHullType.MONOHULL, false, "OK-Dinghy", "OK-Jolle", "OK"),
OPTIMIST ("Optimist", true, 2.34, 1.07, BoatHullType.MONOHULL, false, "Opti", "Optimist Dinghy"),
PIRAT ("Pirat", true, 5.00, 1.61, BoatHullType.MONOHULL, false, "Pirate", "Piraten"),
PLATU_25 ("Platu 25", true, 7.53, 2.62, BoatHullType.MONOHULL, true, "Platu", "Platu-25", "PLA", "B25"),
RS_X ("RS:X", true, 2.86, 0.93, BoatHullType.SURFERBOARD, false, "RS-X", "RSX", "RS:X"),
SONAR ("Sonar", true, 7.01, 2.39, BoatHullType.MONOHULL, true),
@@ -105,4 +105,15 @@ public interface Position extends Serializable {
*/
double getQuickApproximateNauticalMileDistance(Position p);
/**
* Computes the intersection of two paths. The first path is defined by the underlying position and the parameter
* <code>thisBearing</code>. The second path is defined by parameters <code>to</code> and <code>toBearing</code>
*
* @param thisBearing defines first path with <code>this</code> position
* @param to defines second path with <code>toBearing</code>
* @param toBearing defines second path <code>to</code> position
* @return position of intersection. Since there are usually 2 intersections, we return the smaller intersection.
*/
Position getIntersection(Bearing thisBearing, Position to, Bearing toBearing);
}
@@ -40,6 +40,7 @@ import com.sap.sse.common.TimeRange;
import com.sap.sse.common.TypeBasedServiceFinder;
import com.sap.sse.common.TypeBasedServiceFinderFactory;
import com.sap.sse.common.Util;
import com.sap.sse.common.WithID;
import com.sap.sse.common.impl.TimeRangeImpl;
/**
@@ -109,7 +110,6 @@ public class MongoGPSFixStoreImpl implements MongoGPSFixStore {
public void loadCompetitorTrack(DynamicGPSFixTrack<Competitor, GPSFixMoving> track, AbstractLog<?, ?> log, Competitor competitor)
throws NoCorrespondingServiceRegisteredException, TransformationException{
List<DeviceMapping<Competitor>> mappings = new DeviceCompetitorMappingFinder<>(log).analyze().get(competitor);
if (mappings != null) {
for (DeviceMapping<Competitor> mapping : mappings) {
loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(), true /*inclusive*/);
@@ -197,6 +197,12 @@ public class MongoGPSFixStoreImpl implements MongoGPSFixStore {
loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(), true /*inclusive*/);
}
@Override
public void loadTrack(DynamicGPSFixTrack<WithID, ?> track, DeviceMapping<WithID> mapping)
throws NoCorrespondingServiceRegisteredException, TransformationException {
loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(), true);
}
private DBObject getDeviceQuery(DeviceIdentifier device)
throws TransformationException, NoCorrespondingServiceRegisteredException {
Object dbDeviceId = MongoObjectFactoryImpl.storeDeviceId(deviceServiceFinder, device);
@@ -229,4 +235,5 @@ public class MongoGPSFixStoreImpl implements MongoGPSFixStore {
}
return ((Number) result.get(FieldNames.NUM_FIXES.name())).longValue();
}
}
@@ -4,6 +4,8 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import com.sap.sailing.domain.common.tracking.impl.CompactGPSFixImpl;
import com.sap.sailing.domain.common.tracking.impl.CompactGPSFixMovingImpl;
import com.sap.sailing.domain.common.tracking.impl.GPSFixImpl;
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
import com.sap.sailing.domain.persistence.impl.DomainObjectFactoryImpl;
@@ -21,8 +23,10 @@ public class MockGPSFixMongoServiceFinder implements TypeBasedServiceFinder<GPSF
@Override
public GPSFixMongoHandler findService(String fixType) {
if (fixType.equals(GPSFixMovingImpl.class.getName())) return movingHandler;
if (fixType.equals(GPSFixImpl.class.getName())) return handler;
if (fixType.equals(GPSFixMovingImpl.class.getName()) ||
fixType.equals(CompactGPSFixMovingImpl.class.getName())) return movingHandler;
if (fixType.equals(GPSFixImpl.class.getName()) ||
fixType.equals(CompactGPSFixImpl.class.getName())) return handler;
return null;
}
@@ -33,6 +33,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogEventFactory;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.LastPublishedCourseDesignFinder;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDefineMarkEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDenoteForTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogStartTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogTrackingStateAnalyzer;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
@@ -205,26 +206,30 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
CourseBase course = new LastPublishedCourseDesignFinder(fromRaceLog).analyze();
final Set<Mark> marks = new HashSet<>();
course.getWaypoints().forEach(wp->Util.addAll(wp.getMarks(), marks));
Set<Competitor> competitors = new RegisteredCompetitorsAnalyzer<>(fromRaceLog).analyze();
final Set<Competitor> competitors = new RegisteredCompetitorsAnalyzer<>(fromRaceLog).analyze();
final List<RaceLogEvent> raceLogDeviceMarkMappingEvents = new AllEventsOfTypeFinder<>(fromRaceLog, /* only unrevoked */ true, RaceLogDeviceMarkMappingEvent.class).analyze();
for (RaceLog toRaceLog : toRaceLogs) {
if (course == null || !new RaceLogTrackingStateAnalyzer(toRaceLog).analyze().isForTracking()) {
continue;
}
CourseBase to = new CourseDataImpl("Copy of \"" + course.getName());
CourseBase newCourse = new CourseDataImpl("Copy of \"" + course.getName() + "\"");
TimePoint now = MillisecondsTimePoint.now();
int i = 0;
revokeAlreadyDefinedMarks(toRaceLog, service.getServerAuthor());
for (Waypoint oldWaypoint : course.getWaypoints()) {
to.addWaypoint(i++, oldWaypoint);
newCourse.addWaypoint(i++, oldWaypoint);
}
for (Mark mark : marks) {
RaceLogEvent event = RaceLogEventFactory.INSTANCE.createDefineMarkEvent(now,
service.getServerAuthor(), toRaceLog.getCurrentPassId(), mark);
toRaceLog.add(event);
}
for (RaceLogEvent raceLogDeviceMarkMappingEvent : raceLogDeviceMarkMappingEvents) {
toRaceLog.add(raceLogDeviceMarkMappingEvent);
}
int passId = toRaceLog.getCurrentPassId();
RaceLogEvent newCourseEvent = RaceLogEventFactory.INSTANCE.createCourseDesignChangedEvent(now,
service.getServerAuthor(), passId, to);
service.getServerAuthor(), passId, newCourse);
toRaceLog.add(newCourseEvent);
registerCompetitors(service, toRaceLog, competitors);
}
@@ -35,6 +35,7 @@ Export-Package: com.sap.sailing.domain.abstractlog,
com.sap.sailing.domain.abstractlog.regatta.events,
com.sap.sailing.domain.abstractlog.regatta.events.impl,
com.sap.sailing.domain.abstractlog.regatta.impl,
com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl,
com.sap.sailing.domain.abstractlog.shared.analyzing,
com.sap.sailing.domain.abstractlog.shared.events,
com.sap.sailing.domain.base,
@@ -0,0 +1,15 @@
apply plugin: "java"
sourceSets {
main {
java.srcDirs = ["src"]
}
}
dependencies {
/* local dependencies */
compile project(":java:com.sap.sailing.domain.common")
compile project(":java:com.sap.sse.common")
compile project(":java:com.sap.sse.datamining.shared")
compile project(":java:com.sap.sse.shared.android")
}
@@ -0,0 +1,31 @@
package com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl;
import java.io.Serializable;
import java.util.UUID;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogCloseOpenEndedDeviceMappingEventImpl;
import com.sap.sailing.domain.abstractlog.shared.analyzing.OpenEndedDeviceMappingCloser;
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class RegattaLogOpenEndedDeviceMappingCloser extends
OpenEndedDeviceMappingCloser<RegattaLog, RegattaLogEvent, RegattaLogEventVisitor, RegattaLogCloseOpenEndedDeviceMappingEvent> {
public RegattaLogOpenEndedDeviceMappingCloser(RegattaLog log, DeviceMapping<?> mapping, AbstractLogEventAuthor author,
TimePoint closingTimePoint) {
super(log, mapping, author, closingTimePoint);
}
@Override
protected RegattaLogCloseOpenEndedDeviceMappingEvent createCloseEvent(TimePoint logicalTimePoint,
Serializable eventToCloseId) {
return new RegattaLogCloseOpenEndedDeviceMappingEventImpl(MillisecondsTimePoint.now(), author,
logicalTimePoint, UUID.randomUUID(), eventToCloseId, closingTimePoint);
}
}
@@ -21,7 +21,6 @@ public class DeviceCompetitorMappingFinder<LogT extends AbstractLog<EventT, Visi
public LogAnalyzer<Map<Competitor, List<DeviceMapping<Competitor>>>> createAnalyzer(AbstractLog<?, ?> log) {
return new DeviceCompetitorMappingFinder(log);
}
}
public DeviceCompetitorMappingFinder(LogT log) {
@@ -179,10 +179,14 @@ public class SharedDomainFactoryImpl implements SharedDomainFactory {
@Override
public ControlPointWithTwoMarks getOrCreateControlPointWithTwoMarks(Serializable id, String name, Mark left, Mark right) {
if (controlPointWithTwoMarksCache.containsKey(id)) {
return controlPointWithTwoMarksCache.get(id);
final ControlPointWithTwoMarks result;
final ControlPointWithTwoMarks fromCache = controlPointWithTwoMarksCache.get(id);
if (fromCache != null) {
result = fromCache;
} else {
result = createControlPointWithTwoMarks(id, left, right, name);
}
return createControlPointWithTwoMarks(id, left, right, name);
return result;
}
@Override
@@ -47,4 +47,10 @@ public interface RaceGroup extends Named {
* Gets configuration objects for {@link RacingProcedure}s of this {@link RaceGroup}'s races.
*/
public RegattaConfiguration getRegattaConfiguration();
/**
* An optional (may be <code>null</code>0 non-identifying name that may, e.g., be a short name
* for the necessarily unique and therefore potentially longer, maybe clumsy full {@link #getName()}.
*/
String getDisplayName();
}
@@ -11,28 +11,38 @@ import com.sap.sse.common.impl.NamedImpl;
public class RaceGroupImpl extends NamedImpl implements RaceGroup {
private static final long serialVersionUID = 7760879536339600827L;
private final String displayName;
private final BoatClass boatClass;
private final CourseArea courseArea;
private final Iterable<SeriesWithRows> series;
private final RegattaConfiguration regattaConfiguration;
public RaceGroupImpl(String name, BoatClass boatClass, CourseArea courseArea, Iterable<SeriesWithRows> series,
RegattaConfiguration regattaConfiguration) {
public RaceGroupImpl(String name, String displayName, BoatClass boatClass, CourseArea courseArea,
Iterable<SeriesWithRows> series, RegattaConfiguration regattaConfiguration) {
super(name);
this.displayName = displayName;
this.boatClass = boatClass;
this.courseArea = courseArea;
this.series = series;
this.regattaConfiguration = regattaConfiguration;
}
@Override
public String getDisplayName() {
return displayName;
}
@Override
public CourseArea getDefaultCourseArea() {
return courseArea;
}
@Override
public Iterable<SeriesWithRows> getSeries() {
return series;
}
@Override
public BoatClass getBoatClass() {
return boatClass;
}
@@ -319,7 +319,7 @@ public class DomainFactoryImpl implements DomainFactory {
for (Mark mark : marks) {
// TODO bug 1043: propagate the mark names to the waypoint names
com.sap.sailing.domain.base.ControlPoint domainControlPoint = getOrCreateControlPoint(mark.getDevices());
newDomainControlPoints.add(new com.sap.sse.common.Util.Pair<com.sap.sailing.domain.base.ControlPoint, PassingInstruction>(domainControlPoint, null));
newDomainControlPoints.add(new com.sap.sse.common.Util.Pair<>(domainControlPoint, PassingInstruction.None));
}
courseToUpdate.update(newDomainControlPoints, baseDomainFactory);
}
@@ -149,9 +149,9 @@ public abstract class AbstractTracTracLiveTest extends StoredTrackBasedTest {
}
public static Iterable<Pair<TracTracControlPoint, PassingInstruction>> getTracTracControlPointsWithPassingInstructions(Iterable<IControl> controlPoints) {
List<Pair<TracTracControlPoint, PassingInstruction>> ttControlPoints = new ArrayList<Pair<TracTracControlPoint, PassingInstruction>>();
List<Pair<TracTracControlPoint, PassingInstruction>> ttControlPoints = new ArrayList<>();
for (IControl cp : controlPoints) {
ttControlPoints.add(new Pair<TracTracControlPoint, PassingInstruction>(new ControlPointAdapter(cp), null));
ttControlPoints.add(new Pair<TracTracControlPoint, PassingInstruction>(new ControlPointAdapter(cp), PassingInstruction.None));
}
return ttControlPoints;
}
@@ -2,6 +2,7 @@ package com.sap.sailing.domain.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
@@ -31,6 +32,7 @@ import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.CourseImpl;
import com.sap.sailing.domain.base.impl.MarkImpl;
import com.sap.sailing.domain.base.impl.WaypointImpl;
import com.sap.sailing.domain.common.PassingInstruction;
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
@@ -47,6 +49,7 @@ import com.sap.sailing.domain.tractracadapter.impl.ControlPointAdapter;
import com.sap.sailing.domain.tractracadapter.impl.DomainFactoryImpl;
import com.sap.sailing.domain.tractracadapter.impl.RaceCourseReceiver;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.Util.Triple;
import com.tractrac.model.lib.api.event.CreateModelException;
import com.tractrac.model.lib.api.event.IRace;
@@ -166,6 +169,35 @@ public class CourseUpdateTest extends AbstractTracTracLiveTest {
assertEquals(wp2, deletedWaypoints.iterator().next());
}
/**
* A test failing before bug 2858 was fixed: updating only the {@link PassingInstructions} of a {@link Waypoint#getPassingInstructions() waypoint}
* would have left the waypoint in place, not updating the course properly.
*/
@Test
public void testWaypointListDiffWithDifferentPassingInstructionsOnly() throws PatchFailedException {
Waypoint wp1 = new WaypointImpl(new MarkImpl("b1"), PassingInstruction.Port);
Waypoint wp2 = new WaypointImpl(new MarkImpl("b2"), PassingInstruction.Port);
Waypoint wp3 = new WaypointImpl(new MarkImpl("b3"), PassingInstruction.Port);
Waypoint wp4 = new WaypointImpl(new MarkImpl("b4"), PassingInstruction.Port);
List<Waypoint> waypoints = new ArrayList<Waypoint>(4);
waypoints.add(wp1);
waypoints.add(wp2);
waypoints.add(wp3);
waypoints.add(wp4);
Course course = new CourseImpl("Test Course", waypoints);
List<Pair<ControlPoint, PassingInstruction>> changedControlPoints = new ArrayList<>();
changedControlPoints.add(new Pair<>(wp1.getControlPoint(), PassingInstruction.Starboard));
changedControlPoints.add(new Pair<>(wp2.getControlPoint(), wp2.getPassingInstructions()));
changedControlPoints.add(new Pair<>(wp3.getControlPoint(), wp3.getPassingInstructions()));
changedControlPoints.add(new Pair<>(wp4.getControlPoint(), wp4.getPassingInstructions()));
course.update(changedControlPoints, com.sap.sailing.domain.base.DomainFactory.INSTANCE);
assertNotSame(wp1, Util.get(course.getWaypoints(), 0));
assertSame(wp2, Util.get(course.getWaypoints(), 1));
assertSame(wp3, Util.get(course.getWaypoints(), 2));
assertSame(wp4, Util.get(course.getWaypoints(), 3));
}
@Test
public void testLastWaypointRemoved() throws PatchFailedException, InterruptedException {
final boolean[] result = new boolean[1];
@@ -0,0 +1,199 @@
package com.sap.sailing.domain.test;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.junit.Test;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
import com.sap.sailing.domain.base.SpeedWithConfidence;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.SpeedWithBearingWithConfidenceImpl;
import com.sap.sailing.domain.base.impl.SpeedWithConfidenceImpl;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.LegType;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.common.Tack;
import com.sap.sailing.domain.common.Wind;
import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.common.WindSourceType;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.common.impl.WindImpl;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.tracking.TrackedLeg;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
import com.sap.sailing.domain.tracking.impl.TrackedLegImpl;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class TargetTimeEstimationTest {
@Test
public void simpleReachTargetTimeEstimation() throws NotEnoughDataHasBeenAddedException, NoWindException {
// Setup mock objects
PolarDataService mockedPolars = mock(PolarDataService.class);
BoatClass mockedBoatClass = mock(BoatClass.class);
Position centerOfCourse = new DegreePosition(54.432800, 10.193655);
TimePoint timepoint = new MillisecondsTimePoint(1431426491696l);
Bearing windBearing = new DegreeBearingImpl(90);
SpeedWithBearing windSpeedWithBearing = new KnotSpeedWithBearingImpl(10, windBearing);
Wind wind = new WindImpl(centerOfCourse, timepoint, windSpeedWithBearing);
Position startOfLeg = new DegreePosition(54.434648, 10.193312);
Position endOfLeg = new DegreePosition(54.430454, 10.193226);
Bearing legBearing = startOfLeg.getBearingGreatCircle(endOfLeg);
SpeedWithConfidence<Void> boatSpeedWithConfidence = new SpeedWithConfidenceImpl<Void>(new KnotSpeedImpl(12), 1, null);
DynamicTrackedRaceImpl trackedRace = mock(DynamicTrackedRaceImpl.class);
when(trackedRace.getCenterOfCourse(timepoint)).thenReturn(centerOfCourse);
WindSource source = mock(WindSource.class);
Set<WindSource> sources = Collections.singleton(source);
when(trackedRace.getWindSources(WindSourceType.TRACK_BASED_ESTIMATION)).thenReturn(sources);
when(trackedRace.getWind(any(Position.class), eq(timepoint), eq(sources))).thenReturn(wind);
RaceDefinition race = mock(RaceDefinition.class);
when(race.getBoatClass()).thenReturn(mockedBoatClass);
when(trackedRace.getRace()).thenReturn(race);
Leg leg = mock(Leg.class);
Waypoint from = mock(Waypoint.class);
Waypoint to = mock(Waypoint.class);
when(leg.getFrom()).thenReturn(from);
when(leg.getTo()).thenReturn(to);
when(trackedRace.getApproximatePosition(from, timepoint)).thenReturn(startOfLeg);
when(trackedRace.getApproximatePosition(to, timepoint)).thenReturn(endOfLeg);
when(mockedPolars.getSpeed(mockedBoatClass, wind, windBearing.getDifferenceTo(legBearing))).thenReturn(boatSpeedWithConfidence);
HashSet<Competitor> competitors = new HashSet<Competitor>();
TrackedLeg trackedLeg = new TrackedLegImpl(trackedRace, leg, competitors);
//Actual test of functionality
Duration duration = trackedLeg.getEstimatedTimeToComplete(mockedPolars, timepoint);
assertEquals(75494, duration.asMillis(), 100);
}
@Test
public void simpleUpwindTargetTimeEstimation() throws NotEnoughDataHasBeenAddedException, NoWindException {
// Setup mock objects
PolarDataService mockedPolars = mock(PolarDataService.class);
BoatClass mockedBoatClass = mock(BoatClass.class);
Position centerOfCourse = new DegreePosition(54.432800, 10.193655);
TimePoint timepoint = new MillisecondsTimePoint(1431426491696l);
Bearing windBearing = new DegreeBearingImpl(-175);
SpeedWithBearing windSpeedWithBearing = new KnotSpeedWithBearingImpl(10, windBearing);
Wind wind = new WindImpl(centerOfCourse, timepoint, windSpeedWithBearing);
Position endOfLeg = new DegreePosition(54.434648, 10.193312);
Position startOfLeg = new DegreePosition(54.430454, 10.193226);
DynamicTrackedRaceImpl trackedRace = mock(DynamicTrackedRaceImpl.class);
when(trackedRace.getCenterOfCourse(timepoint)).thenReturn(centerOfCourse);
WindSource source = mock(WindSource.class);
Set<WindSource> sources = Collections.singleton(source);
when(trackedRace.getWindSources(WindSourceType.TRACK_BASED_ESTIMATION)).thenReturn(sources);
when(trackedRace.getWind(any(Position.class), eq(timepoint), eq(sources))).thenReturn(wind);
RaceDefinition race = mock(RaceDefinition.class);
when(race.getBoatClass()).thenReturn(mockedBoatClass);
when(trackedRace.getRace()).thenReturn(race);
Leg leg = mock(Leg.class);
Waypoint from = mock(Waypoint.class);
Waypoint to = mock(Waypoint.class);
when(leg.getFrom()).thenReturn(from);
when(leg.getTo()).thenReturn(to);
when(trackedRace.getApproximatePosition(from, timepoint)).thenReturn(startOfLeg);
when(trackedRace.getApproximatePosition(to, timepoint)).thenReturn(endOfLeg);
SpeedWithBearing speedWithBearingPort = new KnotSpeedWithBearingImpl(6, new DegreeBearingImpl(-45));
SpeedWithBearingWithConfidence<Void> boatSpeedWithBearingWithConfidencePort = new SpeedWithBearingWithConfidenceImpl<Void>(speedWithBearingPort, 1, null);
when(mockedPolars.getAverageSpeedWithBearing(mockedBoatClass, wind, LegType.UPWIND, Tack.PORT)).thenReturn(boatSpeedWithBearingWithConfidencePort);
SpeedWithBearing speedWithBearingStarboard = new KnotSpeedWithBearingImpl(6, new DegreeBearingImpl(45));
SpeedWithBearingWithConfidence<Void> boatSpeedWithBearingWithConfidenceStarboard = new SpeedWithBearingWithConfidenceImpl<Void>(speedWithBearingStarboard, 1, null);
when(mockedPolars.getAverageSpeedWithBearing(mockedBoatClass, wind, LegType.UPWIND, Tack.STARBOARD)).thenReturn(boatSpeedWithBearingWithConfidenceStarboard);
HashSet<Competitor> competitors = new HashSet<Competitor>();
TrackedLeg trackedLeg = new TrackedLegImpl(trackedRace, leg, competitors);
//Actual test of functionality
Duration duration = trackedLeg.getEstimatedTimeToComplete(mockedPolars, timepoint);
assertEquals(213513, duration.asMillis(), 100);
}
@Test
public void simpleDownwindTargetTimeEstimation() throws NotEnoughDataHasBeenAddedException, NoWindException {
// Setup mock objects
PolarDataService mockedPolars = mock(PolarDataService.class);
BoatClass mockedBoatClass = mock(BoatClass.class);
Position centerOfCourse = new DegreePosition(54.432800, 10.193655);
TimePoint timepoint = new MillisecondsTimePoint(1431426491696l);
Bearing windBearing = new DegreeBearingImpl(5);
SpeedWithBearing windSpeedWithBearing = new KnotSpeedWithBearingImpl(10, windBearing);
Wind wind = new WindImpl(centerOfCourse, timepoint, windSpeedWithBearing);
Position endOfLeg = new DegreePosition(54.434648, 10.193312);
Position startOfLeg = new DegreePosition(54.430454, 10.193226);
DynamicTrackedRaceImpl trackedRace = mock(DynamicTrackedRaceImpl.class);
when(trackedRace.getCenterOfCourse(timepoint)).thenReturn(centerOfCourse);
WindSource source = mock(WindSource.class);
Set<WindSource> sources = Collections.singleton(source);
when(trackedRace.getWindSources(WindSourceType.TRACK_BASED_ESTIMATION)).thenReturn(sources);
when(trackedRace.getWind(any(Position.class), eq(timepoint), eq(sources))).thenReturn(wind);
RaceDefinition race = mock(RaceDefinition.class);
when(race.getBoatClass()).thenReturn(mockedBoatClass);
when(trackedRace.getRace()).thenReturn(race);
Leg leg = mock(Leg.class);
Waypoint from = mock(Waypoint.class);
Waypoint to = mock(Waypoint.class);
when(leg.getFrom()).thenReturn(from);
when(leg.getTo()).thenReturn(to);
when(trackedRace.getApproximatePosition(from, timepoint)).thenReturn(startOfLeg);
when(trackedRace.getApproximatePosition(to, timepoint)).thenReturn(endOfLeg);
SpeedWithBearing speedWithBearingPort = new KnotSpeedWithBearingImpl(11, new DegreeBearingImpl(150));
SpeedWithBearingWithConfidence<Void> boatSpeedWithBearingWithConfidencePort = new SpeedWithBearingWithConfidenceImpl<Void>(speedWithBearingPort, 1, null);
when(mockedPolars.getAverageSpeedWithBearing(mockedBoatClass, wind, LegType.DOWNWIND, Tack.PORT)).thenReturn(boatSpeedWithBearingWithConfidencePort);
SpeedWithBearing speedWithBearingStarboard = new KnotSpeedWithBearingImpl(11, new DegreeBearingImpl(-150));
SpeedWithBearingWithConfidence<Void> boatSpeedWithBearingWithConfidenceStarboard = new SpeedWithBearingWithConfidenceImpl<Void>(speedWithBearingStarboard, 1, null);
when(mockedPolars.getAverageSpeedWithBearing(mockedBoatClass, wind, LegType.DOWNWIND, Tack.STARBOARD)).thenReturn(boatSpeedWithBearingWithConfidenceStarboard);
HashSet<Competitor> competitors = new HashSet<Competitor>();
TrackedLeg trackedLeg = new TrackedLegImpl(trackedRace, leg, competitors);
//Actual test of functionality
Duration duration = trackedLeg.getEstimatedTimeToComplete(mockedPolars, timepoint);
assertEquals(95090, duration.asMillis(), 100);
}
}
@@ -40,6 +40,7 @@ import com.sap.sailing.domain.common.racelog.Flags;
import com.sap.sailing.domain.common.tracking.GPSFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.leaderboard.ScoringScheme;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
@@ -67,6 +68,7 @@ import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sailing.domain.tracking.WindWithConfidence;
import com.sap.sailing.domain.tracking.impl.WindTrackImpl;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
@@ -909,4 +911,11 @@ public class MockedTrackedRace implements DynamicTrackedRace {
@Override
public void setPolarDataService(PolarDataService polarDataService) {
}
@Override
public Duration getEstimatedTimeToComplete(TimePoint timepoint) throws NotEnoughDataHasBeenAddedException,
NoWindException {
// TODO Auto-generated method stub
return null;
}
}
@@ -29,9 +29,10 @@ import com.sap.sailing.domain.common.Tack;
import com.sap.sailing.domain.common.Wind;
import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.common.WindSourceType;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.common.tracking.GPSFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
import com.sap.sailing.domain.tracking.CourseDesignChangedListener;
import com.sap.sailing.domain.tracking.GPSFixTrack;
@@ -52,6 +53,7 @@ import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sailing.domain.tracking.WindWithConfidence;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
@@ -614,4 +616,11 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
public void setPolarDataService(PolarDataService polarDataService) {
}
@Override
public Duration getEstimatedTimeToComplete(TimePoint timepoint) throws NotEnoughDataHasBeenAddedException,
NoWindException {
// TODO Auto-generated method stub
return null;
}
}
@@ -159,7 +159,7 @@ public class DomainFactoryImpl implements DomainFactory {
@Override
public void updateCourseWaypoints(Course courseToUpdate, Iterable<com.sap.sse.common.Util.Pair<TracTracControlPoint, PassingInstruction>> controlPoints) throws PatchFailedException {
List<com.sap.sse.common.Util.Pair<com.sap.sailing.domain.base.ControlPoint, PassingInstruction>> newDomainControlPoints = new ArrayList<com.sap.sse.common.Util.Pair<com.sap.sailing.domain.base.ControlPoint, PassingInstruction>>();
List<com.sap.sse.common.Util.Pair<com.sap.sailing.domain.base.ControlPoint, PassingInstruction>> newDomainControlPoints = new ArrayList<>();
for (com.sap.sse.common.Util.Pair<TracTracControlPoint, PassingInstruction> tractracControlPoint : controlPoints) {
com.sap.sailing.domain.base.ControlPoint newDomainControlPoint = getOrCreateControlPoint(tractracControlPoint.getA());
newDomainControlPoints.add(new com.sap.sse.common.Util.Pair<com.sap.sailing.domain.base.ControlPoint, PassingInstruction>(newDomainControlPoint, tractracControlPoint.getB()));
@@ -24,6 +24,7 @@ import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.domain.tractracadapter.DomainFactory;
import com.sap.sailing.domain.tractracadapter.TracTracControlPoint;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.Util.Triple;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.tractrac.model.lib.api.event.IEvent;
@@ -113,11 +114,11 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueue<IControlRoute,
routeControlPoints.add(ttControlPointsForAllOriginalEventControlPoints.get(cp));
}
Map<Integer, PassingInstruction> courseWaypointPassingInstructions = getDomainFactory().getMetadataParser().parsePassingInstructionData(routeMetadataString, routeControlPoints);
List<com.sap.sse.common.Util.Pair<TracTracControlPoint, PassingInstruction>> ttControlPoints = new ArrayList<>();
final List<Pair<TracTracControlPoint, PassingInstruction>> ttControlPoints = new ArrayList<>();
int i = 0;
for (IControl cp : event.getA().getControls()) {
PassingInstruction passingInstructions = courseWaypointPassingInstructions.containsKey(i) ? courseWaypointPassingInstructions.get(i) : null;
ttControlPoints.add(new com.sap.sse.common.Util.Pair<TracTracControlPoint, PassingInstruction>(ttControlPointsForAllOriginalEventControlPoints.get(cp), passingInstructions));
PassingInstruction passingInstructions = courseWaypointPassingInstructions.containsKey(i) ? courseWaypointPassingInstructions.get(i) : PassingInstruction.None;
ttControlPoints.add(new Pair<TracTracControlPoint, PassingInstruction>(ttControlPointsForAllOriginalEventControlPoints.get(cp), passingInstructions));
i++;
}
+16
View File
@@ -0,0 +1,16 @@
apply plugin: "java"
sourceSets {
main {
java.srcDirs = ["src"]
}
}
dependencies {
/* local dependencies */
compile project(":java:com.googlecode.java-diff-utils")
compile project(":java:com.sap.sailing.domain.common")
compile project(":java:com.sap.sailing.domain.shared.android")
compile project(":java:com.sap.sailing.geocoding")
compile project(":java:com.sap.sse.replication")
}
@@ -23,7 +23,7 @@ import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.PassingInstruction;
import com.sap.sailing.util.CourseAsWaypointList;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.impl.NamedImpl;
import com.sap.sse.concurrent.LockUtil;
import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
@@ -330,33 +330,33 @@ public class CourseImpl extends NamedImpl implements Course {
}
@Override
public void update(Iterable<Util.Pair<ControlPoint, PassingInstruction>> newControlPoints, DomainFactory baseDomainFactory) throws PatchFailedException {
public void update(Iterable<Pair<ControlPoint, PassingInstruction>> newControlPoints, DomainFactory baseDomainFactory) throws PatchFailedException {
Patch<Waypoint> patch = null;
synchronized (updateMonitor) {
lockForRead();
try {
Iterable<Waypoint> courseWaypoints = getWaypoints();
List<Waypoint> newWaypointList = new LinkedList<Waypoint>();
// key existing waypoints by control points and re-use each one at most once during construction of the
// key existing waypoints by (ControlPoint, PassingInstruction) pairs and re-use them during construction of the
// new waypoint list; since several waypoints can have the same control point, the map goes from
// control point to List<Waypoint>. The waypoints in the lists are held in the order of their
// Pair<ControlPoint, PassingInstruction> to List<Waypoint>. The waypoints in the lists are held in the order of their
// occurrence in courseToUpdate.getWaypoints().
Map<com.sap.sailing.domain.base.ControlPoint, List<Waypoint>> existingWaypointsByControlPoint = new HashMap<com.sap.sailing.domain.base.ControlPoint, List<Waypoint>>();
final Map<Pair<com.sap.sailing.domain.base.ControlPoint, PassingInstruction>, List<Waypoint>> existingWaypointsByControlPoint = new HashMap<>();
for (Waypoint waypoint : courseWaypoints) {
List<Waypoint> wpl = existingWaypointsByControlPoint.get(waypoint.getControlPoint());
final Pair<ControlPoint, PassingInstruction> key = new Pair<>(waypoint.getControlPoint(), waypoint.getPassingInstructions());
List<Waypoint> wpl = existingWaypointsByControlPoint.get(key);
if (wpl == null) {
wpl = new ArrayList<Waypoint>();
existingWaypointsByControlPoint.put(waypoint.getControlPoint(), wpl);
existingWaypointsByControlPoint.put(key, wpl);
}
wpl.add(waypoint);
}
for (Util.Pair<ControlPoint, PassingInstruction> newDomainControlPoint : newControlPoints) {
List<Waypoint> waypoints = existingWaypointsByControlPoint.get(newDomainControlPoint.getA());
for (Pair<ControlPoint, PassingInstruction> newDomainControlPoint : newControlPoints) {
List<Waypoint> waypoints = existingWaypointsByControlPoint.get(new Pair<>(newDomainControlPoint.getA(), newDomainControlPoint.getB()));
Waypoint waypoint;
if (waypoints == null || waypoints.isEmpty()) {
// must be a new control point for which we don't have a waypoint yet
waypoint = baseDomainFactory.createWaypoint(newDomainControlPoint.getA(),
newDomainControlPoint.getB());
waypoint = baseDomainFactory.createWaypoint(newDomainControlPoint.getA(), newDomainControlPoint.getB());
} else {
waypoint = waypoints.remove(0); // take the first from the list
}
@@ -573,7 +573,7 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
for (Event event : eventFetcher.getAllEvents()) {
event.removeRegatta(this);
for (CourseArea courseArea : event.getVenue().getCourseAreas()) {
if (defaultCourseArea != null && courseArea.getId().equals(defaultCourseArea)) {
if (defaultCourseArea != null && courseArea.getId().equals(defaultCourseArea.getId())) {
event.addRegatta(this);
}
}
@@ -23,6 +23,7 @@ import com.sap.sailing.domain.tracking.RaceChangeListener;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.impl.AbstractRaceChangeListener;
import com.sap.sse.common.Color;
import com.sap.sse.common.TimePoint;
import com.sap.sse.concurrent.ConcurrentWeakHashMap;
import com.sap.sse.concurrent.LockUtil;
import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
@@ -156,6 +157,17 @@ public class LeaderboardCacheManager {
public void isSuppressedChanged(Competitor competitor, boolean newIsSuppressed) {
removeFromCache(leaderboard);
}
@Override
public void timePointOfLastCorrectionsValidityChanged(TimePoint oldTimePointOfLastCorrectionsValidity,
TimePoint newTimePointOfLastCorrectionsValidity) {
removeFromCache(leaderboard);
}
@Override
public void commentChanged(String oldComment, String newComment) {
removeFromCache(leaderboard);
}
}
private final LeaderboardCache leaderboardCache;
@@ -3,6 +3,7 @@ package com.sap.sailing.domain.leaderboard;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sse.common.TimePoint;
public interface ScoreCorrectionListener {
void correctedScoreChanced(Competitor competitor, RaceColumn raceColumn, Double oldCorrectedScore, Double newCorrectedScore);
@@ -12,4 +13,8 @@ public interface ScoreCorrectionListener {
void carriedPointsChanged(Competitor competitor, Double oldCarriedPoints, Double newCarriedPoints);
void isSuppressedChanged(Competitor competitor, boolean newIsSuppressed);
void timePointOfLastCorrectionsValidityChanged(TimePoint oldTimePointOfLastCorrectionsValidity, TimePoint newTimePointOfLastCorrectionsValidity);
void commentChanged(String oldComment, String newComment);
}
@@ -41,4 +41,7 @@ public interface SettableScoreCorrection extends ScoreCorrection {
void notifyListenersAboutIsSuppressedChange(Competitor competitor, boolean suppressed);
void notifyListenersAboutLastCorrectionsValidityChanged(TimePoint oldTimePointOfLastCorrectionsValidity, TimePoint newTimePointOfLastCorrectionsValidity);
void notifyListenersAboutCommentChanged(String oldComment, String newComment);
}
@@ -377,7 +377,9 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
@Override
public void setCarriedPoints(Competitor competitor, double carriedPoints) {
Double oldCarriedPoints = this.carriedPoints.put(competitor, carriedPoints);
getScoreCorrection().notifyListenersAboutCarriedPointsChange(competitor, oldCarriedPoints, carriedPoints);
if (!Util.equalsWithNull(oldCarriedPoints, carriedPoints)) {
getScoreCorrection().notifyListenersAboutCarriedPointsChange(competitor, oldCarriedPoints, carriedPoints);
}
}
@Override
@@ -394,7 +396,9 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
@Override
public void unsetCarriedPoints(Competitor competitor) {
Double oldCarriedPoints = carriedPoints.remove(competitor);
getScoreCorrection().notifyListenersAboutCarriedPointsChange(competitor, oldCarriedPoints, null);
if (oldCarriedPoints != null) {
getScoreCorrection().notifyListenersAboutCarriedPointsChange(competitor, oldCarriedPoints, null);
}
}
@Override
@@ -411,7 +415,9 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
public void setDisplayName(Competitor competitor, String displayName) {
String oldDisplayName = displayNames.get(competitor);
displayNames.put(competitor, displayName);
getRaceColumnListeners().notifyListenersAboutCompetitorDisplayNameChanged(competitor, oldDisplayName, displayName);
if (!Util.equalsWithNull(oldDisplayName, displayName)) {
getRaceColumnListeners().notifyListenersAboutCompetitorDisplayNameChanged(competitor, oldDisplayName, displayName);
}
}
@Override
@@ -124,6 +124,21 @@ public class ScoreCorrectionImpl implements SettableScoreCorrection {
}
}
@Override
public void notifyListenersAboutLastCorrectionsValidityChanged(TimePoint oldTimePointOfLastCorrectionsValidity,
TimePoint newTimePointOfLastCorrectionsValidity) {
for (ScoreCorrectionListener listener : getScoreCorrectionListeners()) {
listener.timePointOfLastCorrectionsValidityChanged(oldTimePointOfLastCorrectionsValidity, newTimePointOfLastCorrectionsValidity);
}
}
@Override
public void notifyListenersAboutCommentChanged(String oldComment, String newComment) {
for (ScoreCorrectionListener listener : getScoreCorrectionListeners()) {
listener.commentChanged(oldComment, newComment);
}
}
@Override
public void setMaxPointsReason(Competitor competitor, RaceColumn raceColumn, MaxPointsReason reason) {
com.sap.sse.common.Util.Pair<Competitor, RaceColumn> key = raceColumn.getKey(competitor);
@@ -483,12 +498,20 @@ public class ScoreCorrectionImpl implements SettableScoreCorrection {
@Override
public void setTimePointOfLastCorrectionsValidity(TimePoint timePointOfLastCorrectionsValidity) {
final TimePoint oldTimePointOfLastCorrectionsValidity = this.timePointOfLastCorrectionsValidity;
this.timePointOfLastCorrectionsValidity = timePointOfLastCorrectionsValidity;
if (!Util.equalsWithNull(oldTimePointOfLastCorrectionsValidity, timePointOfLastCorrectionsValidity)) {
notifyListenersAboutLastCorrectionsValidityChanged(oldTimePointOfLastCorrectionsValidity, timePointOfLastCorrectionsValidity);
}
}
@Override
public void setComment(String scoreCorrectionComment) {
final String oldComment = this.comment;
this.comment = scoreCorrectionComment;
if (!Util.equalsWithNull(oldComment, scoreCorrectionComment)) {
notifyListenersAboutCommentChanged(oldComment, scoreCorrectionComment);
}
}
protected Leaderboard getLeaderboard() {
@@ -87,6 +87,17 @@ public abstract class AbstractMetaLeaderboard extends AbstractSimpleLeaderboardI
public void isSuppressedChanged(Competitor competitor, boolean newIsSuppressed) {
getScoreCorrection().notifyListenersAboutIsSuppressedChange(competitor, newIsSuppressed);
}
@Override
public void timePointOfLastCorrectionsValidityChanged(TimePoint oldTimePointOfLastCorrectionsValidity,
TimePoint newTimePointOfLastCorrectionsValidity) {
getScoreCorrection().notifyListenersAboutLastCorrectionsValidityChanged(oldTimePointOfLastCorrectionsValidity, newTimePointOfLastCorrectionsValidity);
}
@Override
public void commentChanged(String oldComment, String newComment) {
getScoreCorrection().notifyListenersAboutCommentChanged(oldComment, newComment);
}
}
public AbstractMetaLeaderboard(String name, ScoringScheme scoringScheme,
@@ -479,7 +479,7 @@ public class CandidateFinderImpl implements CandidateFinder {
}
}
List<Distance> wayPointXTEs = xtes.get(w);
int size = wayPointXTEs.size();
int size = wayPointXTEs == null ? 0 : wayPointXTEs.size();
if (size > 0) {
Double xte = wayPointXTEs.get(0).getMeters();
if (xte == 0) {
@@ -710,11 +710,7 @@ public class CandidateFinderImpl implements CandidateFinder {
boolean singleMark = false;
switch (instruction) {
case Port:
singleMark = true;
break;
case Starboard:
singleMark = true;
break;
case FixedBearing:
singleMark = true;
break;
@@ -8,19 +8,41 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Logger;
import com.sap.sailing.domain.abstractlog.AbstractLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.shared.events.DeviceMappingEvent;
import com.sap.sailing.domain.base.CourseArea;
import com.sap.sailing.domain.base.Event;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.common.RaceIdentifier;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.RegattaIdentifier;
import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.common.media.MediaTrack;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.common.tracking.GPSFix;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.impl.DeviceMappingImpl;
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.impl.DynamicGPSFixMovingTrackImpl;
import com.sap.sailing.domain.tracking.impl.DynamicGPSFixTrackImpl;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.WithID;
import com.sap.sse.common.impl.TimeRangeImpl;
/**
* Holds all information needed for a master data import.
@@ -30,26 +52,112 @@ import com.sap.sailing.domain.tracking.TrackedRace;
*/
public class TopLevelMasterData implements Serializable {
private static final Logger logger = Logger.getLogger(TopLevelMasterData.class.getName());
private static final long serialVersionUID = 4820893865792553281L;
private final Map<RegattaIdentifier, Set<String>> raceIdStringsForRegatta;
private final Set<MediaTrack> allMediaTracks;
private final Set<MediaTrack> filteredMediaTracks;
private final Set<LeaderboardGroup> leaderboardGroups;
private final Set<WindTrackMasterData> windTrackMasterData;
private final Map<LeaderboardGroup, Set<Event>> eventForLeaderboardGroup;
private final Map<DeviceIdentifier, Set<GPSFix>> raceLogTrackingFixes;
public TopLevelMasterData(final Set<LeaderboardGroup> groupsToExport, final Iterable<Event> allEvents,
final Map<String, Regatta> regattaForRaceIdString, final Collection<MediaTrack> allMediaTracks,
boolean exportWind) {
GPSFixStore gpsFixStore, boolean exportWind) {
this.raceIdStringsForRegatta = convertToRaceIdStringsForRegattaMap(regattaForRaceIdString);
this.allMediaTracks = new HashSet<MediaTrack>();
this.allMediaTracks.addAll(allMediaTracks);
this.leaderboardGroups = groupsToExport;
this.raceLogTrackingFixes = getAllRelevantRaceLogTrackingFixes(gpsFixStore);
if (exportWind) {
this.windTrackMasterData = fillWindMap(groupsToExport);
} else {
this.windTrackMasterData = new HashSet<WindTrackMasterData>();
}
this.eventForLeaderboardGroup = createEventMap(groupsToExport, allEvents);
this.filteredMediaTracks = new HashSet<MediaTrack>();
filterMediaTracks(allMediaTracks, this.filteredMediaTracks);
}
private Map<DeviceIdentifier, Set<GPSFix>> getAllRelevantRaceLogTrackingFixes(GPSFixStore gpsFixStore) {
Map<DeviceIdentifier, Set<GPSFix>> relevantFixes = new HashMap<>();
//Add fixes for regatta log mappings
for (Regatta regatta : getAllRegattas()) {
RegattaLog regattaLog = regatta.getRegattaLog();
try {
regattaLog.lockForRead();
for (RegattaLogEvent logEvent : regattaLog.getRawFixes()) {
addAllFixesIfMappingEvent(gpsFixStore, relevantFixes, logEvent);
}
} finally {
regattaLog.unlockAfterRead();
}
}
//Add fixes for race log mapping
for (LeaderboardGroup group : leaderboardGroups) {
for (Leaderboard leaderboard : group.getLeaderboards()) {
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
for (Fleet fleet : raceColumn.getFleets()) {
RaceLog raceLog = raceColumn.getRaceLog(fleet);
try {
raceLog.lockForRead();
for (RaceLogEvent logEvent : raceLog.getRawFixes()) {
addAllFixesIfMappingEvent(gpsFixStore, relevantFixes, logEvent);
}
} finally {
raceLog.unlockAfterRead();
}
}
}
}
}
return relevantFixes;
}
private void addAllFixesIfMappingEvent(GPSFixStore gpsFixStore, Map<DeviceIdentifier, Set<GPSFix>> relevantFixes,
AbstractLogEvent<?> logEvent) {
if (logEvent instanceof DeviceMappingEvent<?,?>) {
DeviceMappingEvent<?,?> mappingEvent = (DeviceMappingEvent<?,?>) logEvent;
try {
addAllFixesForMappingEvent(gpsFixStore, relevantFixes, mappingEvent);
} catch (NoCorrespondingServiceRegisteredException | TransformationException e) {
logger.severe("Failed to add fixes to exportdata for mapping Event");
e.printStackTrace();
}
}
}
private void addAllFixesForMappingEvent(GPSFixStore gpsFixStore, Map<DeviceIdentifier, Set<GPSFix>> relevantFixes,
DeviceMappingEvent<?, ?> mappingEvent) throws NoCorrespondingServiceRegisteredException, TransformationException {
DynamicGPSFixTrack<WithID, ?> track;
if (isMarkMappingEvent(mappingEvent)) {
track = new DynamicGPSFixTrackImpl<WithID>(mappingEvent.getMappedTo(), 10000);
} else {
track = new DynamicGPSFixMovingTrackImpl<WithID>(mappingEvent.getMappedTo(), 1000);
}
DeviceIdentifier device = mappingEvent.getDevice();
gpsFixStore.loadTrack(track, new DeviceMappingImpl<WithID>(mappingEvent.getMappedTo(), device,
new TimeRangeImpl(mappingEvent.getFrom(), mappingEvent.getTo())));
if (!relevantFixes.containsKey(device)) {
relevantFixes.put(device, new HashSet<>());
}
Set<GPSFix> fixes = relevantFixes.get(device);
try {
track.lockForRead();
for (GPSFix fix : track.getRawFixes()) {
fixes.add(fix);
}
} finally {
track.unlockAfterRead();
}
}
private boolean isMarkMappingEvent(DeviceMappingEvent<?, ?> mappingEvent) {
boolean isMarkMappingEvent = false;
if (mappingEvent instanceof RaceLogDeviceMarkMappingEvent || mappingEvent instanceof RegattaLogDeviceMarkMappingEvent) {
isMarkMappingEvent = true;
}
return isMarkMappingEvent;
}
/**
@@ -134,8 +242,8 @@ public class TopLevelMasterData implements Serializable {
}
}
public Collection<MediaTrack> getAllMediaTracks() {
return allMediaTracks;
public Collection<MediaTrack> getFilteredMediaTracks() {
return this.filteredMediaTracks;
}
public Collection<LeaderboardGroup> getLeaderboardGroups() {
@@ -186,4 +294,45 @@ public class TopLevelMasterData implements Serializable {
}
return regattas;
}
/**
* Copies only those media tracks from allMediaTracks to filteredMediaTracks which are
* assigned to races related to the exported LeaderboardGroup.
*/
private void filterMediaTracks(Collection<MediaTrack> allMediaTracks, Set<MediaTrack> filteredMediaTracks) {
Set<RaceIdentifier> raceIdentitifiersForMediaExport = collectRaceIdentifiersForMediaExport();
for (MediaTrack mediaTrack : allMediaTracks) {
for (RegattaAndRaceIdentifier raceIdentifier : mediaTrack.assignedRaces) {
if (raceIdentitifiersForMediaExport.contains(raceIdentifier)) {
filteredMediaTracks.add(mediaTrack);
continue;
}
}
}
}
/**
* Returns the set of races (in form of raceIdentifiers) related to the exported LeaderboardGroup.
*
*/
private Set<RaceIdentifier> collectRaceIdentifiersForMediaExport() {
Set<RaceIdentifier> raceIdentifiers = new HashSet<>();
for (LeaderboardGroup leaderboardGroup : leaderboardGroups) {
for (Leaderboard leaderboard : leaderboardGroup.getLeaderboards()) {
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
for (Fleet fleet : raceColumn.getFleets()) {
RaceIdentifier raceIdentifier = raceColumn.getRaceIdentifier(fleet);
if (raceIdentifier != null) {
raceIdentifiers.add(raceIdentifier);
}
}
}
}
}
return raceIdentifiers;
}
public Map<DeviceIdentifier, Set<GPSFix>> getRaceLogTrackingFixes() {
return raceLogTrackingFixes;
}
}
@@ -3,12 +3,15 @@ package com.sap.sailing.domain.racelog.tracking;
import com.sap.sailing.domain.abstractlog.AbstractLog;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.common.tracking.GPSFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.TimeRange;
import com.sap.sse.common.WithID;
public enum EmptyGPSFixStore implements GPSFixStore {
INSTANCE;
@@ -57,4 +60,10 @@ public enum EmptyGPSFixStore implements GPSFixStore {
public long getNumberOfFixes(DeviceIdentifier device) {
return 0;
}
@Override
public void loadTrack(DynamicGPSFixTrack<WithID, ?> track, DeviceMapping<WithID> mapping)
throws NoCorrespondingServiceRegisteredException, TransformationException {
}
}
@@ -13,6 +13,7 @@ import com.sap.sailing.domain.racelogtracking.DeviceMapping;
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.TimeRange;
import com.sap.sse.common.WithID;
public interface GPSFixStore {
@@ -40,6 +41,12 @@ public interface GPSFixStore {
void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, DeviceMapping<Mark> mapping) throws TransformationException,
NoCorrespondingServiceRegisteredException;
/**
* Load all fixes for both marks and competitors according to the {@code mapping}.
*/
void loadTrack(DynamicGPSFixTrack<WithID, ?> track, DeviceMapping<WithID> mapping)
throws NoCorrespondingServiceRegisteredException, TransformationException;
void storeFix(DeviceIdentifier device, GPSFix fix) throws TransformationException, NoCorrespondingServiceRegisteredException;
/**
@@ -16,7 +16,7 @@ public class BaseRegattaLikeImpl implements IsRegattaLike {
private final RegattaLikeIdentifier identifier;
private transient Set<RegattaLikeListener> listeners = new HashSet<>();
public BaseRegattaLikeImpl(RegattaLikeIdentifier identifier, RegattaLogStore store) {
public BaseRegattaLikeImpl(final RegattaLikeIdentifier identifier, RegattaLogStore store) {
regattaLog = store.getRegattaLog(identifier, /*ignoreCache*/ true);
this.identifier = identifier;
@@ -10,7 +10,10 @@ import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.LegType;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.tracking.impl.TrackedLegImpl;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
public interface TrackedLeg extends Serializable {
@@ -107,4 +110,13 @@ public interface TrackedLeg extends Serializable {
*/
Position getMiddleOfLeg(TimePoint at);
/**
* @param timepoint Used for positions of marks and wind information
* @return estimated time it takes to complete the leg
* @throws NotEnoughDataHasBeenAddedException thrown if not enough polar data has been added or polar data service
* is not available
* @throws NoWindException no wind available. unable to determine legtypes for given timepoint
*/
Duration getEstimatedTimeToComplete(PolarDataService polarDataService, TimePoint timepoint) throws NotEnoughDataHasBeenAddedException, NoWindException;
}
@@ -35,10 +35,12 @@ import com.sap.sailing.domain.common.WindSourceType;
import com.sap.sailing.domain.common.dto.TrackedRaceDTO;
import com.sap.sailing.domain.common.racelog.Flags;
import com.sap.sailing.domain.common.racelog.RacingProcedureType;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.common.tracking.GPSFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
@@ -771,6 +773,15 @@ public interface TrackedRace extends Serializable {
boolean isUsingMarkPassingCalculator();
/**
* @param timepoint Used for positions of marks and wind information
* @return estimated time it takes to complete the race
* @throws NotEnoughDataHasBeenAddedException thrown if not enough polar data has been added or polar data service
* is not available
* @throws NoWindException
*/
Duration getEstimatedTimeToComplete(TimePoint timepoint) throws NotEnoughDataHasBeenAddedException, NoWindException;
void setPolarDataService(PolarDataService polarDataService);
}
@@ -478,6 +478,7 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
// clearMarkPassings(...) as well as inside the subsequent for-loop. It is important to always first obtain the mark passings lock
// for the competitor mark passings before obtaining the lock for the mark passings in order for the waypoint to avoid
// deadlocks.
getRace().getCourse().lockForRead();
LockUtil.lockForWrite(markPassingsLock);
try {
clearMarkPassings(competitor);
@@ -529,6 +530,7 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
}
} finally {
LockUtil.unlockAfterWrite(markPassingsLock);
getRace().getCourse().unlockAfterRead();
}
updated(timePointOfLatestEvent);
triggerManeuverCacheRecalculation(competitor);
@@ -660,7 +662,8 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
if ((startOfTracking == null || !startOfTracking.minus(TrackedRaceImpl.TIME_BEFORE_START_TO_TRACK_WIND_MILLIS).after(wind.getTimePoint()) ||
(startOfRace != null && !startOfRace.minus(TrackedRaceImpl.TIME_BEFORE_START_TO_TRACK_WIND_MILLIS).after(wind.getTimePoint())))
&&
(endOfTracking == null || endOfTracking.plus(TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS).after(wind.getTimePoint()) ||
// Caution: don't add to endOfTracking; it may be the end of time, leading to a wrap-around / overflow
(endOfTracking == null || endOfTracking.after(wind.getTimePoint().minus(TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS)) ||
(endOfRace != null && endOfRace.plus(TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS).after(wind.getTimePoint())))) {
result = getOrCreateWindTrack(windSource).add(wind);
updated(/* time point */null); // wind events shouldn't advance race time
@@ -13,23 +13,31 @@ import java.util.Set;
import java.util.concurrent.Callable;
import java.util.logging.Logger;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
import com.sap.sailing.domain.base.SpeedWithConfidence;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.LegType;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.Tack;
import com.sap.sailing.domain.common.Wind;
import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.common.WindSourceType;
import com.sap.sailing.domain.common.impl.MeterDistance;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.tracking.TrackedLeg;
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRaceStatus;
import com.sap.sailing.domain.tracking.WindLegTypeAndLegBearingCache;
import com.sap.sailing.domain.tracking.WindPositionMode;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
@@ -368,4 +376,44 @@ public class TrackedLegImpl implements TrackedLeg {
return result;
}
@Override
public Duration getEstimatedTimeToComplete(PolarDataService polarDataService, TimePoint timepoint)
throws NotEnoughDataHasBeenAddedException, NoWindException {
Position centralPosition = trackedRace.getCenterOfCourse(timepoint);
Wind wind = trackedRace.getWind(centralPosition, timepoint, getTrackedRace().getWindSources(WindSourceType.TRACK_BASED_ESTIMATION));
Position from = trackedRace.getApproximatePosition(leg.getFrom(), timepoint);
Position to = trackedRace.getApproximatePosition(leg.getTo(), timepoint);
LegType legType = getLegType(timepoint);
BoatClass boatClass = trackedRace.getRace().getBoatClass();
Duration result;
if (legType == LegType.REACHING) {
Bearing trueWindAngle = wind.getBearing().getDifferenceTo(from.getBearingGreatCircle(to));
SpeedWithConfidence<Void> reachSpeed = polarDataService.getSpeed(boatClass, wind, trueWindAngle);
Distance distance = from.getDistance(to);
result = reachSpeed.getObject().getDuration(distance);
} else {
SpeedWithBearingWithConfidence<Void> portSpeedAndBearing = polarDataService.getAverageSpeedWithBearing(
boatClass, wind, legType, Tack.PORT);
SpeedWithBearingWithConfidence<Void> starboardSpeedAndBearing = polarDataService.getAverageSpeedWithBearing(
boatClass, wind, legType, Tack.STARBOARD);
result = estimateTargetTimeTacking(from, to, portSpeedAndBearing, starboardSpeedAndBearing, wind);
}
return result;
}
private Duration estimateTargetTimeTacking(Position from, Position to,
SpeedWithBearingWithConfidence<Void> portSpeedAndBearing,
SpeedWithBearingWithConfidence<Void> starboardSpeedAndBearing, Wind wind) {
Bearing portBearing = portSpeedAndBearing.getObject().getBearing();
Bearing starboardBearing = starboardSpeedAndBearing.getObject().getBearing();
Position intersection = from.getIntersection(portBearing, to, starboardBearing);
Distance fromToIntersection = from.getDistance(intersection);
Speed portSpeed = portSpeedAndBearing.getObject();
Duration duration1 = portSpeed.getDuration(fromToIntersection);
Distance fromToTo = intersection.getDistance(to);
Speed starboardSpeed = starboardSpeedAndBearing.getObject();
Duration duration2 = starboardSpeed.getDuration(fromToTo);
return duration1.plus(duration2);
}
}
@@ -130,6 +130,7 @@ 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;
@@ -3514,6 +3515,20 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
return result;
}
@Override
public Duration getEstimatedTimeToComplete(TimePoint timepoint) throws NotEnoughDataHasBeenAddedException,
NoWindException {
if (polarDataService == null) {
throw new NotEnoughDataHasBeenAddedException("Target time estimation failed. No polar service available.");
}
Duration durationOfAllLegs = new MillisecondsDurationImpl(0);
for (TrackedLeg leg : trackedLegs.values()) {
Duration durationOfLeg = leg.getEstimatedTimeToComplete(polarDataService, timepoint);
durationOfAllLegs = durationOfAllLegs.plus(durationOfLeg);
}
return durationOfAllLegs;
}
@Override
public void setPolarDataService(PolarDataService polarDataService) {
this.polarDataService = polarDataService;
@@ -86,4 +86,9 @@ public class ScoreCorrectionProviderImpl implements ScoreCorrectionProvider, Res
}
return null;
}
@Override
public String getOptionalSampleURL() {
return null;
}
}
@@ -0,0 +1,14 @@
apply plugin: "java"
sourceSets {
main {
java.srcDirs = ["src"]
}
}
dependencies {
compile "com.googlecode.json-simple:json-simple:1.1.1"
/* local dependencies */
compile project(":java:com.sap.sailing.domain.common")
}
@@ -38,6 +38,7 @@ import com.sap.sailing.domain.common.racelog.Flags;
import com.sap.sailing.domain.common.tracking.GPSFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.leaderboard.ScoringScheme;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
@@ -65,6 +66,7 @@ import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sailing.domain.tracking.WindWithConfidence;
import com.sap.sailing.domain.tracking.impl.WindTrackImpl;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
@@ -907,4 +909,11 @@ public class MockedTrackedRace implements DynamicTrackedRace {
@Override
public void setPolarDataService(PolarDataService polarDataService) {
}
@Override
public Duration getEstimatedTimeToComplete(TimePoint timepoint) throws NotEnoughDataHasBeenAddedException,
NoWindException {
// TODO Auto-generated method stub
return null;
}
}
File mode changed.
@@ -8,7 +8,7 @@
<listEntry value="com.sap.sailing.gwt.ui.Simulator"/>
<listEntry value="com.sap.sailing.gwt.ui.Leaderboard"/>
<listEntry value="com.sap.sailing.gwt.ui.PolarSheets"/>
<listEntry value="com.sap.sailing.gwt.regattaoverview.RegattaOverview"/>
<listEntry value="com.sap.sailing.gwt.ui.RegattaOverview"/>
<listEntry value="com.sap.sailing.gwt.ui.Spectator"/>
<listEntry value="com.sap.sailing.gwt.ui.AdminConsole"/>
<listEntry value="com.sap.sailing.gwt.ui.LeaderboardEditing"/>
@@ -71,7 +71,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="-superDevMode -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 -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.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.AdminConsole com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.Home com.sap.sailing.gwt.ui.RaceBoard"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-superDevMode -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 -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 -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup 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.ui.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.Home 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>
@@ -12,7 +12,7 @@
<listEntry value="com.sap.sailing.gwt.ui.LeaderboardEditing"/>
<listEntry value="com.sap.sailing.gwt.ui.AdminConsole"/>
<listEntry value="com.sap.sailing.gwt.ui.Spectator"/>
<listEntry value="com.sap.sailing.gwt.regattaoverview.RegattaOverview"/>
<listEntry value="com.sap.sailing.gwt.ui.RegattaOverview"/>
<listEntry value="com.sap.sailing.gwt.AutoPlay"/>
<listEntry value="com.sap.sailing.gwt.ui.VideoPopup"/>
<listEntry value="com.sap.sailing.gwt.ui.PolarSheets"/>
@@ -69,7 +69,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 auto -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.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup -startupUrl /security/ui/Login.html com.sap.sse.security.ui.Login -startupUrl /security/ui/EditProfile.html com.sap.sse.security.ui.EditProfile -startupUrl /security/ui/EmailValidation.html com.sap.sse.security.ui.EmailValidation com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.ui.PolarSheets com.sap.sailing.gwt.ui.VideoPopup com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.regattaoverview.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.Home com.sap.sailing.gwt.ui.RaceBoard"/>
<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 auto -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 -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup -startupUrl /security/ui/Login.html com.sap.sse.security.ui.Login -startupUrl /security/ui/EditProfile.html com.sap.sse.security.ui.EditProfile -startupUrl /security/ui/EmailValidation.html com.sap.sse.security.ui.EmailValidation com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.ui.PolarSheets com.sap.sailing.gwt.ui.VideoPopup com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.Home 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>
@@ -1,2 +1 @@
deploy
classes
+1
View File
@@ -0,0 +1 @@
/*
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10.3 22.2"><path fill="#FFF" d="M6.9 22.2H2.3V11.1H0V7.3h2.3V5c0-3.1 1.3-5 5-5h3.1v3.8h-2c-1.4 0-1.5.6-1.5 1.6v1.9h3.5l-.4 3.8H6.9v11.1z"/></svg>

After

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 23.5 19.1"><path fill="#FFF" d="M23.48 2.293c-.9.4-1.8.6-2.8.8 1-.6 1.8-1.5 2.1-2.7-.9.6-2 1-3.1 1.2-.9-.9-2.1-1.5-3.5-1.5-2.7 0-4.8 2.2-4.8 4.8 0 .4 0 .7.1 1.1-4-.2-7.6-2.1-9.9-5-.4.7-.7 1.5-.7 2.4 0 1.7.9 3.1 2.1 4-.8 0-1.5-.2-2.2-.6v.1c0 2.3 1.7 4.3 3.9 4.7-.4.1-.8.2-1.3.2-.3 0-.6 0-.9-.1.6 1.9 2.4 3.3 4.5 3.3-1.7 1.3-3.7 2.1-6 2.1-.4 0-.8 0-1.2-.1 2.1 1.4 4.7 2.2 7.4 2.2 8.9 0 13.7-7.3 13.7-13.7v-.6c1.2-.8 2-1.7 2.6-2.6z"/></svg>

After

Width:  |  Height:  |  Size: 490 B

@@ -6,6 +6,12 @@ import java.util.Map;
import com.google.gwt.resources.client.ImageResource;
import com.sap.sailing.domain.common.BoatClassMasterdata;
/**
* All images are expected to be 140x140px with transparent background.
*
* @author Steffen Tobias Wagner, Axel Uhl (D043530)
*
*/
public class BoatClassImageResolver {
private static Map<String, ImageResource> boatClassIconsMap;
private static BoatClassImageResources imageResources = BoatClassImageResources.INSTANCE;
@@ -52,6 +58,7 @@ public class BoatClassImageResolver {
boatClassIconsMap.put(BoatClassMasterdata.NACRA_17.getDisplayName(), imageResources.Nacra17Icon());
boatClassIconsMap.put(BoatClassMasterdata.OK.getDisplayName(), imageResources.OKIcon());
boatClassIconsMap.put(BoatClassMasterdata.OPTIMIST.getDisplayName(), imageResources.OptimistIcon());
boatClassIconsMap.put(BoatClassMasterdata.PIRAT.getDisplayName(), imageResources.PiratIcon());
boatClassIconsMap.put(BoatClassMasterdata.PLATU_25.getDisplayName(), imageResources.Platu25Icon());
boatClassIconsMap.put(BoatClassMasterdata.RS_X.getDisplayName(), imageResources.RSXIcon());
boatClassIconsMap.put(BoatClassMasterdata.SONAR.getDisplayName(), imageResources.SonarIcon());
@@ -115,6 +115,9 @@ public interface BoatClassImageResources extends ClientBundle {
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/OPTIMIST.png")
ImageResource OptimistIcon();
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/PIRAT.png")
ImageResource PiratIcon();
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/PLATU_25.png")
ImageResource Platu25Icon();
@@ -31,10 +31,6 @@
/* font-size: 0; */
margin-bottom: -1px;
}
.navigation a{
border-top-left-radius:4px;
border-top-right-radius:4px;
}
.tabExtension {
float: right;
margin-left: 0.5em;
@@ -1,16 +1,18 @@
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:s="urn:import:com.sap.sailing.gwt.home.client.shared">
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:style>
.mainContent {
min-height: 400px;
height: 100%;
}
</ui:style>
<g:HTMLPanel>
<s:header.Header ui:field="headerPanel" />
<g:SimplePanel ui:field="mainContentPanel" styleName="{style.mainContent}" />
<g:HTMLPanel addStyleNames="{style.mainContent}">
<div class="{res.mainCss.wrapper}">
<s:header.Header ui:field="headerPanel" />
<g:SimplePanel ui:field="mainContentPanel" />
</div>
<s:footer.Footer ui:field="footerPanel" />
</g:HTMLPanel>
</ui:UiBinder>
@@ -4,10 +4,11 @@
.sitefooter {
font-size: 1rem;
background: #333;
border-top: 5px solid #fff;
border-top: 0.333333333333333em solid #fff;
color: #fff;
line-height: 5em;
width: 100%;
margin-top: -5.333333333333333em;
padding: 0 1.333333333333333em;
}
.sitefooter_copyright {
@@ -48,7 +49,7 @@
}
}
.sitefooter_language_link {
color: #f0ab00;
color: #efaa00;
display: inline-block;
cursor: pointer;
margin-left: 0.666666666666667em;
@@ -5,9 +5,8 @@
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:with field="local_res" type="com.sap.sailing.gwt.home.client.shared.footer.FooterResources" />
<ui:with field="releaseNotesNavigation" type="com.sap.sailing.gwt.home.client.app.PlaceNavigation" />
<g:HTMLPanel>
<g:HTMLPanel tag="footer" addStyleNames="{local_res.css.sitefooter}">
<!-- Website footer-->
<footer class="{local_res.css.sitefooter}">
<div class="{res.mediaCss.grid}">
<div class="{res.mediaCss.small12} {res.mediaCss.medium9} {res.mediaCss.columns}">
<div class="{local_res.css.sitefooter_copyright}">
@@ -36,6 +35,5 @@
<g:Anchor ui:field="changeLanguageLink" styleName="{local_res.css.sitefooter_language_link}" />
</div>
</div>
</footer>
</g:HTMLPanel>
</ui:UiBinder>
@@ -86,9 +86,9 @@
width: 13.333333333333334em;
}
.search_button {
width: 2.666666666666667em;
height: 1em;
vertical-align: middle;
width: 2.666666666666667em !important;
height: 1em !important;
vertical-align: middle !important;
}
@media (min-width: 61em) {
.search_button {
@@ -5,9 +5,8 @@
<ui:with field="i18n" type="com.sap.sailing.gwt.common.client.i18n.TextMessages" />
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:with field="local_res" type="com.sap.sailing.gwt.home.client.shared.header.HeaderResources" />
<g:HTMLPanel>
<g:HTMLPanel tag="header" addStyleNames="{local_res.css.siteheader}">
<!-- Website header-->
<header class="{local_res.css.siteheader}">
<div class="{res.mediaCss.grid}">
<div class="{local_res.css.siteheader_logo} {res.mediaCss.small2} {res.mediaCss.medium2} {res.mediaCss.large3} {res.mediaCss.columns}">
<a href="http://sapsponsorships.com">
@@ -36,6 +35,5 @@
<!-- IFEND siteNavigation.current -->
</nav>
</div>
</header>
</g:HTMLPanel>
</ui:UiBinder>
@@ -1,66 +0,0 @@
/**
* Events on the main page
*/
.socialfooter {
font-size: 16px;
font-size: 1rem;
background: #008fcc;
color: #fff;
}
.socialfooter .mainsection_header {
margin-bottom: 1.25em;
}
.socialfooter .mainsection_header_title {
color: #fff;
}
.socialfooter_button {
position: relative;
display: inline-block;
width: 19.0625em;
height: 3.75em;
margin: 0 0.9375em;
}
.socialfooter_button:before {
content: ' ';
position: absolute;
width: 3.125em;
height: 3.75em;
left: 0;
background: url("images/home/social-icons.png");
}
.socialfooter_buttontwitter {
background: #58aeee;
}
.socialfooter_buttontwitter:before {
background-position: 0 0;
}
.socialfooter_buttonfacebook {
background: #3b5998;
}
.socialfooter_buttonfacebook:before {
background-position: 100% 0;
}
.socialfooter_button_text {
position: absolute;
left: 3.125em;
width: 10em;
padding: 0.3125em 0.625em;
margin: 0.3125em 0;
border-left: 1px solid rgba(255,255,255,0.2);
text-align: left;
line-height: 1;
}
.socialfooter_button_text span {
font-size: 1.5em;
font-weight: 600;
}
.socialfooter_button_widget {
position: absolute;
right: 0.625em;
top: 50%;
-webkit-transform: translate(0, -40%);
-moz-transform: translate(0, -40%);
-o-transform: translate(0, -40%);
-ms-transform: translate(0, -40%);
transform: translate(0, -40%);
}
@@ -0,0 +1,58 @@
/**
* Events on the main page
*/
.socialfooter {
font-size: 1rem;
background: #008fcc;
color: #fff;
padding: 5.333333333333333em 0 7.333333333333333em;
}
.socialfooter_heading {
text-align: center;
font-size: 2.4em;
margin-bottom: 0.833333333333333em;
}
.socialfooter_item {
white-space: nowrap;
}
.socialfooter_item a {
color: #f6f9fc;
}
.socialfooter_item_contentwrapper {
padding: 1.133333333333333em 6.666666666666667em 1.4em 0.666666666666667em;
}
.socialfooter_item_contentwrappertwitter {
background: #58aeee;
padding-left: 1.133333333333333em;
}
.socialfooter_item_contentwrapperfacebook {
background: #3b5998;
padding-left: 1.333333333333333em;
}
.socialfooter_itemleft {
text-align: right;
}
.socialfooter_itemright {
text-align: left;
}
img.socialfooter_item_icon {
display: inline-block;
vertical-align: middle;
height: 1.666666666666667em;
}
.socialfooter_item_text {
line-height: 1;
text-align: left;
vertical-align: middle;
display: inline-block;
padding: 0.2em 0 0.2em 0.8em;
margin-left: 1em;
border-left: 1px solid rgba(246,249,252,0.2);
}
.socialfooter_item_text_top {
font-size: 1em;
}
.socialfooter_item_text_bottom {
font-size: 1.466666666666667em;
font-weight: 600;
}
@@ -1,30 +1,41 @@
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui"
xmlns:s="urn:import:com.sap.sailing.gwt.home.client.shared">
<ui:with field="i18n" type="com.sap.sailing.gwt.common.client.i18n.TextMessages"/>
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:with field="local_res" type="com.sap.sailing.gwt.home.client.shared.socialfooter.SocialFooterResources" />
<g:HTMLPanel>
<!-- The search/social media page footer-->
<div class="{res.mainCss.mainsection} {local_res.css.socialfooter}">
<div class="{res.mediaCss.grid}">
<div class="{res.mediaCss.small12} {res.mediaCss.columns}">
<header class="{res.mainCss.mainsection_header}">
<h3 class="{local_res.css.mainsection_header_title}">Follow SAP Sports</h3>
</header>
<div class="{res.mainCss.mainsection_navigation}">
<a href="http://twitter.com/SAPSports" target="_blank" class="{local_res.css.socialfooter_button} {local_res.css.socialfooter_buttontwitter}" style="color:white;">
<div class="{local_res.css.socialfooter_button_text}">SAP Sports on <span>Twitter</span></div>
<div class="{local_res.css.socialfooter_button_widget}"></div>
</a>
<a href="http://www.facebook.com/SAPSports" target="_blank" class="{local_res.css.socialfooter_button} {local_res.css.socialfooter_buttonfacebook}" style="color:white;">
<div class="{local_res.css.socialfooter_button_text}">SAP Sports on <span>Facebook</span></div>
<div class="{local_res.css.socialfooter_button_widget}"></div>
</a>
xmlns:s="urn:import:com.sap.sailing.gwt.home.client.shared">
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
<ui:with field="i18n_ubi" type="com.sap.sailing.gwt.common.client.i18n.TextMessages"/>
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:with field="local_res" type="com.sap.sailing.gwt.home.client.shared.socialfooter.SocialFooterResources" />
<g:HTMLPanel>
<!-- The search/social media page footer-->
<div class="{local_res.css.socialfooter}">
<div class="{res.mediaCss.grid}">
<h3 class="{local_res.css.socialfooter_heading} {res.mediaCss.small12} {res.mediaCss.columns}">
<ui:text from="{i18n.followSapSports}" />
</h3>
<div class="{local_res.css.socialfooter_item} {local_res.css.socialfooter_itemleft} {res.mediaCss.small6} {res.mediaCss.columns}">
<a href="http://twitter.com/SAPSports" target="_blank" class="{local_res.css.socialfooter_item_contentwrapper} {local_res.css.socialfooter_item_contentwrappertwitter}">
<img src="images/home/twitter-logo.svg" class="{local_res.css.socialfooter_item_icon}"></img>
<div class="{local_res.css.socialfooter_item_text}">
<div class="{local_res.css.socialfooter_item_text_top}">
<ui:text from='{i18n.sapSportsOn}' />
</div>
<div class="{local_res.css.socialfooter_item_text_bottom}">Twitter</div>
</div>
</a>
</div>
<div class="{local_res.css.socialfooter_item} {local_res.css.socialfooter_itemright} {res.mediaCss.small6} {res.mediaCss.columns}">
<a href="http://www.facebook.com/SAPSports" target="_blank" class="{local_res.css.socialfooter_item_contentwrapper} {local_res.css.socialfooter_item_contentwrapperfacebook}">
<img src="images/home/facebook-logo.svg" class="{local_res.css.socialfooter_item_icon}"></img>
<div class="{local_res.css.socialfooter_item_text}">
<div class="{local_res.css.socialfooter_item_text_top}">
<ui:text from='{i18n.sapSportsOn}' />
</div>
<div class="{local_res.css.socialfooter_item_text_bottom}">Facebook</div>
</div>
</a>
</div>
</div>
</div>
</div>
</div>
</g:HTMLPanel>
</g:HTMLPanel>
</ui:UiBinder>
@@ -7,17 +7,21 @@ import com.google.gwt.resources.client.CssResource;
public interface SocialFooterResources extends ClientBundle {
public static final SocialFooterResources INSTANCE = GWT.create(SocialFooterResources.class);
@Source("com/sap/sailing/gwt/home/client/shared/socialfooter/SocialFooter.css")
@Source("SocialFooter.gss")
LocalCss css();
public interface LocalCss extends CssResource {
String socialfooter();
String mainsection_header();
String mainsection_header_title();
String socialfooter_button();
String socialfooter_buttontwitter();
String socialfooter_buttonfacebook();
String socialfooter_button_text();
String socialfooter_button_widget();
String socialfooter_heading();
String socialfooter_item();
String socialfooter_item_contentwrapper();
String socialfooter_item_contentwrappertwitter();
String socialfooter_item_contentwrapperfacebook();
String socialfooter_itemleft();
String socialfooter_itemright();
String socialfooter_item_icon();
String socialfooter_item_text();
String socialfooter_item_text_top();
String socialfooter_item_text_bottom();
}
}
@@ -22,7 +22,7 @@
padding: 1em 0 0.733333333333333em 0;
border-bottom: 0.266666666666667em solid transparent;
font-weight: 600;
color: #666;
color: #333;
-webkit-transition: 0.2s border ease;
-moz-transition: 0.2s border ease;
-o-transition: 0.2s border ease;
@@ -35,7 +35,7 @@
.solutions_nav_linkactive {
border-bottom-color: #f0ab00;
text-decoration: none;
color: #333;
color: #666;
}
.solutions_nav_link:last-child {
margin-right: 0;
@@ -4,13 +4,11 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Random;
@@ -58,6 +56,7 @@ import com.sap.sailing.server.RacingEventService;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.TimeRange;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.impl.TimeRangeImpl;
@@ -182,9 +181,8 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home
EventHolder holder = pair.getB();
result.addStageEvent(convertToEventStageDTO(holder.event, holder.baseURL, holder.onRemoteServer, stageType));
// TODO implement better that using a hard cast...
Collection<URL> videosOfEvent = (Collection<URL>) holder.event.getVideoURLs();
if (videosOfEvent.size() > 0 && result.getVideos().size() < MAX_VIDEO_COUNT) {
Iterable<URL> videosOfEvent = holder.event.getVideoURLs();
if (!Util.isEmpty(videosOfEvent) && result.getVideos().size() < MAX_VIDEO_COUNT) {
URL youTubeRandomUrl = HomeServiceUtil.getRandomURL(videosOfEvent);
VideoMetadataDTO candidate = new VideoMetadataDTO(youTubeRandomUrl, holder.event.getName());
if (candidate.getType() == VideoType.YOUTUBE) {
@@ -279,9 +277,7 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home
boolean isFakeSeries = HomeServiceUtil.isFakeSeries(event);
for (Iterator<LeaderboardGroup> iter = event.getLeaderboardGroups().iterator(); iter.hasNext();) {
LeaderboardGroup leaderboardGroup = iter.next();
for (LeaderboardGroup leaderboardGroup : event.getLeaderboardGroups()) {
for (Leaderboard leaderboard : leaderboardGroup.getLeaderboards()) {
if(leaderboard instanceof RegattaLeaderboard) {
Regatta regatta = getService().getRegattaByName(leaderboard.getName());
@@ -2,7 +2,6 @@ package com.sap.sailing.gwt.home.server;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
@@ -202,7 +201,7 @@ public final class HomeServiceUtil {
*/
public static URL getStageImageURL(final EventBase event) {
final URL result;
if (!event.getImageURLs().iterator().hasNext()) {
if (Util.isEmpty(event.getImageURLs())) {
result = null;
} else {
Comparator<URL> stageImageComparator = new Comparator<URL>() {
@@ -288,21 +287,13 @@ public final class HomeServiceUtil {
}
public static int calculateCompetitorsCount(Leaderboard sl) {
int count=0;
for (Iterator<Competitor> iterator = sl.getCompetitors().iterator(); iterator.hasNext();) {
iterator.next();
count++;
}
return count;
return Util.size(sl.getCompetitors());
}
public static int calculateRaceCount(Leaderboard sl) {
int count=0;
for (RaceColumn column : sl.getRaceColumns()) {
for (Iterator<? extends Fleet> iterator = column.getFleets().iterator(); iterator.hasNext();) {
iterator.next();
count++;
}
count += Util.size(column.getFleets());
}
return count;
}
@@ -344,16 +335,11 @@ public final class HomeServiceUtil {
public static boolean hasPhotos(Event event) {
// FIXME filter teaser images
Iterator<URL> iterator = event.getImageURLs().iterator();
if(!iterator.hasNext()) {
return false;
}
iterator.next();
return iterator.hasNext();
return Util.size(event.getImageURLs()) > 1;
}
public static boolean hasVideos(Event event) {
return event.getVideoURLs().iterator().hasNext();
return !Util.isEmpty(event.getVideoURLs());
}
public static boolean isPartOfEvent(Event event, Regatta regattaEntity) {
@@ -365,11 +351,11 @@ public final class HomeServiceUtil {
return false;
}
public static URL getRandomURL(Collection<URL> urls) {
List<URL> videoURLs = new ArrayList<URL>((Collection<URL>)urls);
if (videoURLs.isEmpty()) {
public static URL getRandomURL(Iterable<URL> urls) {
if(Util.isEmpty(urls)) {
return null;
}
return videoURLs.get(new Random(videoURLs.size()).nextInt(videoURLs.size()));
int size = Util.size(urls);
return Util.get(urls, new Random(size).nextInt(size));
}
}
@@ -40,8 +40,6 @@ public class DeviceConfigurationDetailComposite extends Composite {
void onCloneRequested(DeviceConfigurationMatcherDTO matcher, DeviceConfigurationDTO configuration);
}
private static List<String> suggestedCourseNames = Arrays.asList("Upwind", "Downwind");
private final AdminConsoleResources resources = GWT.create(AdminConsoleResources.class);
protected final SailingServiceAsync sailingService;
@@ -82,7 +80,7 @@ public class DeviceConfigurationDetailComposite extends Composite {
captionPanel = new CaptionPanel(stringMessages.configuration());
VerticalPanel verticalPanel = new VerticalPanel();
contentPanel = new VerticalPanel();
cloneButton = new Button(stringMessages.save() + " + " + "Clone");
cloneButton = new Button(stringMessages.save() + " + " + stringMessages.clone());
cloneButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
@@ -196,7 +194,7 @@ public class DeviceConfigurationDetailComposite extends Composite {
protected void setupIdentifier(Grid grid, int gridRow) {
identifierBox = new TextBox();
identifierBox.setWidth("80%");
identifierBox.setText(DeviceConfigurationPanel.renderIdentifiers(matcher.clients));
identifierBox.setText(DeviceConfigurationPanel.renderIdentifiers(matcher.clients, stringMessages));
identifierBox.setReadOnly(true);
grid.setWidget(gridRow, 0, new Label("Identifier"));
@@ -220,6 +218,7 @@ public class DeviceConfigurationDetailComposite extends Composite {
List<String> initialValues = originalConfiguration.byNameDesignerCourseNames == null ? Collections
.<String> emptyList() : originalConfiguration.byNameDesignerCourseNames;
List<String> suggestedCourseNames = Arrays.asList(stringMessages.upWind(), stringMessages.downWind());
courseNamesList = new StringListEditorComposite(initialValues, stringMessages, stringMessages.courseNames(), IconResources.INSTANCE.removeIcon(), suggestedCourseNames,
stringMessages.enterCourseName());
courseNamesList.setWidth("80%");
@@ -248,7 +247,7 @@ public class DeviceConfigurationDetailComposite extends Composite {
private void markAsDirty(boolean dirty) {
if (dirty) {
if (captionPanel.getCaptionText().equals(stringMessages.configuration())) {
captionPanel.setCaptionText(stringMessages.configuration() + "* (CHANGED)");
captionPanel.setCaptionText(stringMessages.configuration() + "* ("+stringMessages.changed()+")");
}
} else {
if (!captionPanel.getCaptionText().equals(stringMessages.configuration())) {
@@ -39,7 +39,7 @@ public class DeviceConfigurationListComposite extends Composite {
private final SailingServiceAsync sailingService;
private final ErrorReporter errorReporter;
private final StringMessages stringMessages;
protected final StringMessages stringMessages;
public DeviceConfigurationListComposite(final SailingServiceAsync sailingService,
final SelectionProvider<DeviceConfigurationMatcherDTO> selectionProvider,
@@ -130,7 +130,7 @@ public class DeviceConfigurationListComposite extends Composite {
new TextColumn<DeviceConfigurationMatcherDTO>() {
@Override
public String getValue(DeviceConfigurationMatcherDTO identifier) {
return DeviceConfigurationPanel.renderIdentifiers(identifier.clients);
return DeviceConfigurationPanel.renderIdentifiers(identifier.clients, stringMessages);
}
};
identifierNameColumn.setSortable(true);
@@ -141,8 +141,8 @@ public class DeviceConfigurationListComposite extends Composite {
}
});
table.addColumn(identifierTypeColumn, "Matcher");
table.addColumn(identifierNameColumn, "Device");
table.addColumn(identifierTypeColumn, stringMessages.matcher());
table.addColumn(identifierNameColumn, stringMessages.device());
return table;
}
@@ -28,11 +28,11 @@ import com.sap.sse.gwt.client.dialog.DataEntryDialog.Validator;
public class DeviceConfigurationPanel extends SimplePanel implements SelectionChangeListener<DeviceConfigurationMatcherDTO>, DeviceConfigurationCloneListener {
public static String renderIdentifiers(List<String> clientIdentifiers) {
public static String renderIdentifiers(List<String> clientIdentifiers, StringMessages stringMessages) {
if (clientIdentifiers.size() == 1) {
return clientIdentifiers.get(0);
} else if (clientIdentifiers.size() == 0) {
return "[ANY]";
return "["+stringMessages.any()+"]";
} else {
return clientIdentifiers.toString();
}
@@ -34,7 +34,7 @@ public class DeviceConfigurationUserListComposite extends DeviceConfigurationLis
new TextColumn<DeviceConfigurationMatcherDTO>() {
@Override
public String getValue(DeviceConfigurationMatcherDTO identifier) {
return DeviceConfigurationPanel.renderIdentifiers(identifier.clients);
return DeviceConfigurationPanel.renderIdentifiers(identifier.clients, stringMessages);
}
};
identifierNameColumn.setSortable(true);
@@ -45,7 +45,7 @@ public class DeviceConfigurationUserListComposite extends DeviceConfigurationLis
}
});
table.addColumn(identifierNameColumn, "Device");
table.addColumn(identifierNameColumn, stringMessages.device());
return table;
}
@@ -3,6 +3,7 @@ package com.sap.sailing.gwt.ui.adminconsole;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HorizontalPanel;
@@ -38,17 +39,12 @@ public class GateCreationDialog extends DataEntryDialog<GateDTO> {
}
return null;
}
}, /* animationEnabled */ false, callback);
this.stringMessages = stringMessages;
name = createTextBox("");
marksWrapper = new MarkTableWrapper<MultiSelectionModel<MarkDTO>>(
/* multiSelection */ true, sailingService, stringMessages, errorReporter);
marksWrapper.getDataProvider().getList().addAll(marks);
marksWrapper.getSelectionModel().addSelectionChangeHandler(new Handler() {
@Override
public void onSelectionChange(SelectionChangeEvent event) {
@@ -66,23 +62,19 @@ public class GateCreationDialog extends DataEntryDialog<GateDTO> {
Iterator<MarkDTO> i = marksWrapper.getSelectionModel().getSelectedSet().iterator();
MarkDTO first = i.next();
MarkDTO second = i.next();
controlPoint = new GateDTO(/* generate UUID on the server */ null, name.getText(), first, second);
controlPoint = new GateDTO(UUID.randomUUID().toString(), name.getText(), first, second);
}
return controlPoint;
}
@Override
protected Widget getAdditionalWidget() {
Grid grid = new Grid(2,1);
HorizontalPanel nameRow = new HorizontalPanel();
nameRow.add(new Label(stringMessages.name()));
nameRow.add(name);
grid.setWidget(0, 0, nameRow);
grid.setWidget(1, 0, marksWrapper);
return grid;
}
}
@@ -62,17 +62,16 @@ public class RaceLogTrackingCompetitorRegistrationsDialog extends AbstractSaveDi
}
private void move(CompetitorTableWrapper<?> from, CompetitorTableWrapper<?> to, Collection<CompetitorDTO> toMove) {
if (toMove.isEmpty()) {
return;
if (!toMove.isEmpty()) {
List<CompetitorDTO> newFromList = new ArrayList<>();
Util.addAll(from.getFilterField().getAll(), newFromList);
newFromList.removeAll(toMove);
from.getFilterField().updateAll(newFromList);
List<CompetitorDTO> newToList = new ArrayList<>();
Util.addAll(to.getFilterField().getAll(), newToList);
newToList.addAll(toMove);
to.getFilterField().updateAll(newToList);
}
List<CompetitorDTO> newFromList = new ArrayList<>();
Util.addAll(from.getFilterField().getAll(), newFromList);
newFromList.removeAll(toMove);
from.getFilterField().updateAll(newFromList);
List<CompetitorDTO> newToList = new ArrayList<>();
Util.addAll(to.getFilterField().getAll(), newToList);
newToList.addAll(toMove);
to.getFilterField().updateAll(newToList);
}
private void moveSelected(CompetitorTableWrapper<MultiSelectionModel<CompetitorDTO>> from,
@@ -105,7 +105,7 @@ public class RaceLogTrackingDeviceMappingsDialog extends RaceLogTrackingDialog {
public void cancel() {}
}).show();
} else if (RaceLogTrackingDeviceMappingsImagesBarCell.ACTION_REMOVE.equals(value)) {
sailingService.revokeRaceLogEvents(leaderboardName, raceColumnName, fleetName, dto.originalRaceLogEventIds,
sailingService.revokeRaceAndRegattaLogEvents(leaderboardName, raceColumnName, fleetName, dto.originalRaceLogEventIds,
new AsyncCallback<Void>() {
@Override
public void onFailure(Throwable caught) {
@@ -50,6 +50,7 @@ public class RaceLogTrackingEventManagementPanel extends AbstractLeaderboardConf
private TrackFileImportDeviceIdentifierTableWrapper deviceIdentifierTable;
private CheckBox correctWindDirectionForDeclination;
private CheckBox trackWind;
protected boolean regattaHasCompetitors = false;
public RaceLogTrackingEventManagementPanel(SailingServiceAsync sailingService,
RegattaRefresher regattaRefresher, LeaderboardsRefresher leaderboardsRefresher,
@@ -351,6 +352,7 @@ public class RaceLogTrackingEventManagementPanel extends AbstractLeaderboardConf
@Override
protected void leaderboardSelectionChanged() {
StrippedLeaderboardDTO selectedLeaderboard = getSelectedLeaderboard();
regattaHasCompetitors = false;
if (leaderboardSelectionModel.getSelectedSet().size() == 1 && selectedLeaderboard != null) {
raceColumnTable.getDataProvider().getList().clear();
for (RaceColumnDTO raceColumn : selectedLeaderboard.getRaceList()) {
@@ -363,6 +365,8 @@ public class RaceLogTrackingEventManagementPanel extends AbstractLeaderboardConf
if (!selectedLeaderboard.type.isMetaLeaderboard()) {
trackedRacesCaptionPanel.setVisible(true);
}
sailingService.doesRegattaLogContainCompetitors(((StrippedLeaderboardDTO) leaderboardSelectionModel.getSelectedSet().toArray()[0]).name, new RegattaLogCallBack());
} else {
selectedLeaderBoardPanel.setVisible(false);
trackedRacesCaptionPanel.setVisible(false);
@@ -370,6 +374,19 @@ public class RaceLogTrackingEventManagementPanel extends AbstractLeaderboardConf
raceColumnTableSelectionModel.clear();
}
private class RegattaLogCallBack implements AsyncCallback<Boolean>{
@Override
public void onFailure(Throwable caught) {
regattaHasCompetitors = false;
}
@Override
public void onSuccess(Boolean result) {
regattaHasCompetitors = true;
}
}
private void denoteForRaceLogTracking(final StrippedLeaderboardDTO leaderboard) {
sailingService.denoteForRaceLogTracking(leaderboard.name, new AsyncCallback<Void>() {
@Override
@@ -419,9 +436,12 @@ public class RaceLogTrackingEventManagementPanel extends AbstractLeaderboardConf
final StrippedLeaderboardDTO leaderboard = getSelectedLeaderboard();
//prompt user if competitor registrations are missing for same races
String namesOfRacesMissingRegistrations = "";
for (RaceColumnDTOAndFleetDTOWithNameBasedEquality race : races) {
if (!doCompetitorResgistrationsExist(race)) {
namesOfRacesMissingRegistrations += race.getA().getName() + "/" + race.getB().getName() + " ";
if (!regattaHasCompetitors) {
for (RaceColumnDTOAndFleetDTOWithNameBasedEquality race : races) {
if (!doCompetitorResgistrationsExist(race)) {
namesOfRacesMissingRegistrations += race.getA().getName() + "/" + race.getB().getName() + " ";
}
}
}
if (! namesOfRacesMissingRegistrations.isEmpty()) {
@@ -20,6 +20,7 @@ import com.google.gwt.user.client.ui.VerticalPanel;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.TextfieldEntryDialog;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback;
@@ -37,17 +38,15 @@ public class ResultImportUrlsManagementPanel extends FlowPanel {
private final Button refreshButton;
public ResultImportUrlsManagementPanel(SailingServiceAsync sailingService, ErrorReporter errorReporter,
StringMessages stringMessages) {
final StringMessages stringMessages) {
final Label sampleURLLabel = new Label();
this.sailingService = sailingService;
this.errorReporter = errorReporter;
this.stringMessages = stringMessages;
urlListBox = new ListBox();
urlListBox.setMultipleSelect(true);
urlProviderSelectionListBox = new ListBox();
urlListBox.setMultipleSelect(false);
urlProviderSelectionListBox.addChangeHandler(new ChangeHandler() {
@Override
public void onChange(ChangeEvent event) {
@@ -56,10 +55,13 @@ public class ResultImportUrlsManagementPanel extends FlowPanel {
addButton.setEnabled(buttonsEnabled);
removeButton.setEnabled(buttonsEnabled);
refreshButton.setEnabled(buttonsEnabled);
final String value = urlProviderSelectionListBox.getValue(selectedIndex);
// believe it or not: adding an item with (someString, null) results in an item
// whose getValue() returns "null" and not null...
sampleURLLabel.setText(value == null || value.equals("null") ? "" : stringMessages.sampleURL(value));
refreshUrlList();
}
});
addButton = new Button(stringMessages.add());
removeButton = new Button(stringMessages.remove());
refreshButton = new Button(stringMessages.refresh());
@@ -85,18 +87,15 @@ public class ResultImportUrlsManagementPanel extends FlowPanel {
HorizontalPanel providerSelectionPanel = new HorizontalPanel();
providerSelectionPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
vp.add(providerSelectionPanel);
providerSelectionPanel.add(new Label("URL Providers:"));
providerSelectionPanel.add(new Label(stringMessages.urlProviders()));
providerSelectionPanel.add(urlProviderSelectionListBox);
sailingService.getUrlResultProviderNames(new AsyncCallback<List<String>>() {
sailingService.getUrlResultProviderNamesAndOptionalSampleURL(new AsyncCallback<List<Pair<String, String>>>() {
@Override
public void onSuccess(List<String> urlProviderNames) {
public void onSuccess(List<Pair<String, String>> urlProviderNamesAndOptionalSampleURL) {
urlProviderSelectionListBox.clear();
urlProviderSelectionListBox.addItem("Please select a URL provider...");
for(String urlProviderName: urlProviderNames) {
urlProviderSelectionListBox.addItem(urlProviderName);
urlProviderSelectionListBox.addItem(stringMessages.pleaseSelectAURLProvider());
for (Pair<String, String> urlProviderNameAndSampleURL : urlProviderNamesAndOptionalSampleURL) {
urlProviderSelectionListBox.addItem(urlProviderNameAndSampleURL.getA(), urlProviderNameAndSampleURL.getB());
}
}
@@ -104,8 +103,8 @@ public class ResultImportUrlsManagementPanel extends FlowPanel {
public void onFailure(Throwable caught) {
}
});
vp.add(urlListBox);
vp.add(sampleURLLabel);
HorizontalPanel buttonPanel = new HorizontalPanel();
vp.add(buttonPanel);
buttonPanel.add(addButton);
@@ -333,7 +333,7 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
void updateLeaderboardScoreCorrectionMetadata(String leaderboardName, Date timePointOfLastCorrectionValidity,
String comment);
List<String> getUrlResultProviderNames();
List<Pair<String, String>> getUrlResultProviderNamesAndOptionalSampleURL();
void updateRaceCourse(RegattaAndRaceIdentifier raceIdentifier, List<Util.Pair<ControlPointDTO, PassingInstruction>> controlPoints);
@@ -520,7 +520,7 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
* Revoke the events in the {@code RaceLog} that are identified by the {@code eventIds}.
* This only affects such events that implement {@link Revokable}.
*/
void revokeRaceLogEvents(String leaderboardName, String raceColumnName, String fleetName, List<UUID> eventIds)
void revokeRaceAndRegattaLogEvents(String leaderboardName, String raceColumnName, String fleetName, List<UUID> eventIds)
throws NotRevokableException;
Collection<String> getGPSFixImporterTypes();
@@ -610,4 +610,6 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
String emails, String localeInfoName) throws MailException;
ArrayList<LeaderboardGroupDTO> getLeaderboardGroupsByEventId(UUID id);
boolean doesRegattaLogContainCompetitors(String name) throws DoesNotHaveRegattaLogException;
}
@@ -78,6 +78,7 @@ import com.sap.sailing.gwt.ui.shared.VenueDTO;
import com.sap.sailing.gwt.ui.shared.WindDTO;
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.search.KeywordQuery;
import com.sap.sse.gwt.client.BuildVersionRetriever;
import com.sap.sse.gwt.client.filestorage.FileStorageManagementGwtServiceAsync;
@@ -431,7 +432,7 @@ public interface SailingServiceAsync extends BuildVersionRetriever, FileStorageM
void addResultImportUrl(String resultProviderName, String url, AsyncCallback<Void> callback);
void getUrlResultProviderNames(AsyncCallback<List<String>> callback);
void getUrlResultProviderNamesAndOptionalSampleURL(AsyncCallback<List<Pair<String, String>>> callback);
void addColumnsToLeaderboard(String leaderboardName, List<Util.Pair<String, Boolean>> columnsToAdd,
AsyncCallback<Void> callback);
@@ -629,7 +630,7 @@ public interface SailingServiceAsync extends BuildVersionRetriever, FileStorageM
void closeOpenEndedDeviceMapping(String leaderboardName, String raceColumnName, String fleetName,
DeviceMappingDTO mapping, Date closingTimePoint, AsyncCallback<Void> callback);
void revokeRaceLogEvents(String leaderboardName, String raceColumnName, String fleetName, List<UUID> eventIds,
void revokeRaceAndRegattaLogEvents(String leaderboardName, String raceColumnName, String fleetName, List<UUID> eventIds,
AsyncCallback<Void> callback);
void removeSeries(RegattaIdentifier regattaIdentifier, String seriesName, AsyncCallback<Void> callback);
@@ -713,4 +714,6 @@ public interface SailingServiceAsync extends BuildVersionRetriever, FileStorageM
String emails, String localeInfoName, AsyncCallback<Void> callback);
void getLeaderboardGroupsByEventId(UUID id, AsyncCallback<ArrayList<LeaderboardGroupDTO>> callback);
void doesRegattaLogContainCompetitors(String name, AsyncCallback<Boolean> regattaLogCallBack);
}
@@ -1268,4 +1268,13 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String competitorsCount(@PluralCount(DefaultRule_1_0n.class) int count);
String trackedRacesCount(@PluralCount(DefaultRule_1_0n.class) int count);
String eventsCount(@PluralCount(DefaultRule_1_0n.class) int count);
String clone();
String changed();
String matcher();
String any();
String urlProviders();
String pleaseSelectAURLProvider();
String sampleURL(String sampleURL);
String sapSportsOn();
String followSapSports();
}
@@ -1236,3 +1236,12 @@ eventsCount={0,number} events
eventsCount[one]={0,number} event
competitorsCount={0,number} competitors
competitorsCount[one]={0,number} competitor
clone=Clone
changed=Changed
matcher=Matcher
any=Any
urlProviders=URL-based result providers
pleaseSelectAURLProvider=Please select a URL-based result provider...
sampleURL=Sample URL: {0}
sapSportsOn=SAP Sports on
followSapSports=Follow SAP Sports
@@ -1228,3 +1228,12 @@ competitorsCount={0,number} competitors
competitorsCount[one]={0,number} competitor�
dashboardWindBotLoadingText=Loading wind bot data ...
dashboardWindBotLoadingMessage=Depending on your connection this operation might take some minutes to complete the first time.
clone=Clone
changed=Changed
matcher=Matcher
any=Any
urlProviders=URL-based result providers
pleaseSelectAURLProvider=Please select a URL-based result provider...
sampleURL=Sample URL: {0}
sapSportsOn=SAP Sports on
followSapSports=Follow SAP Sports
@@ -1226,3 +1226,12 @@ eventsCount={0,number} Veranstaltungen
eventsCount[one]={0,number} Veranstaltung
competitorsCount={0,number} Teams
competitorsCount[one]={0,number} Team
clone=Clone
changed=Changed
matcher=Matcher
any=Any
urlProviders=URL-basierte Ergebnisdienste
pleaseSelectAURLProvider=Bitte einen URL-basierten Ergebnisdienst auswählen...
sampleURL=Beispiel-URL: {0}
sapSportsOn=SAP Sports bei
followSapSports=SAP Sports folgen
@@ -1175,3 +1175,12 @@ eventsCount={0,number} events
eventsCount[one]={0,number} event
competitorsCount={0,number} competitors
competitorsCount[one]={0,number} competitor
clone=Clone
changed=Changed
matcher=Matcher
any=Any
urlProviders=URL-based result providers
pleaseSelectAURLProvider=Please select a URL-based result provider...
sampleURL=Sample URL: {0}
sapSportsOn=SAP Sports on
followSapSports=Follow SAP Sports
@@ -58,8 +58,9 @@ import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import com.sap.sailing.domain.abstractlog.AbstractLog;
import com.sap.sailing.domain.abstractlog.AbstractLogEvent;
import com.sap.sailing.domain.abstractlog.MultiLogAnalyzer;
import com.sap.sailing.domain.abstractlog.Revokable;
import com.sap.sailing.domain.abstractlog.impl.AllEventsOfTypeFinder;
import com.sap.sailing.domain.abstractlog.race.FixedMarkPassingEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
@@ -81,6 +82,9 @@ import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogOp
import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogTrackingStateAnalyzer;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterCompetitorEvent;
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogOpenEndedDeviceMappingCloser;
import com.sap.sailing.domain.abstractlog.shared.analyzing.DeviceCompetitorMappingFinder;
import com.sap.sailing.domain.abstractlog.shared.analyzing.DeviceMarkMappingFinder;
import com.sap.sailing.domain.abstractlog.shared.analyzing.RegisteredCompetitorsAnalyzer;
@@ -1965,18 +1969,18 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
}
private ControlPoint getOrCreateControlPoint(ControlPointDTO dto) {
String id = dto.getIdAsString();
if (id == null) {
id = UUID.randomUUID().toString();
String idAsString = dto.getIdAsString();
if (idAsString == null) {
idAsString = UUID.randomUUID().toString();
}
if (dto instanceof GateDTO) {
GateDTO gateDTO = (GateDTO) dto;
Mark left = (Mark) getOrCreateControlPoint(gateDTO.getLeft());
Mark right = (Mark) getOrCreateControlPoint(gateDTO.getRight());
return baseDomainFactory.getOrCreateControlPointWithTwoMarks(id, gateDTO.getName(), left, right);
return baseDomainFactory.getOrCreateControlPointWithTwoMarks(idAsString, gateDTO.getName(), left, right);
} else {
MarkDTO markDTO = (MarkDTO) dto;
return baseDomainFactory.getOrCreateMark(id, dto.getName(), markDTO.type, markDTO.color, markDTO.shape, markDTO.pattern);
return baseDomainFactory.getOrCreateMark(idAsString, dto.getName(), markDTO.type, markDTO.color, markDTO.shape, markDTO.pattern);
}
}
@@ -3714,11 +3718,11 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
}
@Override
public List<String> getUrlResultProviderNames() {
List<String> result = new ArrayList<String>();
public List<Pair<String, String>> getUrlResultProviderNamesAndOptionalSampleURL() {
List<Pair<String, String>> result = new ArrayList<>();
for (ScoreCorrectionProvider scp : getAllScoreCorrectionProviders()) {
if (scp instanceof ResultUrlProvider) {
result.add(scp.getName());
result.add(new Pair<>(scp.getName(), ((ResultUrlProvider) scp).getOptionalSampleURL()));
}
}
return result;
@@ -5184,31 +5188,71 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
@Override
public void closeOpenEndedDeviceMapping(String leaderboardName, String raceColumnName, String fleetName,
DeviceMappingDTO mappingDTO, Date closingTimePoint) throws NoCorrespondingServiceRegisteredException, TransformationException {
RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName);
DeviceMapping<?> mapping = convertToDeviceMapping(mappingDTO);
List<RaceLogCloseOpenEndedDeviceMappingEvent> closingEvents =
new RaceLogOpenEndedDeviceMappingCloser(raceLog, mapping, getService().getServerAuthor(),
new MillisecondsTimePoint(closingTimePoint)).analyze();
for (RaceLogEvent event : closingEvents) {
raceLog.add(event);
List<AbstractLog<?, ?>> logHierarchy = getLogHierarchy(leaderboardName, raceColumnName, fleetName);
for (AbstractLog<?, ?> abstractLog : logHierarchy) {
//check if abstractLog is the correct log for the closingEvent
final AbstractLogEvent<?> event;
abstractLog.lockForRead();
try {
event = abstractLog.getEventById(mappingDTO.originalRaceLogEventIds.get(0));
} finally {
abstractLog.unlockAfterRead();
}
if (event != null) {
DeviceMapping<?> mapping = convertToDeviceMapping(mappingDTO);
if (abstractLog instanceof RegattaLog) {
RegattaLog regattaLog = (RegattaLog) abstractLog;
List<RegattaLogCloseOpenEndedDeviceMappingEvent> closingEvents =
new RegattaLogOpenEndedDeviceMappingCloser(regattaLog, mapping, getService().getServerAuthor(),
new MillisecondsTimePoint(closingTimePoint)).analyze();
for (RegattaLogEvent closingEvent : closingEvents) {
regattaLog.add(closingEvent);
}
} else if (abstractLog instanceof RaceLog) {
RaceLog raceLog = (RaceLog) abstractLog;
List<RaceLogCloseOpenEndedDeviceMappingEvent> closingEvents =
new RaceLogOpenEndedDeviceMappingCloser(raceLog, mapping, getService().getServerAuthor(),
new MillisecondsTimePoint(closingTimePoint)).analyze();
for (RaceLogEvent closingEvent : closingEvents) {
raceLog.add(closingEvent);
}
}
}
}
}
@Override
public void revokeRaceLogEvents(String leaderboardName, String raceColumnName, String fleetName,
public void revokeRaceAndRegattaLogEvents(String leaderboardName, String raceColumnName, String fleetName,
List<UUID> eventIds) throws NotRevokableException {
RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName);
List<AbstractLog<?, ?>> logHierarchy = getLogHierarchy(leaderboardName, raceColumnName, fleetName);
boolean eventRevoked = false;
for (Serializable idToRevoke : eventIds) {
raceLog.lockForRead();
RaceLogEvent event = raceLog.getEventById(idToRevoke);
raceLog.unlockAfterRead();
if (event instanceof Revokable) {
raceLog.revokeEvent(getService().getServerAuthor(), event, "revoke triggered by GWT user action");
eventRevoked = false;
for (AbstractLog<?, ?> abstractLog : logHierarchy) {
eventRevoked = revokeEvent(eventRevoked, idToRevoke, abstractLog);
}
if (!eventRevoked){
logger.warning("Could not revoke event with id "+idToRevoke);
}
}
}
private <EventT extends AbstractLogEvent<VisitorT>, VisitorT> boolean revokeEvent(boolean eventRevoked, Serializable idToRevoke, AbstractLog<EventT, VisitorT> abstractLog)
throws NotRevokableException {
final EventT event;
abstractLog.lockForRead();
try {
event = abstractLog.getEventById(idToRevoke);
} finally {
abstractLog.unlockAfterRead();
}
if (event != null) {
abstractLog.revokeEvent(getService().getServerAuthor(), event, "revoke triggered by GWT user action");
eventRevoked = true;
}
return eventRevoked;
}
@Override
public void startRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName, final boolean trackWind, final boolean correctWindByDeclination)
throws NotDenotedForRaceLogTrackingException, Exception {
@@ -5596,4 +5640,18 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
}
return result;
}
@Override
public boolean doesRegattaLogContainCompetitors(String leaderboardName) throws DoesNotHaveRegattaLogException {
RegattaLog regattaLog = getRegattaLogInternal(leaderboardName);
List<RegattaLogEvent> markEvents = new AllEventsOfTypeFinder<>(regattaLog, /* only unrevoked */ true, RegattaLogRegisterCompetitorEvent.class)
.analyze();
if (markEvents.isEmpty()){
return false;
} else {
return true;
}
}
}
@@ -1,2 +0,0 @@
/WindLatticeDTO.java
/WindLatticeGenParamsDTO.java
Loaded 100 of 974 files, more files were not shown because too many files have changed in this diff. Show more