mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-11-01 00:30:46 +00:00
Merge branch 'master' into tracapi
This commit is contained in:
commit
69b0466a6c
66 files changed
+1568
-335
No files matched your search
+38
@@ -0,0 +1,38 @@
|
||||
package com.sap.sailing.domain.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface DataImportProgress extends Serializable {
|
||||
|
||||
double getOverallProgressPct();
|
||||
|
||||
void setOverAllProgressPct(double pct);
|
||||
|
||||
String getNameOfCurrentSubProgress();
|
||||
|
||||
void setNameOfCurrentSubProgress(String name);
|
||||
|
||||
double getCurrentSubProgressPct();
|
||||
|
||||
void setCurrentSubProgressPct(double pct);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the result if the operation id done, null otherwise
|
||||
*/
|
||||
MasterDataImportObjectCreationCount getResult();
|
||||
|
||||
void setResult(MasterDataImportObjectCreationCount result);
|
||||
|
||||
UUID getOperationId();
|
||||
|
||||
boolean failed();
|
||||
|
||||
void setFailed();
|
||||
|
||||
String getErrorMessage();
|
||||
|
||||
void setErrorMessage(String message);
|
||||
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
package com.sap.sailing.domain.common.impl;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.sap.sailing.domain.common.DataImportProgress;
|
||||
import com.sap.sailing.domain.common.MasterDataImportObjectCreationCount;
|
||||
|
||||
public class DataImportProgressImpl implements DataImportProgress {
|
||||
|
||||
private static final long serialVersionUID = 5538458397711003527L;
|
||||
private UUID currentImportOperationId;
|
||||
private MasterDataImportObjectCreationCount result = null;
|
||||
private double overallProgressPct = 0;
|
||||
private String currentSubProgressName = "Initializing Import";
|
||||
private double currentSubProgressPct = 0;
|
||||
private boolean failed = false;
|
||||
private String errorMessage;
|
||||
|
||||
DataImportProgressImpl() {
|
||||
}
|
||||
|
||||
public DataImportProgressImpl(final UUID currentImportOperationId) {
|
||||
this.currentImportOperationId = currentImportOperationId;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getOverallProgressPct() {
|
||||
return overallProgressPct;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNameOfCurrentSubProgress() {
|
||||
return currentSubProgressName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getCurrentSubProgressPct() {
|
||||
return currentSubProgressPct;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MasterDataImportObjectCreationCount getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOverAllProgressPct(double pct) {
|
||||
overallProgressPct = pct;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNameOfCurrentSubProgress(String name) {
|
||||
currentSubProgressName = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentSubProgressPct(double pct) {
|
||||
currentSubProgressPct = pct;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResult(MasterDataImportObjectCreationCount result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getOperationId() {
|
||||
return currentImportOperationId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean failed() {
|
||||
return failed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getErrorMessage() {
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFailed() {
|
||||
failed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setErrorMessage(String message) {
|
||||
errorMessage = message;
|
||||
}
|
||||
|
||||
}
|
||||
+16
-2
@@ -309,7 +309,14 @@ public class TrackImpl<FixType extends Timed> implements Track<FixType> {
|
||||
public Duration getAverageIntervalBetweenFixes() {
|
||||
lockForRead();
|
||||
try {
|
||||
return getFixes().first().getTimePoint().until(getFixes().last().getTimePoint()).divide(getFixes().size()-1);
|
||||
final Duration result;
|
||||
final int size = getFixes().size();
|
||||
if (size > 1) {
|
||||
result = getFixes().first().getTimePoint().until(getFixes().last().getTimePoint()).divide(size-1);
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
} finally {
|
||||
unlockAfterRead();
|
||||
}
|
||||
@@ -319,7 +326,14 @@ public class TrackImpl<FixType extends Timed> implements Track<FixType> {
|
||||
public Duration getAverageIntervalBetweenRawFixes() {
|
||||
lockForRead();
|
||||
try {
|
||||
return getRawFixes().first().getTimePoint().until(getRawFixes().last().getTimePoint()).divide(getRawFixes().size()-1);
|
||||
final Duration result;
|
||||
final int size = getRawFixes().size();
|
||||
if (size > 1) {
|
||||
result = getRawFixes().first().getTimePoint().until(getRawFixes().last().getTimePoint()).divide(size-1);
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
} finally {
|
||||
unlockAfterRead();
|
||||
}
|
||||
|
||||
+11
-2
@@ -8,6 +8,7 @@ import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.NavigableSet;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.SortedSet;
|
||||
|
||||
/**
|
||||
@@ -62,12 +63,20 @@ public class ArrayListNavigableSet<E> implements NavigableSet<E>, Serializable {
|
||||
|
||||
@Override
|
||||
public E first() {
|
||||
return list.get(0);
|
||||
try {
|
||||
return list.get(0);
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw new NoSuchElementException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public E last() {
|
||||
return list.get(list.size()-1);
|
||||
try {
|
||||
return list.get(list.size()-1);
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw new NoSuchElementException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-1
@@ -139,7 +139,8 @@ public class ActivelyConnectingStoreAndForwardTest {
|
||||
}
|
||||
assertTrue(receivedSomething[0]);
|
||||
assertEquals(2, racesReceived.size());
|
||||
Thread.sleep(500); // wait for DB to read our previous write
|
||||
db.getLastError(); // synchronize on DB and wait for last write to have completed
|
||||
Thread.sleep(2000); // the synchronization doesn't seem to help
|
||||
DBCollection lastMessageCountCollection = db.getCollection(CollectionNames.LAST_MESSAGE_COUNT.name());
|
||||
Long lastMessageCount = (Long) lastMessageCountCollection.findOne().get(FieldNames.LAST_MESSAGE_COUNT.name());
|
||||
assertEquals((Long) 1l, lastMessageCount);
|
||||
|
||||
+16
-8
@@ -489,9 +489,16 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
}
|
||||
|
||||
private boolean isDiscarded(Competitor competitor, RaceColumn raceColumn, Iterable<RaceColumn> raceColumnsToConsider, TimePoint timePoint) {
|
||||
return !raceColumn.isMedalRace() && getMaxPointsReason(competitor, raceColumn, timePoint).isDiscardable()
|
||||
&& getResultDiscardingRule().getDiscardedRaceColumns(competitor, this, raceColumnsToConsider, timePoint).contains(
|
||||
raceColumn);
|
||||
final boolean result;
|
||||
if (getResultDiscardingRule() == null) {
|
||||
result = false;
|
||||
} else {
|
||||
result = !raceColumn.isMedalRace()
|
||||
&& getMaxPointsReason(competitor, raceColumn, timePoint).isDiscardable()
|
||||
&& getResultDiscardingRule().getDiscardedRaceColumns(competitor, this, raceColumnsToConsider,
|
||||
timePoint).contains(raceColumn);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1120,11 +1127,12 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
result.setDelayToLiveInMillisForLatestRace(this.getDelayToLiveInMillis());
|
||||
result.rows = new HashMap<CompetitorDTO, LeaderboardRowDTO>();
|
||||
result.hasCarriedPoints = this.hasCarriedPoints();
|
||||
if (this.getResultDiscardingRule() instanceof ThresholdBasedResultDiscardingRule) {
|
||||
result.discardThresholds = ((ThresholdBasedResultDiscardingRule) this.getResultDiscardingRule()).getDiscardIndexResultsStartingWithHowManyRaces();
|
||||
} else {
|
||||
result.discardThresholds = null;
|
||||
}
|
||||
if (this.getResultDiscardingRule() instanceof ThresholdBasedResultDiscardingRule) {
|
||||
result.discardThresholds = ((ThresholdBasedResultDiscardingRule) this.getResultDiscardingRule())
|
||||
.getDiscardIndexResultsStartingWithHowManyRaces();
|
||||
} else {
|
||||
result.discardThresholds = null;
|
||||
}
|
||||
// competitor, leading to square effort. We therefore need to compute the leg ranks for those race where leg
|
||||
// details
|
||||
// are requested only once and pass them into getLeaderboardEntryDTO
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<!-- -->
|
||||
<title>SAP Sailing Analytics Administration Console</title>
|
||||
|
||||
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="js/jquery-1.7.1.min.js"></script>
|
||||
<script type="text/javascript" src="highcharts/js/highcharts.js"></script>
|
||||
|
||||
<!-- Optionally, add a highcharts theme file -->
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
/*!
|
||||
* Bootstrap v2.3.2
|
||||
*
|
||||
* Copyright 2013 Twitter, Inc
|
||||
* Licensed under the Apache License v2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Designed and built with all the love in the world @twitter by @mdo and @fat.
|
||||
*/
|
||||
.clearfix {
|
||||
*zoom: 1;
|
||||
}
|
||||
.clearfix:before,
|
||||
.clearfix:after {
|
||||
display: table;
|
||||
content: "";
|
||||
line-height: 0;
|
||||
}
|
||||
.clearfix:after {
|
||||
clear: both;
|
||||
}
|
||||
.hide-text {
|
||||
font: 0/0 a;
|
||||
color: transparent;
|
||||
text-shadow: none;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
}
|
||||
.input-block-level {
|
||||
display: block;
|
||||
width: 100%;
|
||||
min-height: 30px;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@-webkit-keyframes progress-bar-stripes {
|
||||
from {
|
||||
background-position: 40px 0;
|
||||
}
|
||||
to {
|
||||
background-position: 0 0;
|
||||
}
|
||||
}
|
||||
@-moz-keyframes progress-bar-stripes {
|
||||
from {
|
||||
background-position: 40px 0;
|
||||
}
|
||||
to {
|
||||
background-position: 0 0;
|
||||
}
|
||||
}
|
||||
@-ms-keyframes progress-bar-stripes {
|
||||
from {
|
||||
background-position: 40px 0;
|
||||
}
|
||||
to {
|
||||
background-position: 0 0;
|
||||
}
|
||||
}
|
||||
@-o-keyframes progress-bar-stripes {
|
||||
from {
|
||||
background-position: 0 0;
|
||||
}
|
||||
to {
|
||||
background-position: 40px 0;
|
||||
}
|
||||
}
|
||||
@keyframes progress-bar-stripes {
|
||||
from {
|
||||
background-position: 40px 0;
|
||||
}
|
||||
to {
|
||||
background-position: 0 0;
|
||||
}
|
||||
}
|
||||
.progress {
|
||||
overflow: hidden;
|
||||
height: 20px;
|
||||
margin-bottom: 20px;
|
||||
background-color: #f7f7f7;
|
||||
background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));
|
||||
background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9);
|
||||
background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9);
|
||||
background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);
|
||||
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
-moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.progress .bar {
|
||||
width: 0%;
|
||||
height: 100%;
|
||||
color: #ffffff;
|
||||
float: left;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||
background-color: #0e90d2;
|
||||
background-image: -moz-linear-gradient(top, #149bdf, #0480be);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));
|
||||
background-image: -webkit-linear-gradient(top, #149bdf, #0480be);
|
||||
background-image: -o-linear-gradient(top, #149bdf, #0480be);
|
||||
background-image: linear-gradient(to bottom, #149bdf, #0480be);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0);
|
||||
-webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
|
||||
-moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
|
||||
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
-webkit-transition: width 0.6s ease;
|
||||
-moz-transition: width 0.6s ease;
|
||||
-o-transition: width 0.6s ease;
|
||||
transition: width 0.6s ease;
|
||||
}
|
||||
.progress .bar + .bar {
|
||||
-webkit-box-shadow: inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);
|
||||
-moz-box-shadow: inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);
|
||||
box-shadow: inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);
|
||||
}
|
||||
.progress-striped .bar {
|
||||
background-color: #149bdf;
|
||||
background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
|
||||
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
-webkit-background-size: 40px 40px;
|
||||
-moz-background-size: 40px 40px;
|
||||
-o-background-size: 40px 40px;
|
||||
background-size: 40px 40px;
|
||||
}
|
||||
.progress.active .bar {
|
||||
-webkit-animation: progress-bar-stripes 2s linear infinite;
|
||||
-moz-animation: progress-bar-stripes 2s linear infinite;
|
||||
-ms-animation: progress-bar-stripes 2s linear infinite;
|
||||
-o-animation: progress-bar-stripes 2s linear infinite;
|
||||
animation: progress-bar-stripes 2s linear infinite;
|
||||
}
|
||||
.progress-danger .bar,
|
||||
.progress .bar-danger {
|
||||
background-color: #dd514c;
|
||||
background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));
|
||||
background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
|
||||
background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
|
||||
background-image: linear-gradient(to bottom, #ee5f5b, #c43c35);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0);
|
||||
}
|
||||
.progress-danger.progress-striped .bar,
|
||||
.progress-striped .bar-danger {
|
||||
background-color: #ee5f5b;
|
||||
background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
|
||||
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
}
|
||||
.progress-success .bar,
|
||||
.progress .bar-success {
|
||||
background-color: #5eb95e;
|
||||
background-image: -moz-linear-gradient(top, #62c462, #57a957);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));
|
||||
background-image: -webkit-linear-gradient(top, #62c462, #57a957);
|
||||
background-image: -o-linear-gradient(top, #62c462, #57a957);
|
||||
background-image: linear-gradient(to bottom, #62c462, #57a957);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0);
|
||||
}
|
||||
.progress-success.progress-striped .bar,
|
||||
.progress-striped .bar-success {
|
||||
background-color: #62c462;
|
||||
background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
|
||||
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
}
|
||||
.progress-info .bar,
|
||||
.progress .bar-info {
|
||||
background-color: #4bb1cf;
|
||||
background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));
|
||||
background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
|
||||
background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
|
||||
background-image: linear-gradient(to bottom, #5bc0de, #339bb9);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0);
|
||||
}
|
||||
.progress-info.progress-striped .bar,
|
||||
.progress-striped .bar-info {
|
||||
background-color: #5bc0de;
|
||||
background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
|
||||
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
}
|
||||
.progress-warning .bar,
|
||||
.progress .bar-warning {
|
||||
background-color: #faa732;
|
||||
background-image: -moz-linear-gradient(top, #fbb450, #f89406);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));
|
||||
background-image: -webkit-linear-gradient(top, #fbb450, #f89406);
|
||||
background-image: -o-linear-gradient(top, #fbb450, #f89406);
|
||||
background-image: linear-gradient(to bottom, #fbb450, #f89406);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);
|
||||
}
|
||||
.progress-warning.progress-striped .bar,
|
||||
.progress-striped .bar-warning {
|
||||
background-color: #fbb450;
|
||||
background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
|
||||
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
<link href='images/sap-sailing-app-icon.png' rel='apple-touch-icon'>
|
||||
<link rel="shortcut icon" type="image/x-icon" href="images/sap.ico" />
|
||||
|
||||
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="js/jquery-1.5.2.min.js"></script>
|
||||
<script type="text/javascript" src="highcharts/js/highcharts.js"></script>
|
||||
|
||||
<!-- Optionally, add a highcharts theme file -->
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<!--<link href='http://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700,300italic,400italic,500italic,700italic' rel='stylesheet' type='text/css'>-->
|
||||
<!-- <link href='http://fonts.googleapis.com/css?family=Open+Sans+Condensed:700,300,300italic' rel='stylesheet' type='text/css'>-->
|
||||
|
||||
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="js/jquery-1.5.2.min.js"></script>
|
||||
<script type="text/javascript" src="highcharts/js/highcharts.js"></script>
|
||||
|
||||
<!-- Optionally, add a highcharts theme file -->
|
||||
|
||||
@@ -43,7 +43,7 @@ a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
table td,select,button {
|
||||
table td,select,button,checkbox {
|
||||
line-height: 1;
|
||||
font-family: 'OpenSansRegular', Arial, Verdana, sans-serif;
|
||||
font-size: 16px;
|
||||
@@ -209,4 +209,41 @@ table {
|
||||
.RegattaOverview-Leaderboards {
|
||||
padding-top: 20px;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.viewerToolbar-innerElement {
|
||||
background: url("images/btn-cta-orangeleft.png") repeat-x scroll center 0 transparent;
|
||||
border-bottom-left-radius: 3px;
|
||||
border-top-left-radius: 3px;
|
||||
color: #FFFFFF;
|
||||
cursor: pointer;
|
||||
font-family: UbuntuBold,Verdana,Arial,sans-serif;
|
||||
font-size: 14px;
|
||||
margin: 0 15px 0 0;
|
||||
padding: 2px 7px 2px 3px;
|
||||
height: 18px;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
-moz-border-radius: 5px 0 0 5px;
|
||||
-webkit-border-radius: 5px 0 0 5px;
|
||||
border-radius: 5px 0 0 5px;
|
||||
-moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
|
||||
-webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
|
||||
text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.25);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.viewerToolbar-innerElement:active {
|
||||
top: 1px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.viewerToolbar-innerElement:hover {
|
||||
background: url("images/btn-cta-orangeleft.png") repeat-x scroll center -30px transparent;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.viewerToolbar-innerElement label {
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -51,5 +51,6 @@ bin.includes = META-INF/,\
|
||||
DataMining.css,\
|
||||
DataMining.html,\
|
||||
AdminConsoleDateTimePicker.css,\
|
||||
qrcode/
|
||||
qrcode/,\
|
||||
js/
|
||||
output.. = WEB-INF/classes/
|
||||
@@ -0,0 +1 @@
|
||||
(function(a,b){function cg(a){return d.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cd(a){if(!bZ[a]){var b=d("<"+a+">").appendTo("body"),c=b.css("display");b.remove();if(c==="none"||c==="")c="block";bZ[a]=c}return bZ[a]}function cc(a,b){var c={};d.each(cb.concat.apply([],cb.slice(0,b)),function(){c[this]=a});return c}function bY(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function bX(){try{return new a.XMLHttpRequest}catch(b){}}function bW(){d(a).unload(function(){for(var a in bU)bU[a](0,1)})}function bQ(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var e=a.dataTypes,f={},g,h,i=e.length,j,k=e[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h==="string"&&(f[h.toLowerCase()]=a.converters[h]);l=k,k=e[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=f[m]||f["* "+k];if(!n){p=b;for(o in f){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=f[j[1]+" "+k];if(p){o=f[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&d.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function bP(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function bO(a,b,c,e){if(d.isArray(b)&&b.length)d.each(b,function(b,f){c||bq.test(a)?e(a,f):bO(a+"["+(typeof f==="object"||d.isArray(f)?b:"")+"]",f,c,e)});else if(c||b==null||typeof b!=="object")e(a,b);else if(d.isArray(b)||d.isEmptyObject(b))e(a,"");else for(var f in b)bO(a+"["+f+"]",b[f],c,e)}function bN(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bH,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l==="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=bN(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=bN(a,c,d,e,"*",g));return l}function bM(a){return function(b,c){typeof b!=="string"&&(c=b,b="*");if(d.isFunction(c)){var e=b.toLowerCase().split(bB),f=0,g=e.length,h,i,j;for(;f<g;f++)h=e[f],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bo(a,b,c){var e=b==="width"?bi:bj,f=b==="width"?a.offsetWidth:a.offsetHeight;if(c==="border")return f;d.each(e,function(){c||(f-=parseFloat(d.css(a,"padding"+this))||0),c==="margin"?f+=parseFloat(d.css(a,"margin"+this))||0:f-=parseFloat(d.css(a,"border"+this+"Width"))||0});return f}function ba(a,b){b.src?d.ajax({url:b.src,async:!1,dataType:"script"}):d.globalEval(b.text||b.textContent||b.innerHTML||""),b.parentNode&&b.parentNode.removeChild(b)}function _(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function $(a,b){if(b.nodeType===1){var c=b.nodeName.toLowerCase();b.clearAttributes(),b.mergeAttributes(a);if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(d.expando)}}function Z(a,b){if(b.nodeType===1&&d.hasData(a)){var c=d.expando,e=d.data(a),f=d.data(b,e);if(e=e[c]){var g=e.events;f=f[c]=d.extend({},e);if(g){delete f.handle,f.events={};for(var h in g)for(var i=0,j=g[h].length;i<j;i++)d.event.add(b,h+(g[h][i].namespace?".":"")+g[h][i].namespace,g[h][i],g[h][i].data)}}}}function Y(a,b){return d.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function O(a,b,c){if(d.isFunction(b))return d.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return d.grep(a,function(a,d){return a===b===c});if(typeof b==="string"){var e=d.grep(a,function(a){return a.nodeType===1});if(J.test(b))return d.filter(b,e,!c);b=d.filter(b,e)}return d.grep(a,function(a,e){return d.inArray(a,b)>=0===c})}function N(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function F(a,b){return(a&&a!=="*"?a+".":"")+b.replace(r,"`").replace(s,"&")}function E(a){var b,c,e,f,g,h,i,j,k,l,m,n,o,q=[],r=[],s=d._data(this,"events");if(a.liveFired!==this&&s&&s.live&&!a.target.disabled&&(!a.button||a.type!=="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var t=s.live.slice(0);for(i=0;i<t.length;i++)g=t[i],g.origType.replace(p,"")===a.type?r.push(g.selector):t.splice(i--,1);f=d(a.target).closest(r,a.currentTarget);for(j=0,k=f.length;j<k;j++){m=f[j];for(i=0;i<t.length;i++){g=t[i];if(m.selector===g.selector&&(!n||n.test(g.namespace))&&!m.elem.disabled){h=m.elem,e=null;if(g.preType==="mouseenter"||g.preType==="mouseleave")a.type=g.preType,e=d(a.relatedTarget).closest(g.selector)[0];(!e||e!==h)&&q.push({elem:h,handleObj:g,level:m.level}Line truncated
|
||||
@@ -0,0 +1 @@
|
||||
(function(a,b){function ci(a){return d.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cf(a){if(!b_[a]){var b=d("<"+a+">").appendTo("body"),c=b.css("display");b.remove();if(c==="none"||c==="")c="block";b_[a]=c}return b_[a]}function ce(a,b){var c={};d.each(cd.concat.apply([],cd.slice(0,b)),function(){c[this]=a});return c}function b$(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function bZ(){try{return new a.XMLHttpRequest}catch(b){}}function bY(){d(a).unload(function(){for(var a in bW)bW[a](0,1)})}function bS(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var e=a.dataTypes,f={},g,h,i=e.length,j,k=e[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h==="string"&&(f[h.toLowerCase()]=a.converters[h]);l=k,k=e[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=f[m]||f["* "+k];if(!n){p=b;for(o in f){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=f[j[1]+" "+k];if(p){o=f[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&d.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function bR(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function bQ(a,b,c,e){if(d.isArray(b)&&b.length)d.each(b,function(b,f){c||bs.test(a)?e(a,f):bQ(a+"["+(typeof f==="object"||d.isArray(f)?b:"")+"]",f,c,e)});else if(c||b==null||typeof b!=="object")e(a,b);else if(d.isArray(b)||d.isEmptyObject(b))e(a,"");else for(var f in b)bQ(a+"["+f+"]",b[f],c,e)}function bP(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bJ,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l==="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=bP(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=bP(a,c,d,e,"*",g));return l}function bO(a){return function(b,c){typeof b!=="string"&&(c=b,b="*");if(d.isFunction(c)){var e=b.toLowerCase().split(bD),f=0,g=e.length,h,i,j;for(;f<g;f++)h=e[f],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bq(a,b,c){var e=b==="width"?bk:bl,f=b==="width"?a.offsetWidth:a.offsetHeight;if(c==="border")return f;d.each(e,function(){c||(f-=parseFloat(d.css(a,"padding"+this))||0),c==="margin"?f+=parseFloat(d.css(a,"margin"+this))||0:f-=parseFloat(d.css(a,"border"+this+"Width"))||0});return f}function bc(a,b){b.src?d.ajax({url:b.src,async:!1,dataType:"script"}):d.globalEval(b.text||b.textContent||b.innerHTML||""),b.parentNode&&b.parentNode.removeChild(b)}function bb(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function ba(a,b){if(b.nodeType===1){var c=b.nodeName.toLowerCase();b.clearAttributes(),b.mergeAttributes(a);if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(d.expando)}}function _(a,b){if(b.nodeType===1&&d.hasData(a)){var c=d.expando,e=d.data(a),f=d.data(b,e);if(e=e[c]){var g=e.events;f=f[c]=d.extend({},e);if(g){delete f.handle,f.events={};for(var h in g)for(var i=0,j=g[h].length;i<j;i++)d.event.add(b,h+(g[h][i].namespace?".":"")+g[h][i].namespace,g[h][i],g[h][i].data)}}}}function $(a,b){return d.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function Q(a,b,c){if(d.isFunction(b))return d.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return d.grep(a,function(a,d){return a===b===c});if(typeof b==="string"){var e=d.grep(a,function(a){return a.nodeType===1});if(L.test(b))return d.filter(b,e,!c);b=d.filter(b,e)}return d.grep(a,function(a,e){return d.inArray(a,b)>=0===c})}function P(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function H(a,b){return(a&&a!=="*"?a+".":"")+b.replace(t,"`").replace(u,"&")}function G(a){var b,c,e,f,g,h,i,j,k,l,m,n,o,p=[],q=[],s=d._data(this,"events");if(a.liveFired!==this&&s&&s.live&&!a.target.disabled&&(!a.button||a.type!=="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var t=s.live.slice(0);for(i=0;i<t.length;i++)g=t[i],g.origType.replace(r,"")===a.type?q.push(g.selector):t.splice(i--,1);f=d(a.target).closest(q,a.currentTarget);for(j=0,k=f.length;j<k;j++){m=f[j];for(i=0;i<t.length;i++){g=t[i];if(m.selector===g.selector&&(!n||n.test(g.namespace))&&!m.elem.disabled){h=m.elem,e=null;if(g.preType==="mouseenter"||g.preType==="mouseleave")a.type=g.preType,e=d(a.relatedTarget).closest(g.selector)[0];(!e||e!==h)&&p.push({elem:h,handleObj:g,level:m.leveLine truncated
|
||||
@@ -0,0 +1,2 @@
|
||||
(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"<!doctype html>":"")+"<html><body>"),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h=="string"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=e[m]||e["* "+k];if(!n){p=b;for(o in e){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=e[j[1]+" "+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function cb(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function ca(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bE.test(a)?d(a,e):ca(a+"["+(typeof e=="object"||f.isArray(e)?b:"")+"]",e,c,d)});else if(!c&&b!=null&&typeof b=="object")for(var e in b)ca(a+"["+e+"]",b[e],c,d);else d(a,b)}function b_(a,c){var d,e,g=f.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((g[d]?a:e||(e={}))[d]=c[d]);e&&f.extend(!0,a,e)}function b$(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bT,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l=="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=b$(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=b$(a,c,d,e,"*",g));return l}function bZ(a){return function(b,c){typeof b!="string"&&(c=b,b="*");if(f.isFunction(c)){var d=b.toLowerCase().split(bP),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bC(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=b==="width"?bx:by,g=0,h=e.length;if(d>0){if(c!=="border")for(;g<h;g++)c||(d-=parseFloat(f.css(a,"padding"+e[g]))||0),c==="margin"?d+=parseFloat(f.css(a,c+e[g]))||0:d-=parseFloat(f.css(a,"border"+e[g]+"Width"))||0;return d+"px"}d=bz(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0;if(c)for(;g<h;g++)d+=parseFloat(f.css(a,"padding"+e[g]))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+e[g]+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+e[g]))||0);return d+"px"}function bp(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bf,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bo(a){var b=c.createElement("div");bh.appendChild(b),b.innerHTML=a.outerHTML;return b.firstChild}function bn(a){var b=(a.nodeName||"").toLowerCase();b==="input"?bm(a):b!=="script"&&typeof a.getElementsByTagName!="undefined"&&f.grep(a.getElementsByTagName("input"),bm)}function bm(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bl(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bk(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bj(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c,d,e,g=f._data(a),h=f._data(b,g),i=g.events;if(i){delete h.handle,h.events={};for(c in i)for(d=0,e=i[c].length;d<e;d++)f.event.add(b,c+(i[c][d].namespace?".":"")+i[c][d].namespace,i[c][d],i[c][d].data)}h.data&&(h.data=f.extend({},h.data))}}function bi(a,b){return f.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function U(a){var b=V.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function T(a,b,c){b=b||0;iLine truncated
|
||||
{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1></$2>");try{for(var c=0,d=this.length;c<d;c++)this[c].nodeType===1&&(f.cleanData(this[c].getElementsByTagName("*")),this[c].innerHTML=a)}catch(e){this.empty().append(a)}}else f.isFunction(a)?this.each(function(b){var c=f(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!="string"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j=="string"&&bd.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bi(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,bp)}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i,j=a[0];b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof j=="string"&&j.length<512&&i===c&&j.charAt(0)==="<"&&!bb.test(j)&&(f.support.checkClone||!bd.test(j))&&(f.support.html5Clone||!bc.test(j))&&(g=!0,h=f.fragments[j],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean(a,i,e,d)),g&&(f.fragments[j]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1></$2>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]==="<table>"&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof(r=k.length)=="number")for(i=0;i<r;i++)bn(k[i]);else bn(k);k.nodeType?h.push(k):h=f.merge(h,k)}if(d){g=function(a){return!a.type||be.test(a.type)};for(j=0;h[j];j++)if(e&&f.nodeName(h[j],"script")&&(!h[j].type||h[j].type.toLowerCase()==="text/javascript"))e.push(h[j].parentNode?h[j].parentNode.removeChild(h[j]):h[j]);else{if(h[j].nodeType===1){var s=f.grep(h[j].getElementsByTagName("script"),g);h.splice.apply(h,[j+1,0].concat(s))}d.appendChild(h[j])}}return h},cleanData:function(a){var b,c,d=f.cache,e=f.event.special,g=f.support.deleteExpando;for(var h=0,i;(i=a[h])!=null;h++){if(i.nodeName&&f.noData[i.nodeName.toLowerCase()])continue;c=i[f.expando];if(c){b=d[c];if(b&&b.events){for(var j in b.events)e[j]?f.event.remove(i,j):f.removeEvent(i,j,b.handle);b.handle&&(b.handle.elem=null)}g?delete i[f.expando]:i.removeAttribute&&i.removeAttribute(f.expando),delete d[c]}}}});var bq=/alpha\([^)]*\)/i,br=/opacityLine truncated
|
||||
+4
-2
@@ -12,9 +12,9 @@ import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
|
||||
import com.sap.sailing.datamining.shared.DataMiningSerializationDummy;
|
||||
import com.sap.sailing.datamining.shared.QueryDefinition;
|
||||
import com.sap.sailing.datamining.shared.QueryResult;
|
||||
import com.sap.sailing.domain.common.DataImportProgress;
|
||||
import com.sap.sailing.domain.common.DetailType;
|
||||
import com.sap.sailing.domain.common.LeaderboardType;
|
||||
import com.sap.sailing.domain.common.MasterDataImportObjectCreationCount;
|
||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.PassingInstruction;
|
||||
@@ -345,8 +345,10 @@ public interface SailingService extends RemoteService {
|
||||
|
||||
List<String> getLeaderboardGroupNamesFromRemoteServer(String host);
|
||||
|
||||
MasterDataImportObjectCreationCount importMasterData(String host, String[] groupNames, boolean override, boolean compress);
|
||||
UUID importMasterData(String host, String[] groupNames, boolean override, boolean compress);
|
||||
|
||||
DataImportProgress getImportOperationProgress(UUID id);
|
||||
|
||||
<ResultType extends Number> QueryResult<ResultType> runQuery(QueryDefinition queryDefinition) throws Exception;
|
||||
|
||||
Iterable<CompetitorDTO> getCompetitors();
|
||||
|
||||
+4
-2
@@ -11,9 +11,9 @@ import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.sap.sailing.datamining.shared.DataMiningSerializationDummy;
|
||||
import com.sap.sailing.datamining.shared.QueryDefinition;
|
||||
import com.sap.sailing.datamining.shared.QueryResult;
|
||||
import com.sap.sailing.domain.common.DataImportProgress;
|
||||
import com.sap.sailing.domain.common.DetailType;
|
||||
import com.sap.sailing.domain.common.LeaderboardType;
|
||||
import com.sap.sailing.domain.common.MasterDataImportObjectCreationCount;
|
||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.PassingInstruction;
|
||||
import com.sap.sailing.domain.common.PolarSheetGenerationResponse;
|
||||
@@ -462,7 +462,9 @@ public interface SailingServiceAsync {
|
||||
AsyncCallback<RaceLogDTO> callback);
|
||||
|
||||
void importMasterData(String host, String[] names, boolean override, boolean compress,
|
||||
AsyncCallback<MasterDataImportObjectCreationCount> asyncCallback);
|
||||
AsyncCallback<UUID> asyncCallback);
|
||||
|
||||
void getImportOperationProgress(UUID id, AsyncCallback<DataImportProgress> asyncCallback);
|
||||
|
||||
void getLeaderboardGroupNamesFromRemoteServer(String host, AsyncCallback<List<String>> leaderboardGroupNames);
|
||||
|
||||
|
||||
+2
-2
@@ -141,8 +141,8 @@ public class SmallWindHistoryPanel extends FormPanel implements TimeListener, Ra
|
||||
}
|
||||
|
||||
@Override
|
||||
public void timeChanged(Date date) {
|
||||
this.date = date;
|
||||
public void timeChanged(Date newTime, Date oldTime) {
|
||||
this.date = newTime;
|
||||
updateWindDisplay();
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -960,4 +960,5 @@ public interface StringMessages extends Messages {
|
||||
String hasSplitFleetContiguousScoring();
|
||||
String eventOverview();
|
||||
String start();
|
||||
String overallProgress();
|
||||
}
|
||||
+1
@@ -947,5 +947,6 @@ use=Use
|
||||
groupingProvider=Grouping Provider
|
||||
releaseNotes=News and Release History
|
||||
hasSplitFleetContiguousScoring=Split fleets scored contiguously
|
||||
overallProgress=Overall Progress
|
||||
eventOverview=Event Overview
|
||||
start=Start
|
||||
+1
@@ -943,5 +943,6 @@ use=Verwende
|
||||
groupingProvider=Gruppierungs-Versorger
|
||||
releaseNotes=Neuigkeiten und Änderungshistorie
|
||||
hasSplitFleetContiguousScoring=Gruppen durchgängig bepunkten
|
||||
overallProgress=Gesamtfortschritt
|
||||
eventOverview=Veranstaltungsübersicht
|
||||
start=Start
|
||||
+1
-1
@@ -3,5 +3,5 @@ package com.sap.sailing.gwt.ui.client;
|
||||
import java.util.Date;
|
||||
|
||||
public interface TimeListener {
|
||||
void timeChanged(Date date);
|
||||
void timeChanged(Date newTime, Date oldTime);
|
||||
}
|
||||
+9
-9
@@ -291,16 +291,16 @@ public class TimePanel<T extends TimePanelSettings> extends SimplePanel implemen
|
||||
}
|
||||
|
||||
@Override
|
||||
public void timeChanged(Date time) {
|
||||
public void timeChanged(Date newTime, Date oldTime) {
|
||||
if (timeRangeProvider.isZoomed()) {
|
||||
timeSlider.setCurrentValue(new Double(time.getTime()), false);
|
||||
timeSlider.setCurrentValue(new Double(newTime.getTime()), false);
|
||||
} else {
|
||||
if (getFromTime() != null && getToTime() != null) {
|
||||
// handle the case where time advances beyond slider's end.
|
||||
if (time.after(getToTime())) {
|
||||
if (newTime.after(getToTime())) {
|
||||
switch (timer.getPlayMode()) {
|
||||
case Live:
|
||||
Date newMaxTime = new Date(time.getTime());
|
||||
Date newMaxTime = new Date(newTime.getTime());
|
||||
if (newMaxTime.getTime() - getToTime().getTime() < MINIMUM_AUTO_ADVANCE_TIME_IN_MS) {
|
||||
newMaxTime.setTime(getToTime().getTime() + MINIMUM_AUTO_ADVANCE_TIME_IN_MS);
|
||||
}
|
||||
@@ -311,15 +311,15 @@ public class TimePanel<T extends TimePanelSettings> extends SimplePanel implemen
|
||||
break;
|
||||
}
|
||||
}
|
||||
timeSlider.setCurrentValue(new Double(time.getTime()), false);
|
||||
timeSlider.setCurrentValue(new Double(newTime.getTime()), false);
|
||||
}
|
||||
}
|
||||
dateLabel.setText(getDateLabelText(time));
|
||||
timeLabel.setText(getTimeLabelText(time));
|
||||
String timeToStartLabelText = getTimeToStartLabelText(time);
|
||||
dateLabel.setText(getDateLabelText(newTime));
|
||||
timeLabel.setText(getTimeLabelText(newTime));
|
||||
String timeToStartLabelText = getTimeToStartLabelText(newTime);
|
||||
if(timeToStartLabelText != null && !timeToStartLabelText.isEmpty()) {
|
||||
timeToStartControlPanel.setVisible(true);
|
||||
timeToStartLabel.setText(getTimeToStartLabelText(time));
|
||||
timeToStartLabel.setText(getTimeToStartLabelText(newTime));
|
||||
} else {
|
||||
timeToStartControlPanel.setVisible(false);
|
||||
timeToStartLabel.setText("");
|
||||
|
||||
@@ -187,7 +187,7 @@ public class Timer {
|
||||
time = new Date(timePointAsMillis);
|
||||
if ((oldTime == null) != (time == null) || (oldTime != null && !oldTime.equals(time))) {
|
||||
for (TimeListener listener : timeListeners) {
|
||||
listener.timeChanged(time);
|
||||
listener.timeChanged(time, oldTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -261,8 +261,8 @@ public class MediaSelector implements PlayStateListener, TimeListener,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void timeChanged(Date raceTime) {
|
||||
this.currentRaceTime = raceTime;
|
||||
public void timeChanged(Date newRaceTime, Date oldRaceTime) {
|
||||
this.currentRaceTime = newRaceTime;
|
||||
if (activeAudioPlayer != null) {
|
||||
activeAudioPlayer.raceTimeChanged(this.currentRaceTime);
|
||||
ensurePlayState(activeAudioPlayer);
|
||||
|
||||
+5
-5
@@ -204,12 +204,12 @@ public abstract class AbstractCompetitorLeaderboardChart<SettingsType> extends A
|
||||
}
|
||||
|
||||
@Override
|
||||
public void timeChanged(Date date) {
|
||||
public void timeChanged(Date newTime, Date oldTime) {
|
||||
if(!isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadChartData(timer.getPlayMode() == PlayModes.Live ? null : date);
|
||||
loadChartData(timer.getPlayMode() == PlayModes.Live ? null : newTime);
|
||||
}
|
||||
|
||||
protected void loadChartData(Date date) {
|
||||
@@ -362,17 +362,17 @@ public abstract class AbstractCompetitorLeaderboardChart<SettingsType> extends A
|
||||
|
||||
@Override
|
||||
public void competitorsListChanged(Iterable<CompetitorDTO> competitors) {
|
||||
timeChanged(timer.getTime());
|
||||
timeChanged(timer.getTime(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addedToSelection(CompetitorDTO competitor) {
|
||||
timeChanged(timer.getTime());
|
||||
timeChanged(timer.getTime(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removedFromSelection(CompetitorDTO competitor) {
|
||||
timeChanged(timer.getTime());
|
||||
timeChanged(timer.getTime(), null);
|
||||
}
|
||||
|
||||
protected DetailType getSelectedDetailType() {
|
||||
|
||||
+11
-11
@@ -547,7 +547,7 @@ public abstract class AbstractCompetitorRaceChart<SettingsType extends ChartSett
|
||||
|
||||
clearChart();
|
||||
if (selectedRaceIdentifier != null) {
|
||||
timeChanged(timer.getTime());
|
||||
timeChanged(timer.getTime(), null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -592,21 +592,21 @@ public abstract class AbstractCompetitorRaceChart<SettingsType extends ChartSett
|
||||
}
|
||||
|
||||
@Override
|
||||
public void timeChanged(Date date) {
|
||||
public void timeChanged(Date newTime, Date oldTime) {
|
||||
if (!isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (allowTimeAdjust) {
|
||||
updateTimePlotLine(date);
|
||||
updateTimePlotLine(newTime);
|
||||
}
|
||||
|
||||
switch (timer.getPlayMode()) {
|
||||
case Live: {
|
||||
// is date before first cache entry or is cache empty?
|
||||
if (timeOfEarliestRequestInMillis == null || date.getTime() < timeOfEarliestRequestInMillis) {
|
||||
updateChart(timeRangeWithZoomProvider.getFromTime(), date, /* append */true);
|
||||
} else if (date.getTime() > timeOfLatestRequestInMillis) {
|
||||
if (timeOfEarliestRequestInMillis == null || newTime.getTime() < timeOfEarliestRequestInMillis) {
|
||||
updateChart(timeRangeWithZoomProvider.getFromTime(), newTime, /* append */true);
|
||||
} else if (newTime.getTime() > timeOfLatestRequestInMillis) {
|
||||
updateChart(new Date(timeOfLatestRequestInMillis), timeRangeWithZoomProvider.getToTime(), /* append */true);
|
||||
}
|
||||
// otherwise the cache spans across date and so we don't need to load anything
|
||||
@@ -618,9 +618,9 @@ public abstract class AbstractCompetitorRaceChart<SettingsType extends ChartSett
|
||||
updateChart(timeRangeWithZoomProvider.getFromTime(), timeRangeWithZoomProvider.getToTime(), /* append */false);
|
||||
} else {
|
||||
// replay mode during live play
|
||||
if (timeOfEarliestRequestInMillis == null || date.getTime() < timeOfEarliestRequestInMillis) {
|
||||
updateChart(timeRangeWithZoomProvider.getFromTime(), date, /* append */true);
|
||||
} else if (date.getTime() > timeOfLatestRequestInMillis) {
|
||||
if (timeOfEarliestRequestInMillis == null || newTime.getTime() < timeOfEarliestRequestInMillis) {
|
||||
updateChart(timeRangeWithZoomProvider.getFromTime(), newTime, /* append */true);
|
||||
} else if (newTime.getTime() > timeOfLatestRequestInMillis) {
|
||||
updateChart(new Date(timeOfLatestRequestInMillis), timeRangeWithZoomProvider.getToTime(), /* append */true);
|
||||
}
|
||||
}
|
||||
@@ -646,11 +646,11 @@ public abstract class AbstractCompetitorRaceChart<SettingsType extends ChartSett
|
||||
|
||||
@Override
|
||||
public void competitorsListChanged(Iterable<CompetitorDTO> competitors) {
|
||||
timeChanged(timer.getTime());
|
||||
timeChanged(timer.getTime(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void filteredCompetitorsListChanged(Iterable<CompetitorDTO> filteredCompetitors) {
|
||||
timeChanged(timer.getTime());
|
||||
timeChanged(timer.getTime(), null);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -42,7 +42,7 @@ public class MultiCompetitorLeaderboardChart extends AbstractCompetitorLeaderboa
|
||||
|
||||
if(redraw) {
|
||||
clearChart();
|
||||
timeChanged(timer.getTime());
|
||||
timeChanged(timer.getTime(), null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ public class MultiCompetitorRaceChart extends AbstractCompetitorRaceChart<MultiC
|
||||
boolean selectedDetailTypeChanged = setSelectedDetailType(newSettings.getDetailType());
|
||||
if (selectedDetailTypeChanged || settingsChanged) {
|
||||
clearChart();
|
||||
timeChanged(timer.getTime());
|
||||
timeChanged(timer.getTime(), null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+9
-9
@@ -502,20 +502,20 @@ public class WindChart extends AbstractRaceChart implements Component<WindChartS
|
||||
* everything for the currently selected race is loaded; otherwise, no-op.
|
||||
*/
|
||||
@Override
|
||||
public void timeChanged(Date date) {
|
||||
public void timeChanged(Date newTime, Date oldTime) {
|
||||
if(!isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateTimePlotLine(date);
|
||||
updateTimePlotLine(newTime);
|
||||
|
||||
switch(timer.getPlayMode()) {
|
||||
case Live:
|
||||
{
|
||||
// is date before first cache entry or is cache empty?
|
||||
if (timeOfEarliestRequestInMillis == null || date.getTime() < timeOfEarliestRequestInMillis) {
|
||||
loadData(timeRangeWithZoomProvider.getFromTime(), date, /* append */ true);
|
||||
} else if (date.getTime() > timeOfLatestRequestInMillis) {
|
||||
if (timeOfEarliestRequestInMillis == null || newTime.getTime() < timeOfEarliestRequestInMillis) {
|
||||
loadData(timeRangeWithZoomProvider.getFromTime(), newTime, /* append */ true);
|
||||
} else if (newTime.getTime() > timeOfLatestRequestInMillis) {
|
||||
loadData(new Date(timeOfLatestRequestInMillis), timeRangeWithZoomProvider.getToTime(), /* append */true);
|
||||
}
|
||||
// otherwise the cache spans across date and so we don't need to load anything
|
||||
@@ -528,10 +528,10 @@ public class WindChart extends AbstractRaceChart implements Component<WindChartS
|
||||
loadData(timeRangeWithZoomProvider.getFromTime(), timeRangeWithZoomProvider.getToTime(), /* append */false);
|
||||
} else {
|
||||
// replay mode during live play
|
||||
if (timeOfEarliestRequestInMillis == null || date.getTime() < timeOfEarliestRequestInMillis) {
|
||||
loadData(timeRangeWithZoomProvider.getFromTime(), date, /* append */ true);
|
||||
} else if (date.getTime() > timeOfLatestRequestInMillis) {
|
||||
loadData(new Date(timeOfLatestRequestInMillis), date, /* append */true);
|
||||
if (timeOfEarliestRequestInMillis == null || newTime.getTime() < timeOfEarliestRequestInMillis) {
|
||||
loadData(timeRangeWithZoomProvider.getFromTime(), newTime, /* append */ true);
|
||||
} else if (newTime.getTime() > timeOfLatestRequestInMillis) {
|
||||
loadData(new Date(timeOfLatestRequestInMillis), newTime, /* append */true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
+70
-13
@@ -8,6 +8,8 @@ import com.google.gwt.maps.client.base.LatLng;
|
||||
import com.google.gwt.maps.client.base.Point;
|
||||
import com.google.gwt.maps.client.base.Size;
|
||||
import com.sap.sailing.domain.common.Color;
|
||||
import com.sap.sailing.domain.common.LegType;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sailing.domain.common.dto.BoatClassDTO;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
@@ -46,6 +48,23 @@ public class BoatOverlay extends CanvasOverlayV3 {
|
||||
|
||||
private final BoatClassVectorGraphics boatVectorGraphics;
|
||||
|
||||
private LegType lastLegType;
|
||||
private Tack lastTack;
|
||||
private Boolean lastSelected;
|
||||
private Integer lastWidth;
|
||||
private Integer lastHeight;
|
||||
private Double lastScale;
|
||||
private Color lastColor;
|
||||
|
||||
/**
|
||||
* Remembers the old drawing angle as passed to {@link #setCanvasRotation(double)} to minimize rotation angle upon
|
||||
* the next update. The rotation property will always be animated according to the magnitude of the values. A
|
||||
* transition from 5 to 355 will go through 180 and not from 5 to 0==360 and back to 355! Therefore, with 5 being
|
||||
* the last rotation angle, the new rotation angle of 355 needs to be converted to -5 to ensure that the transition
|
||||
* goes through 0.<p>
|
||||
*/
|
||||
private Double boatDrawingAngle;
|
||||
|
||||
public BoatOverlay(final MapWidget map, int zIndex, final CompetitorDTO competitorDTO, Color color) {
|
||||
super(map, zIndex);
|
||||
this.boatClass = competitorDTO.getBoatClass();
|
||||
@@ -66,31 +85,69 @@ public class BoatOverlay extends CanvasOverlayV3 {
|
||||
boatScaleAndSizePerZoomCache.put(zoom, boatScaleAndSize);
|
||||
}
|
||||
double boatSizeScaleFactor = boatScaleAndSize.getA();
|
||||
SpeedWithBearingDTO speedWithBearing = boatFix.speedWithBearing;
|
||||
if (speedWithBearing == null) {
|
||||
speedWithBearing = new SpeedWithBearingDTO(0, 0);
|
||||
}
|
||||
double boatDrawingAngle = speedWithBearing.bearingInDegrees - ORIGINAL_BOAT_IMAGE_ROTATIION_ANGLE;
|
||||
if (boatDrawingAngle < 0) {
|
||||
boatDrawingAngle += 360;
|
||||
}
|
||||
canvasWidth = (int) (boatScaleAndSize.getB().getWidth());
|
||||
canvasHeight = (int) (boatScaleAndSize.getB().getHeight());
|
||||
setCanvasSize(canvasWidth, canvasHeight);
|
||||
boatVectorGraphics.drawBoatToCanvas(getCanvas().getContext2d(), boatFix.legType, boatFix.tack, isSelected(),
|
||||
canvasWidth, canvasHeight, boatDrawingAngle, boatSizeScaleFactor, color.getAsHtml());
|
||||
if (lastWidth == null || canvasWidth != lastWidth || lastHeight == null || canvasHeight != lastHeight) {
|
||||
setCanvasSize(canvasWidth, canvasHeight);
|
||||
}
|
||||
if (needToDraw(boatFix.legType, boatFix.tack, isSelected(), canvasWidth, canvasHeight, boatSizeScaleFactor, color)) {
|
||||
boatVectorGraphics.drawBoatToCanvas(getCanvas().getContext2d(), boatFix.legType, boatFix.tack, isSelected(),
|
||||
canvasWidth, canvasHeight, boatSizeScaleFactor, color);
|
||||
lastLegType = boatFix.legType;
|
||||
lastTack = boatFix.tack;
|
||||
lastSelected = isSelected();
|
||||
lastWidth = canvasWidth;
|
||||
lastHeight = canvasHeight;
|
||||
lastScale = boatSizeScaleFactor;
|
||||
lastColor = color;
|
||||
}
|
||||
LatLng latLngPosition = LatLng.newInstance(boatFix.position.latDeg, boatFix.position.lngDeg);
|
||||
Point boatPositionInPx = mapProjection.fromLatLngToDivPixel(latLngPosition);
|
||||
setCanvasPosition(boatPositionInPx.getX() - getCanvas().getCoordinateSpaceWidth() / 2,
|
||||
boatPositionInPx.getY() - getCanvas().getCoordinateSpaceHeight() / 2);
|
||||
// now rotate the canvas accordingly
|
||||
SpeedWithBearingDTO speedWithBearing = boatFix.speedWithBearing;
|
||||
if (speedWithBearing == null) {
|
||||
speedWithBearing = new SpeedWithBearingDTO(0, 0);
|
||||
}
|
||||
updateBoatDrawingAngle(speedWithBearing.bearingInDegrees - ORIGINAL_BOAT_IMAGE_ROTATIION_ANGLE);
|
||||
setCanvasRotation(boatDrawingAngle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the drawing parameters to {@link #lastLegType} and the other <code>last...</code>. If anything has
|
||||
* changed, the result is <code>true</code>.
|
||||
*/
|
||||
private boolean needToDraw(LegType legType, Tack tack, boolean isSelected, double width, double height,
|
||||
double scaleFactor, Color color) {
|
||||
return lastLegType == null || lastLegType != legType || lastTack == null || lastTack != tack
|
||||
|| lastSelected == null || lastSelected != isSelected || lastWidth == null || lastWidth != width
|
||||
|| lastHeight == null || lastHeight != height || lastScale == null || lastScale != scaleFactor
|
||||
|| lastColor == null || !lastColor.equals(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates {@link #boatDrawingAngle} to that the CSS transition from the old {@link #boatDrawingAngle} to
|
||||
* <code>newBoatDrawingAngle</code> is minimal.
|
||||
*/
|
||||
private void updateBoatDrawingAngle(double newBoatDrawingAngle) {
|
||||
if (boatDrawingAngle == null) {
|
||||
boatDrawingAngle = newBoatDrawingAngle;
|
||||
} else {
|
||||
double newMinusOld;
|
||||
while (Math.abs(newMinusOld = newBoatDrawingAngle - boatDrawingAngle) > 180) {
|
||||
newBoatDrawingAngle -= Math.signum(newMinusOld)*360;
|
||||
}
|
||||
boatDrawingAngle = boatDrawingAngle+newMinusOld;
|
||||
}
|
||||
}
|
||||
|
||||
public void setBoatFix(GPSFixDTO boatFix, long timeForPositionTransitionMillis) {
|
||||
if (timeForPositionTransitionMillis == -1) {
|
||||
removeCanvasPositionTransition();
|
||||
removeCanvasPositionAndRotationTransition();
|
||||
} else {
|
||||
setCanvasPositionTransition(timeForPositionTransitionMillis);
|
||||
setCanvasPositionAndRotationTransition(timeForPositionTransitionMillis);
|
||||
}
|
||||
this.boatFix = boatFix;
|
||||
}
|
||||
|
||||
+2
-2
@@ -112,9 +112,9 @@ public class CompetitorInfoOverlay extends CanvasOverlayV3 {
|
||||
|
||||
public void setPosition(PositionDTO position, long timeForPositionTransitionMillis) {
|
||||
if (timeForPositionTransitionMillis == -1) {
|
||||
removeCanvasPositionTransition();
|
||||
removeCanvasPositionAndRotationTransition();
|
||||
} else {
|
||||
setCanvasPositionTransition(timeForPositionTransitionMillis);
|
||||
setCanvasPositionAndRotationTransition(timeForPositionTransitionMillis);
|
||||
}
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
+45
-35
@@ -252,7 +252,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
|
||||
/**
|
||||
* The last quick ranks received from a call to {@link SailingServiceAsync#getQuickRanks(RaceIdentifier, Date, AsyncCallback)} upon
|
||||
* the last {@link #timeChanged(Date)} event. Therefore, the ranks listed here correspond to the {@link #timer}'s time.
|
||||
* the last {@link #timeChanged(Date, Date)} event. Therefore, the ranks listed here correspond to the {@link #timer}'s time.
|
||||
*/
|
||||
private List<QuickRankDTO> quickRanks;
|
||||
|
||||
@@ -363,11 +363,11 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
if (!isAutoZoomInProgress() && !map.getBounds().equals(currentMapBounds)) {
|
||||
// remove the canvas animations for boats
|
||||
for (BoatOverlay boatOverlay : RaceMap.this.getBoatOverlays().values()) {
|
||||
boatOverlay.removeCanvasPositionTransition();
|
||||
boatOverlay.removeCanvasPositionAndRotationTransition();
|
||||
}
|
||||
// remove the canvas animations for the info overlays of the selected boats
|
||||
for(CompetitorInfoOverlay infoOverlay: competitorInfoOverlays.values()) {
|
||||
infoOverlay.removeCanvasPositionTransition();
|
||||
infoOverlay.removeCanvasPositionAndRotationTransition();
|
||||
}
|
||||
}
|
||||
currentMapBounds = map.getBounds();
|
||||
@@ -376,7 +376,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
|
||||
//If there was a time change before the API was loaded, reset the time
|
||||
if (lastTimeChangeBeforeInitialization != null) {
|
||||
timeChanged(lastTimeChangeBeforeInitialization);
|
||||
timeChanged(lastTimeChangeBeforeInitialization, null);
|
||||
lastTimeChangeBeforeInitialization = null;
|
||||
}
|
||||
//Data has been initialized
|
||||
@@ -389,7 +389,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
}
|
||||
|
||||
public void redraw() {
|
||||
timeChanged(timer.getTime());
|
||||
timeChanged(timer.getTime(), null);
|
||||
}
|
||||
|
||||
Map<CompetitorDTO, BoatOverlay> getBoatOverlays() {
|
||||
@@ -414,19 +414,19 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
}
|
||||
|
||||
@Override
|
||||
public void timeChanged(final Date date) {
|
||||
if (date != null && isMapInitialized) {
|
||||
public void timeChanged(final Date newTime, final Date oldTime) {
|
||||
if (newTime != null && isMapInitialized) {
|
||||
if (selectedRaces != null && !selectedRaces.isEmpty()) {
|
||||
RegattaAndRaceIdentifier race = selectedRaces.get(selectedRaces.size() - 1);
|
||||
final Iterable<CompetitorDTO> competitorsToShow = getCompetitorsToShow();
|
||||
|
||||
if (race != null) {
|
||||
final Triple<Map<CompetitorDTO, Date>, Map<CompetitorDTO, Date>, Map<CompetitorDTO, Boolean>> fromAndToAndOverlap =
|
||||
fixesAndTails.computeFromAndTo(date, competitorsToShow, settings.getEffectiveTailLengthInMilliseconds());
|
||||
fixesAndTails.computeFromAndTo(newTime, competitorsToShow, settings.getEffectiveTailLengthInMilliseconds());
|
||||
final int requestID = ++boatPositionRequestIDCounter;
|
||||
|
||||
GetRaceMapDataAction getRaceMapDataAction = new GetRaceMapDataAction(sailingService, competitorSelection.getAllCompetitors(), race,
|
||||
date, fromAndToAndOverlap.getA(), fromAndToAndOverlap.getB(), /* extrapolate */ true, new AsyncCallback<RaceMapDataDTO>() {
|
||||
newTime, fromAndToAndOverlap.getA(), fromAndToAndOverlap.getB(), /* extrapolate */ true, new AsyncCallback<RaceMapDataDTO>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError("Error obtaining racemap data: " + caught.getMessage(), true /*silentMode */);
|
||||
@@ -441,11 +441,10 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
startedProcessingRequestID = requestID;
|
||||
// Do boat specific actions
|
||||
Map<CompetitorDTO, List<GPSFixDTO>> boatData = raceMapDataDTO.boatPositions;
|
||||
final long timeForPositionTransitionMillis = timer.getPlayState() == PlayStates.Playing ? // animate when playing
|
||||
1300*timer.getRefreshInterval()/1000 : -1;
|
||||
long timeForPositionTransitionMillis = calculateTimeForPositionTransition(newTime, oldTime);
|
||||
fixesAndTails.updateFixes(boatData, fromAndToAndOverlap.getC(), RaceMap.this, timeForPositionTransitionMillis);
|
||||
showBoatsOnMap(date, getCompetitorsToShow(), timeForPositionTransitionMillis);
|
||||
showCompetitorInfoOnMap(date, competitorSelection.getSelectedCompetitors());
|
||||
showBoatsOnMap(newTime, timeForPositionTransitionMillis, getCompetitorsToShow());
|
||||
showCompetitorInfoOnMap(newTime, timeForPositionTransitionMillis, competitorSelection.getSelectedCompetitors());
|
||||
if (douglasMarkers != null) {
|
||||
removeAllMarkDouglasPeuckerpoints();
|
||||
}
|
||||
@@ -457,7 +456,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
showCourseMarksOnMap(raceMapDataDTO.coursePositions);
|
||||
showCourseSidelinesOnMap(raceMapDataDTO.courseSidelines);
|
||||
showStartAndFinishLines(raceMapDataDTO.coursePositions);
|
||||
showAdvantageLine(competitorsToShow, date);
|
||||
showAdvantageLine(competitorsToShow, newTime);
|
||||
|
||||
// Rezoom the map
|
||||
// TODO make this a loop across the LatLngBoundsCalculators, pulling them from a collection updated in updateSettings
|
||||
@@ -478,7 +477,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lastTimeChangeBeforeInitialization = date;
|
||||
lastTimeChangeBeforeInitialization = newTime;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -488,7 +487,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
windSourceTypeNames.add(WindSourceType.EXPEDITION.name());
|
||||
windSourceTypeNames.add(WindSourceType.COMBINED.name());
|
||||
|
||||
GetWindInfoAction getWindInfoAction = new GetWindInfoAction(sailingService, race, date, 1000L, 1, windSourceTypeNames,
|
||||
GetWindInfoAction getWindInfoAction = new GetWindInfoAction(sailingService, race, newTime, 1000L, 1, windSourceTypeNames,
|
||||
new AsyncCallback<WindInfoForRaceDTO>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
@@ -512,7 +511,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
showCombinedWindOnMap(windSource, windTrackInfoDTO);
|
||||
if (windTrackInfoDTO != null) {
|
||||
lastCombinedWindTrackInfoDTO = windTrackInfoDTO;
|
||||
showAdvantageLine(competitorsToShow, date);
|
||||
showAdvantageLine(competitorsToShow, newTime);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -654,16 +653,14 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
}
|
||||
}
|
||||
|
||||
protected void showCompetitorInfoOnMap(final Date date, final Iterable<CompetitorDTO> competitorsToShow) {
|
||||
protected void showCompetitorInfoOnMap(final Date newTime, final long timeForPositionTransitionMillis, final Iterable<CompetitorDTO> competitorsToShow) {
|
||||
if (map != null) {
|
||||
if (settings.isShowSelectedCompetitorsInfo()) {
|
||||
Set<CompetitorDTO> toRemoveCompetorInfoOverlays = new HashSet<CompetitorDTO>(
|
||||
competitorInfoOverlays.keySet());
|
||||
final long timeForPositionTransitionMillis = timer.getPlayState() == PlayStates.Playing ? // animate when playing
|
||||
1300*timer.getRefreshInterval()/1000 : -1;
|
||||
for (CompetitorDTO competitorDTO : competitorsToShow) {
|
||||
if (fixesAndTails.hasFixesFor(competitorDTO)) {
|
||||
GPSFixDTO lastBoatFix = getBoatFix(competitorDTO, date);
|
||||
GPSFixDTO lastBoatFix = getBoatFix(competitorDTO, newTime);
|
||||
if (lastBoatFix != null) {
|
||||
CompetitorInfoOverlay competitorInfoOverlay = competitorInfoOverlays.get(competitorDTO);
|
||||
if (competitorInfoOverlay == null) {
|
||||
@@ -693,11 +690,24 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private long calculateTimeForPositionTransition(final Date newTime, final Date oldTime) {
|
||||
final long timeForPositionTransitionMillis;
|
||||
boolean hasTimeJumped = oldTime != null && Math.abs(oldTime.getTime() - newTime.getTime()) > 3*timer.getRefreshInterval();
|
||||
if (timer.getPlayState() == PlayStates.Playing && !hasTimeJumped) {
|
||||
// choose 130% of the refresh interval as transition period to make it unlikely that the transition
|
||||
// stops before the next update has been received
|
||||
timeForPositionTransitionMillis = 1300 * timer.getRefreshInterval() / 1000;
|
||||
} else {
|
||||
timeForPositionTransitionMillis = -1; // -1 means 'no transition
|
||||
}
|
||||
return timeForPositionTransitionMillis;
|
||||
}
|
||||
|
||||
protected void showBoatsOnMap(final Date date, final Iterable<CompetitorDTO> competitorsToShow, long timeForPositionTransitionMillis) {
|
||||
protected void showBoatsOnMap(final Date newTime, final long timeForPositionTransitionMillis, final Iterable<CompetitorDTO> competitorsToShow) {
|
||||
if (map != null) {
|
||||
Date tailsFromTime = new Date(date.getTime() - settings.getEffectiveTailLengthInMilliseconds());
|
||||
Date tailsToTime = date;
|
||||
Date tailsFromTime = new Date(newTime.getTime() - settings.getEffectiveTailLengthInMilliseconds());
|
||||
Date tailsToTime = newTime;
|
||||
Set<CompetitorDTO> competitorDTOsOfUnusedTails = new HashSet<CompetitorDTO>(fixesAndTails.getCompetitorsWithTails());
|
||||
Set<CompetitorDTO> competitorDTOsOfUnusedBoatCanvases = new HashSet<CompetitorDTO>(boatOverlays.keySet());
|
||||
for (CompetitorDTO competitorDTO : competitorsToShow) {
|
||||
@@ -713,7 +723,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
PolylineOptions newOptions = createTailStyle(competitorDTO, displayHighlighted(competitorDTO));
|
||||
tail.setOptions(newOptions);
|
||||
}
|
||||
boolean usedExistingBoatCanvas = updateBoatCanvasForCompetitor(competitorDTO, date, timeForPositionTransitionMillis);
|
||||
boolean usedExistingBoatCanvas = updateBoatCanvasForCompetitor(competitorDTO, newTime, timeForPositionTransitionMillis);
|
||||
if (usedExistingBoatCanvas) {
|
||||
competitorDTOsOfUnusedBoatCanvases.remove(competitorDTO);
|
||||
}
|
||||
@@ -1508,10 +1518,10 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
i.remove(); // only this way a ConcurrentModificationException while looping can be avoided
|
||||
}
|
||||
}
|
||||
showCompetitorInfoOnMap(timer.getTime(), competitorSelection.getSelectedCompetitors());
|
||||
showCompetitorInfoOnMap(timer.getTime(), -1, competitorSelection.getSelectedCompetitors());
|
||||
} else {
|
||||
// adding a single competitor; may need to re-load data, so refresh:
|
||||
timeChanged(timer.getTime());
|
||||
timeChanged(timer.getTime(), null);
|
||||
}
|
||||
} else {
|
||||
// only change highlighting
|
||||
@@ -1519,12 +1529,12 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
if (boatCanvas != null) {
|
||||
boatCanvas.setSelected(displayHighlighted(competitor));
|
||||
boatCanvas.draw();
|
||||
showCompetitorInfoOnMap(timer.getTime(), competitorSelection.getSelectedCompetitors());
|
||||
showCompetitorInfoOnMap(timer.getTime(), -1, competitorSelection.getSelectedCompetitors());
|
||||
} else {
|
||||
// seems like an internal error not to find the lowlighted marker; but maybe the
|
||||
// competitor was added late to the race;
|
||||
// data for newly selected competitor supposedly missing; refresh
|
||||
timeChanged(timer.getTime());
|
||||
timeChanged(timer.getTime(), null);
|
||||
}
|
||||
}
|
||||
// Now update tails for all competitors because selection change may also affect all unselected competitors
|
||||
@@ -1547,13 +1557,13 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
if (isShowAnyHelperLines()) {
|
||||
// helper lines depend on which competitor is visible, because the *visible* leader is used for
|
||||
// deciding which helper lines to show:
|
||||
timeChanged(timer.getTime());
|
||||
timeChanged(timer.getTime(), null);
|
||||
} else {
|
||||
// try a more incremental update otherwise
|
||||
if (settings.isShowOnlySelectedCompetitors()) {
|
||||
// if selection is now empty, show all competitors
|
||||
if (Util.isEmpty(competitorSelection.getSelectedCompetitors())) {
|
||||
timeChanged(timer.getTime());
|
||||
timeChanged(timer.getTime(), null);
|
||||
} else {
|
||||
// otherwise remove only deselected competitor's boat images and tail
|
||||
BoatOverlay removedBoatOverlay = boatOverlays.remove(competitor);
|
||||
@@ -1561,7 +1571,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
removedBoatOverlay.removeFromMap();
|
||||
}
|
||||
fixesAndTails.removeTail(competitor);
|
||||
showCompetitorInfoOnMap(timer.getTime(), competitorSelection.getSelectedCompetitors());
|
||||
showCompetitorInfoOnMap(timer.getTime(), -1, competitorSelection.getSelectedCompetitors());
|
||||
}
|
||||
} else {
|
||||
// "lowlight" currently selected competitor
|
||||
@@ -1570,7 +1580,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
boatCanvas.setSelected(displayHighlighted(competitor));
|
||||
boatCanvas.draw();
|
||||
}
|
||||
showCompetitorInfoOnMap(timer.getTime(), competitorSelection.getSelectedCompetitors());
|
||||
showCompetitorInfoOnMap(timer.getTime(), -1, competitorSelection.getSelectedCompetitors());
|
||||
}
|
||||
}
|
||||
//Trigger auto-zoom if needed
|
||||
@@ -1793,12 +1803,12 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
|
||||
@Override
|
||||
public void competitorsListChanged(Iterable<CompetitorDTO> competitors) {
|
||||
timeChanged(timer.getTime());
|
||||
timeChanged(timer.getTime(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void filteredCompetitorsListChanged(Iterable<CompetitorDTO> filteredCompetitors) {
|
||||
timeChanged(timer.getTime());
|
||||
timeChanged(timer.getTime(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-2
@@ -116,9 +116,9 @@ public class SmallTransparentInfoOverlay extends CanvasOverlayV3 {
|
||||
|
||||
public void setPosition(PositionDTO position, long timeForPositionTransitionMillis) {
|
||||
if (timeForPositionTransitionMillis == -1) {
|
||||
removeCanvasPositionTransition();
|
||||
removeCanvasPositionAndRotationTransition();
|
||||
} else {
|
||||
setCanvasPositionTransition(timeForPositionTransitionMillis);
|
||||
setCanvasPositionAndRotationTransition(timeForPositionTransitionMillis);
|
||||
}
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
+6
@@ -7,6 +7,12 @@ import com.google.gwt.maps.client.overlays.Polyline;
|
||||
import com.google.gwt.maps.client.overlays.PolylineOptions;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
|
||||
/**
|
||||
* Creates tails and their styles for the map.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public interface TailFactory {
|
||||
Polyline createTail(CompetitorDTO competitor, List<LatLng> points);
|
||||
|
||||
|
||||
+1
-1
@@ -87,7 +87,7 @@ public abstract class AbstractLeaderboardViewer extends SimplePanel {
|
||||
|
||||
if (visible && component instanceof TimeListener) {
|
||||
// trigger the component to update its data
|
||||
((TimeListener) component).timeChanged(timer.getTime());
|
||||
((TimeListener) component).timeChanged(timer.getTime(), null);
|
||||
}
|
||||
if(component.hasSettings() && !hasSettingsWhenComponentIsInvisible) {
|
||||
settingsButton.setEnabled(visible);
|
||||
|
||||
+4
-3
@@ -884,6 +884,7 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
|
||||
* Reports the ratio of the time that passed since the last position fix and the average sampling interval of the
|
||||
* competitor's track. On a perfect track, this value will never exceed 1.0. Immediately when a fix is received, this
|
||||
* value goes to 0.0. For a competitor whose tracker is lagging, this value can grow considerably greater than 1.
|
||||
* The value goes to <code>null</code> if there are no fixes in the track.
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
@@ -2352,12 +2353,12 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
|
||||
}
|
||||
|
||||
/**
|
||||
* @param date
|
||||
* @param newTime
|
||||
* ignored; may be <code>null</code>. The time for loading the leaderboard is determined using
|
||||
* {@link #getLeaderboardDisplayDate()}.
|
||||
*/
|
||||
@Override
|
||||
public void timeChanged(Date date) {
|
||||
public void timeChanged(Date newTime, Date oldTime) {
|
||||
loadCompleteLeaderboard(getLeaderboardDisplayDate());
|
||||
}
|
||||
|
||||
@@ -2470,7 +2471,7 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
|
||||
|
||||
@Override
|
||||
public void competitorsListChanged(Iterable<CompetitorDTO> competitors) {
|
||||
timeChanged(timer.getTime());
|
||||
timeChanged(timer.getTime(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ public class LeaderboardViewer extends AbstractLeaderboardViewer {
|
||||
// Remark: For now we only add the overallLeaderboardPanel to the navigation menu in case it's visible from the beginning
|
||||
|
||||
if(showCharts) {
|
||||
multiCompetitorChart.timeChanged(timer.getTime());
|
||||
multiCompetitorChart.timeChanged(timer.getTime(), null);
|
||||
}
|
||||
|
||||
overallLeaderboardPanel = null;
|
||||
|
||||
+2
-2
@@ -227,9 +227,9 @@ public class MultiLeaderboardPanel extends AbstractLazyComponent<LeaderboardSett
|
||||
}
|
||||
|
||||
@Override
|
||||
public void timeChanged(Date date) {
|
||||
public void timeChanged(Date newTime, Date oldTime) {
|
||||
if(selectedLeaderboardPanel != null) {
|
||||
selectedLeaderboardPanel.timeChanged(date);
|
||||
selectedLeaderboardPanel.timeChanged(newTime, oldTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -698,7 +698,7 @@ public class EditableLeaderboardPanel extends LeaderboardPanel {
|
||||
public void onSuccess(Void result) {
|
||||
Window.setStatus("Successfully unsuppressed competitor "+object.getName());
|
||||
// force a reload of the entire editable leaderboard to hide the now suppressed competitor
|
||||
timeChanged(getLeaderboardDisplayDate());
|
||||
timeChanged(getLeaderboardDisplayDate(), null);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -770,7 +770,7 @@ public class EditableLeaderboardPanel extends LeaderboardPanel {
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
// force a reload of the entire editable leaderboard to hide the now suppressed competitor
|
||||
timeChanged(getLeaderboardDisplayDate());
|
||||
timeChanged(getLeaderboardDisplayDate(), null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+1
-1
@@ -421,7 +421,7 @@ public class MatchAndApplyScoreCorrectionsDialog extends DataEntryDialog<BulkSco
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
Window.setStatus(stringMessages.successfullyUpdatedScores());
|
||||
leaderboardPanel.timeChanged(/* time point is ignored */ null); // reload leaderboard contents to reflect changes
|
||||
leaderboardPanel.timeChanged(/* time point is ignored */ null, null); // reload leaderboard contents to reflect changes
|
||||
// leaderboard panel sets busy indicator to non-busy after done with updating
|
||||
}
|
||||
});
|
||||
|
||||
+96
-26
@@ -5,7 +5,10 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.github.gwtbootstrap.client.ui.ProgressBar;
|
||||
import com.github.gwtbootstrap.client.ui.base.ProgressBarBase.Style;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.event.dom.client.KeyCodes;
|
||||
@@ -13,6 +16,7 @@ import com.google.gwt.event.dom.client.KeyDownEvent;
|
||||
import com.google.gwt.event.dom.client.KeyDownHandler;
|
||||
import com.google.gwt.event.dom.client.KeyUpEvent;
|
||||
import com.google.gwt.event.dom.client.KeyUpHandler;
|
||||
import com.google.gwt.user.client.Timer;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
@@ -23,6 +27,7 @@ import com.google.gwt.user.client.ui.ListBox;
|
||||
import com.google.gwt.user.client.ui.ScrollPanel;
|
||||
import com.google.gwt.user.client.ui.TextBox;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.sap.sailing.domain.common.DataImportProgress;
|
||||
import com.sap.sailing.domain.common.MasterDataImportObjectCreationCount;
|
||||
import com.sap.sailing.gwt.ui.client.EventRefresher;
|
||||
import com.sap.sailing.gwt.ui.client.LeaderboardGroupRefresher;
|
||||
@@ -109,44 +114,101 @@ public class MasterDataImportPanel extends VerticalPanel {
|
||||
|
||||
protected void importLeaderboardGroups() {
|
||||
String[] groupNames = createLeaderBoardGroupNamesFromListBox();
|
||||
final Label overallName = new Label(stringMessages.overallProgress() + ":");
|
||||
this.add(overallName);
|
||||
final ProgressBar overallProgressBar = new ProgressBar(Style.ANIMATED);
|
||||
this.add(overallProgressBar);
|
||||
final Label subProgressName = new Label();
|
||||
this.add(subProgressName);
|
||||
final ProgressBar subProgressBar = new ProgressBar(Style.ANIMATED);
|
||||
this.add(subProgressBar);
|
||||
if (groupNames.length >= 1) {
|
||||
disableAllButtons();
|
||||
boolean override = overrideSwitch.getValue();
|
||||
boolean compress = compressSwitch.getValue();
|
||||
sailingService.importMasterData(currentHost, groupNames, override, compress,
|
||||
new AsyncCallback<MasterDataImportObjectCreationCount>() {
|
||||
@Override
|
||||
public void onSuccess(MasterDataImportObjectCreationCount result) {
|
||||
int leaderboardsCreated = result.getLeaderboardCount();
|
||||
int leaderboardGroupsCreated = result.getLeaderboardGroupCount();
|
||||
int eventsCreated = result.getEventCount();
|
||||
int regattasCreated = result.getRegattaCount();
|
||||
if (regattasCreated > 0) {
|
||||
regattaRefresher.fillRegattas();
|
||||
}
|
||||
if (eventsCreated > 0) {
|
||||
eventRefresher.fillEvents();
|
||||
}
|
||||
if (leaderboardGroupsCreated > 0) {
|
||||
leaderboardGroupRefresher.fillLeaderboardGroups();
|
||||
}
|
||||
Set<String> overwrittenRegattas = result.getOverwrittenRegattaNames();
|
||||
showSuccessAlert(leaderboardsCreated, leaderboardGroupsCreated, eventsCreated,
|
||||
regattasCreated, overwrittenRegattas);
|
||||
changeButtonStateAccordingToApplicationState();
|
||||
}
|
||||
sailingService.importMasterData(currentHost, groupNames, override, compress, new AsyncCallback<UUID>() {
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
showErrorAlert(caught.getLocalizedMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(final UUID resultId) {
|
||||
final Timer timer = new Timer() {
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
showErrorAlert(caught.getLocalizedMessage());
|
||||
changeButtonStateAccordingToApplicationState();
|
||||
public void run() {
|
||||
sailingService.getImportOperationProgress(resultId,
|
||||
new AsyncCallback<DataImportProgress>() {
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
showErrorAlert(stringMessages.importServerError());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(DataImportProgress result) {
|
||||
if (result == null) {
|
||||
showErrorAlert(stringMessages.importServerError());
|
||||
} else {
|
||||
if (result.failed()) {
|
||||
// Got error, cancel timer
|
||||
cancel();
|
||||
deleteProgressIndication(overallName, overallProgressBar,
|
||||
subProgressName, subProgressBar);
|
||||
|
||||
showErrorAlert(result.getErrorMessage());
|
||||
changeButtonStateAccordingToApplicationState();
|
||||
} else {
|
||||
MasterDataImportObjectCreationCount creationCount = result
|
||||
.getResult();
|
||||
if (creationCount != null) {
|
||||
// Got result, cancel timer
|
||||
cancel();
|
||||
deleteProgressIndication(overallName, overallProgressBar,
|
||||
subProgressName, subProgressBar);
|
||||
showCreationMessage(creationCount);
|
||||
} else {
|
||||
overallProgressBar.setPercent((int) (result
|
||||
.getOverallProgressPct() * 100));
|
||||
subProgressName.setText(result.getNameOfCurrentSubProgress());
|
||||
subProgressBar.setPercent((int) (result
|
||||
.getCurrentSubProgressPct() * 100));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
timer.scheduleRepeating(5000);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
showErrorAlert(stringMessages.importSelectAtLeastOne());
|
||||
}
|
||||
}
|
||||
|
||||
private void showCreationMessage(MasterDataImportObjectCreationCount creationCount) {
|
||||
int leaderboardsCreated = creationCount.getLeaderboardCount();
|
||||
int leaderboardGroupsCreated = creationCount.getLeaderboardGroupCount();
|
||||
int eventsCreated = creationCount.getEventCount();
|
||||
int regattasCreated = creationCount.getRegattaCount();
|
||||
if (regattasCreated > 0) {
|
||||
regattaRefresher.fillRegattas();
|
||||
}
|
||||
if (eventsCreated > 0) {
|
||||
eventRefresher.fillEvents();
|
||||
}
|
||||
if (leaderboardGroupsCreated > 0) {
|
||||
leaderboardGroupRefresher.fillLeaderboardGroups();
|
||||
}
|
||||
Set<String> overwrittenRegattas = creationCount.getOverwrittenRegattaNames();
|
||||
showSuccessAlert(leaderboardsCreated, leaderboardGroupsCreated, eventsCreated, regattasCreated,
|
||||
overwrittenRegattas);
|
||||
changeButtonStateAccordingToApplicationState();
|
||||
}
|
||||
|
||||
private void disableAllButtons() {
|
||||
boolean enabled = false;
|
||||
@@ -316,4 +378,12 @@ public class MasterDataImportPanel extends VerticalPanel {
|
||||
changeButtonStateAccordingToApplicationState();
|
||||
}
|
||||
|
||||
private void deleteProgressIndication(final Label overallName, final ProgressBar overallProgressBar,
|
||||
final Label subProgressName, final ProgressBar subProgressBar) {
|
||||
this.remove(overallProgressBar);
|
||||
this.remove(subProgressBar);
|
||||
this.remove(subProgressName);
|
||||
this.remove(overallName);
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -473,7 +473,7 @@ public class RaceBoardPanel extends SimplePanel implements RegattaDisplayer, Rac
|
||||
|
||||
if (visible && component instanceof TimeListener) {
|
||||
// trigger the component to update its data
|
||||
((TimeListener) component).timeChanged(timer.getTime());
|
||||
((TimeListener) component).timeChanged(timer.getTime(), null);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
+61
-25
@@ -5,12 +5,16 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gwt.dom.client.Style;
|
||||
import com.google.gwt.dom.client.Style.Unit;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.event.logical.shared.ValueChangeEvent;
|
||||
import com.google.gwt.event.logical.shared.ValueChangeHandler;
|
||||
import com.google.gwt.i18n.client.DateTimeFormat;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.CheckBox;
|
||||
import com.google.gwt.user.client.ui.FlexTable;
|
||||
import com.google.gwt.user.client.ui.Grid;
|
||||
import com.google.gwt.user.client.ui.HasVerticalAlignment;
|
||||
@@ -40,6 +44,7 @@ import com.sap.sailing.gwt.ui.shared.RaceGroupDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
|
||||
|
||||
public class RegattaOverviewPanel extends SimplePanel {
|
||||
private final static String STYLE_VIEWER_TOOLBAR_INNERELEMENT = "viewerToolbar-innerElement";
|
||||
|
||||
private final long serverUpdateRateInMs = 10000;
|
||||
private final long uiUpdateRateInMs = 450;
|
||||
@@ -55,6 +60,7 @@ public class RegattaOverviewPanel extends SimplePanel {
|
||||
private EventDTO eventDTO;
|
||||
private List<RaceGroupDTO> raceGroupDTOs;
|
||||
private List<EventAndRaceGroupAvailabilityListener> eventRaceGroupListeners;
|
||||
private boolean showLeaderboard = false;
|
||||
|
||||
private RegattaRaceStatesComponent regattaRaceStatesComponent;
|
||||
|
||||
@@ -65,6 +71,7 @@ public class RegattaOverviewPanel extends SimplePanel {
|
||||
private final Button settingsButton;
|
||||
private final Button refreshNowButton;
|
||||
private final Button startStopUpdatingButton;
|
||||
private final CheckBox leaderboardCheckBox;
|
||||
private final UserAgentDetails userAgent;
|
||||
|
||||
private final DateTimeFormat timeFormatter = DateTimeFormat.getFormat("HH:mm:ss");
|
||||
@@ -140,15 +147,15 @@ public class RegattaOverviewPanel extends SimplePanel {
|
||||
this.startStopUpdatingButton.getElement().getStyle().setMarginLeft(20.0, Unit.PX);
|
||||
this.serverUpdateTimer.addTimeListener(new TimeListener() {
|
||||
@Override
|
||||
public void timeChanged(Date date) {
|
||||
public void timeChanged(Date newTime, Date oldTime) {
|
||||
regattaRaceStatesComponent.onUpdateServer();
|
||||
}
|
||||
});
|
||||
this.serverUpdateTimer.play();
|
||||
this.uiUpdateTimer.addTimeListener(new TimeListener() {
|
||||
@Override
|
||||
public void timeChanged(Date date) {
|
||||
onUpdateUI(date);
|
||||
public void timeChanged(Date newTime, Date oldTime) {
|
||||
onUpdateUI(newTime);
|
||||
}
|
||||
});
|
||||
this.uiUpdateTimer.play();
|
||||
@@ -177,6 +184,8 @@ public class RegattaOverviewPanel extends SimplePanel {
|
||||
flexTable.setWidget(0, 0, eventVenueGrid);
|
||||
flexTable.getCellFormatter().setVerticalAlignment(0, 0, HasVerticalAlignment.ALIGN_MIDDLE);
|
||||
|
||||
leaderboardCheckBox = addLeaderboardEnablerButton();
|
||||
this.leaderboardCheckBox.getElement().getStyle().setMarginLeft(20.0, Unit.PX);
|
||||
HorizontalPanel refreshStartStopClockPanel = getRefreshStartStopClockPanel();
|
||||
|
||||
flexTable.setWidget(0, 1, refreshStartStopClockPanel);
|
||||
@@ -189,36 +198,62 @@ public class RegattaOverviewPanel extends SimplePanel {
|
||||
mainPanel.add(leaderboardsTabPanel);
|
||||
|
||||
onUpdateUI(uiUpdateTimer.getLiveTimePointAsDate());
|
||||
addLeaderboardEnablerButton();
|
||||
}
|
||||
|
||||
private CheckBox addLeaderboardEnablerButton() {
|
||||
final CheckBox checkBox = new CheckBox("Leaderboard");
|
||||
|
||||
checkBox.getElement().getStyle().setFloat(Style.Float.LEFT);
|
||||
|
||||
checkBox.setEnabled(true);
|
||||
checkBox.setValue(false);
|
||||
checkBox.setTitle(stringMessages.showHideComponent("Leaderboard"));
|
||||
checkBox.addStyleName(STYLE_VIEWER_TOOLBAR_INNERELEMENT);
|
||||
|
||||
checkBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
|
||||
@Override
|
||||
public void onValueChange(ValueChangeEvent<Boolean> newValue) {
|
||||
boolean visible = checkBox.getValue();
|
||||
showLeaderboard = visible;
|
||||
loadLeaderboard();
|
||||
}
|
||||
});
|
||||
|
||||
return checkBox;
|
||||
}
|
||||
|
||||
private void loadLeaderboard() {
|
||||
/*
|
||||
* Load a tabbed widget with one tab per regatta. Each tab contains the leaderboard for the regatta.
|
||||
*/
|
||||
final CompetitorSelectionModel competitorSelectionProvider = new CompetitorSelectionModel(/* hasMultiSelection */ true);
|
||||
final LeaderboardSettings leaderboardSettings = LeaderboardSettingsFactory.getInstance().createNewDefaultSettings(null, null, null, /* autoExpandFirstRace */ false);
|
||||
sailingService.getLeaderboardsByEvent(eventDTO, new AsyncCallback<List<StrippedLeaderboardDTO>>() {
|
||||
@Override
|
||||
public void onSuccess(List<StrippedLeaderboardDTO> result) {
|
||||
leaderboardsTabPanel.clear();
|
||||
for (StrippedLeaderboardDTO leaderboard : result) {
|
||||
LeaderboardPanel leaderboardPanel = new LeaderboardPanel(sailingService,
|
||||
new AsyncActionsExecutor(), leaderboardSettings,
|
||||
/*preSelectedRace*/null,
|
||||
competitorSelectionProvider,
|
||||
null, leaderboard.name,
|
||||
errorReporter, stringMessages, userAgent, /*showRaceDetails*/false);
|
||||
leaderboardsTabPanel.add(leaderboardPanel, leaderboard.getDisplayName() + " " + stringMessages.leaderboard());
|
||||
if (showLeaderboard) {
|
||||
final CompetitorSelectionModel competitorSelectionProvider = new CompetitorSelectionModel(/* hasMultiSelection */ true);
|
||||
final LeaderboardSettings leaderboardSettings = LeaderboardSettingsFactory.getInstance().createNewDefaultSettings(null, null, null, /* autoExpandFirstRace */ false);
|
||||
sailingService.getLeaderboardsByEvent(eventDTO, new AsyncCallback<List<StrippedLeaderboardDTO>>() {
|
||||
@Override
|
||||
public void onSuccess(List<StrippedLeaderboardDTO> result) {
|
||||
leaderboardsTabPanel.clear();
|
||||
for (StrippedLeaderboardDTO leaderboard : result) {
|
||||
LeaderboardPanel leaderboardPanel = new LeaderboardPanel(sailingService,
|
||||
new AsyncActionsExecutor(), leaderboardSettings,
|
||||
/*preSelectedRace*/null,
|
||||
competitorSelectionProvider,
|
||||
null, leaderboard.name,
|
||||
errorReporter, stringMessages, userAgent, /*showRaceDetails*/false);
|
||||
leaderboardsTabPanel.add(leaderboardPanel, leaderboard.getDisplayName() + " " + stringMessages.leaderboard());
|
||||
}
|
||||
leaderboardsTabPanel.setVisible(true);
|
||||
leaderboardsTabPanel.selectTab(0);
|
||||
}
|
||||
leaderboardsTabPanel.selectTab(0);
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
leaderboardsTabPanel.clear();
|
||||
leaderboardsTabPanel.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
private HorizontalPanel getRefreshStartStopClockPanel() {
|
||||
@@ -227,6 +262,7 @@ public class RegattaOverviewPanel extends SimplePanel {
|
||||
refreshStartStopClockPanel.setStyleName(STYLE_REFRESH_STOP_TIME);
|
||||
refreshStartStopClockPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
|
||||
|
||||
refreshStartStopClockPanel.add(leaderboardCheckBox);
|
||||
refreshStartStopClockPanel.add(settingsButton);
|
||||
refreshStartStopClockPanel.add(refreshNowButton);
|
||||
refreshStartStopClockPanel.add(startStopUpdatingButton);
|
||||
|
||||
+97
-66
@@ -90,13 +90,13 @@ import com.sap.sailing.domain.base.impl.RegattaImpl;
|
||||
import com.sap.sailing.domain.base.impl.SeriesImpl;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.CountryCode;
|
||||
import com.sap.sailing.domain.common.DataImportProgress;
|
||||
import com.sap.sailing.domain.common.DetailType;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.LeaderboardNameConstants;
|
||||
import com.sap.sailing.domain.common.LeaderboardType;
|
||||
import com.sap.sailing.domain.common.LegType;
|
||||
import com.sap.sailing.domain.common.ManeuverType;
|
||||
import com.sap.sailing.domain.common.MasterDataImportObjectCreationCount;
|
||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.NoWindError;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
@@ -1539,9 +1539,11 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
final List<PositionDTO> startMarkPositionDTOs = getMarkPositionDTOs(dateAsTimePoint, trackedRace, firstWaypoint);
|
||||
result.startMarkPositions = startMarkPositionDTOs;
|
||||
result.startLineLengthInMeters = markPositionDTOsAndLineAdvantage.getLength().getMeters();
|
||||
result.startLineAngleToCombinedWind = markPositionDTOsAndLineAdvantage.getAbsoluteAngleDifferenceToTrueWind().getDegrees();
|
||||
Bearing absoluteAngleDifferenceToTrueWind = markPositionDTOsAndLineAdvantage.getAbsoluteAngleDifferenceToTrueWind();
|
||||
result.startLineAngleToCombinedWind = absoluteAngleDifferenceToTrueWind==null?null:absoluteAngleDifferenceToTrueWind.getDegrees();
|
||||
result.startLineAdvantageousSide = markPositionDTOsAndLineAdvantage.getAdvantageousSideWhileApproachingLine();
|
||||
result.startLineAdvantageInMeters = markPositionDTOsAndLineAdvantage.getAdvantage().getMeters();
|
||||
Distance advantage = markPositionDTOsAndLineAdvantage.getAdvantage();
|
||||
result.startLineAdvantageInMeters = advantage==null?null:advantage.getMeters();
|
||||
}
|
||||
}
|
||||
Waypoint lastWaypoint = course.getLastWaypoint();
|
||||
@@ -1551,9 +1553,11 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
final List<PositionDTO> finishMarkPositionDTOs = getMarkPositionDTOs(dateAsTimePoint, trackedRace, lastWaypoint);
|
||||
result.finishMarkPositions = finishMarkPositionDTOs;
|
||||
result.finishLineLengthInMeters = markPositionDTOsAndLineAdvantage.getLength().getMeters();
|
||||
result.finishLineAngleToCombinedWind = markPositionDTOsAndLineAdvantage.getAbsoluteAngleDifferenceToTrueWind().getDegrees();
|
||||
Bearing absoluteAngleDifferenceToTrueWind = markPositionDTOsAndLineAdvantage.getAbsoluteAngleDifferenceToTrueWind();
|
||||
result.finishLineAngleToCombinedWind = absoluteAngleDifferenceToTrueWind==null?null:absoluteAngleDifferenceToTrueWind.getDegrees();
|
||||
result.finishLineAdvantageousSide = markPositionDTOsAndLineAdvantage.getAdvantageousSideWhileApproachingLine();
|
||||
result.finishLineAdvantageInMeters = markPositionDTOsAndLineAdvantage.getAdvantage().getMeters();
|
||||
Distance advantage = markPositionDTOsAndLineAdvantage.getAdvantage();
|
||||
result.finishLineAdvantageInMeters = advantage==null?null:advantage.getMeters();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3444,67 +3448,90 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
}
|
||||
|
||||
@Override
|
||||
public MasterDataImportObjectCreationCount importMasterData(String urlAsString, String[] groupNames,
|
||||
boolean override, boolean compress) {
|
||||
long startTime = System.currentTimeMillis();
|
||||
Pair<String, Integer> hostnameAndPort = parseHostAndPort(urlAsString);
|
||||
String hostname = hostnameAndPort.getA();
|
||||
int port = hostnameAndPort.getB();
|
||||
String query;
|
||||
try {
|
||||
query = createLeaderboardQuery(groupNames, compress);
|
||||
} catch (UnsupportedEncodingException e1) {
|
||||
throw new RuntimeException(e1);
|
||||
}
|
||||
HttpURLConnection connection = null;
|
||||
public UUID importMasterData(final String urlAsString, final String[] groupNames, final boolean override,
|
||||
final boolean compress) {
|
||||
final UUID importOperationId = UUID.randomUUID();
|
||||
getService().createOrUpdateDataImportProgressWithReplication(importOperationId, 0.0, "Initializing", 0.0);
|
||||
// Create a progress indicator for as long as the server gets data from the other server.
|
||||
// As soon as the server starts the import operation, a progress object will be built on every server
|
||||
Runnable masterDataImportTask = new Runnable() {
|
||||
|
||||
URL serverAddress = null;
|
||||
InputStream inputStream = null;
|
||||
ObjectInputStream objectInputStream = null;
|
||||
try {
|
||||
String path = "/sailingserver/spi/v1/masterdata/leaderboardgroups";
|
||||
serverAddress = createUrl(hostname, port, path, query);
|
||||
//set up out communications stuff
|
||||
connection = null;
|
||||
//Set up the initial connection
|
||||
connection = (HttpURLConnection)serverAddress.openConnection();
|
||||
connection.setRequestMethod("GET");
|
||||
connection.setDoOutput(true);
|
||||
// Initial timeout needs to be big enough to allow the first parts of the response to reach this server
|
||||
connection.setReadTimeout(60000);
|
||||
connection.connect();
|
||||
|
||||
|
||||
if (compress) {
|
||||
InputStream timeoutExtendingInputStream = new TimeoutExtendingInputStream(connection.getInputStream(),
|
||||
connection);
|
||||
inputStream = new GZIPInputStream(timeoutExtendingInputStream);
|
||||
} else {
|
||||
inputStream = new TimeoutExtendingInputStream(connection.getInputStream(), connection);
|
||||
}
|
||||
|
||||
objectInputStream = getService().getBaseDomainFactory().createObjectInputStreamResolvingAgainstThisFactory(
|
||||
inputStream);
|
||||
TopLevelMasterData topLevelMasterData = (TopLevelMasterData) objectInputStream.readObject();
|
||||
return importFromHttpResponse(topLevelMasterData, override);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
// close the connection, set all objects to null
|
||||
connection.disconnect();
|
||||
connection = null;
|
||||
long timeToImport = System.currentTimeMillis() - startTime;
|
||||
logger.info(String.format("Took %s ms overall to import master data.", timeToImport));
|
||||
try {
|
||||
if (inputStream != null) {
|
||||
inputStream.close();
|
||||
@Override
|
||||
public void run() {
|
||||
long startTime = System.currentTimeMillis();
|
||||
getService().createOrUpdateDataImportProgressWithReplication(importOperationId, 0.01,
|
||||
"Setting up connection", 0.5);
|
||||
Pair<String, Integer> hostnameAndPort = parseHostAndPort(urlAsString);
|
||||
String hostname = hostnameAndPort.getA();
|
||||
int port = hostnameAndPort.getB();
|
||||
String query;
|
||||
try {
|
||||
query = createLeaderboardQuery(groupNames, compress);
|
||||
} catch (UnsupportedEncodingException e1) {
|
||||
throw new RuntimeException(e1);
|
||||
}
|
||||
if (objectInputStream != null) {
|
||||
objectInputStream.close();
|
||||
HttpURLConnection connection = null;
|
||||
|
||||
URL serverAddress = null;
|
||||
InputStream inputStream = null;
|
||||
ObjectInputStream objectInputStream = null;
|
||||
try {
|
||||
String path = "/sailingserver/spi/v1/masterdata/leaderboardgroups";
|
||||
serverAddress = createUrl(hostname, port, path, query);
|
||||
// set up out communications stuff
|
||||
connection = null;
|
||||
// Set up the initial connection
|
||||
connection = (HttpURLConnection) serverAddress.openConnection();
|
||||
connection.setRequestMethod("GET");
|
||||
connection.setDoOutput(true);
|
||||
// Initial timeout needs to be big enough to allow the first parts of the response to reach this
|
||||
// server
|
||||
connection.setReadTimeout(60000);
|
||||
connection.connect();
|
||||
getService().createOrUpdateDataImportProgressWithReplication(importOperationId, 0.02, "Connecting",
|
||||
0.5);
|
||||
|
||||
if (compress) {
|
||||
InputStream timeoutExtendingInputStream = new TimeoutExtendingInputStream(
|
||||
connection.getInputStream(), connection);
|
||||
inputStream = new GZIPInputStream(timeoutExtendingInputStream);
|
||||
} else {
|
||||
inputStream = new TimeoutExtendingInputStream(connection.getInputStream(), connection);
|
||||
}
|
||||
|
||||
objectInputStream = getService().getBaseDomainFactory()
|
||||
.createObjectInputStreamResolvingAgainstThisFactory(inputStream);
|
||||
getService().createOrUpdateDataImportProgressWithReplication(importOperationId, 0.03,
|
||||
"Reading Data", 0.5);
|
||||
TopLevelMasterData topLevelMasterData = (TopLevelMasterData) objectInputStream.readObject();
|
||||
|
||||
getService().createOrUpdateDataImportProgressWithReplication(importOperationId, 0.3,
|
||||
"Data-Transfer Complete, Initializing Import Operation", 0.5);
|
||||
importFromHttpResponse(topLevelMasterData, importOperationId, override);
|
||||
} catch (Exception e) {
|
||||
getService().setDataImportFailedWithReplication(importOperationId, e.getMessage());
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
// close the connection, set all objects to null
|
||||
connection.disconnect();
|
||||
connection = null;
|
||||
long timeToImport = System.currentTimeMillis() - startTime;
|
||||
logger.info(String.format("Took %s ms overall to import master data.", timeToImport));
|
||||
try {
|
||||
if (inputStream != null) {
|
||||
inputStream.close();
|
||||
}
|
||||
if (objectInputStream != null) {
|
||||
objectInputStream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
};
|
||||
executor.execute(masterDataImportTask);
|
||||
|
||||
return importOperationId;
|
||||
}
|
||||
|
||||
private URL createUrl(String host, Integer port, String path, String query) throws Exception {
|
||||
@@ -3517,10 +3544,14 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
return url;
|
||||
}
|
||||
|
||||
protected MasterDataImportObjectCreationCount importFromHttpResponse(TopLevelMasterData topLevelMasterData,
|
||||
boolean override) {
|
||||
MasterDataImporter importer = new MasterDataImporter(baseDomainFactory, getService());
|
||||
return importer.importMasterData(topLevelMasterData, override);
|
||||
protected void importFromHttpResponse(final TopLevelMasterData topLevelMasterData, final UUID importOperationId,
|
||||
final boolean override) {
|
||||
final MasterDataImporter importer = new MasterDataImporter(baseDomainFactory, getService());
|
||||
importer.importMasterData(topLevelMasterData, importOperationId, override);
|
||||
}
|
||||
|
||||
public DataImportProgress getImportOperationProgress(UUID id) {
|
||||
return getService().getDataImportLock().getProgress(id);
|
||||
}
|
||||
|
||||
private String createLeaderboardQuery(String[] groupNames, boolean compress) throws UnsupportedEncodingException {
|
||||
|
||||
+16
-23
@@ -4,6 +4,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.canvas.dom.client.Context2d;
|
||||
import com.sap.sailing.domain.common.Color;
|
||||
import com.sap.sailing.domain.common.LegType;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
|
||||
@@ -18,19 +19,19 @@ import com.sap.sailing.domain.common.Tack;
|
||||
*
|
||||
*/
|
||||
public abstract class BoatClassVectorGraphics {
|
||||
protected double overallLengthInPx;
|
||||
protected double hullLengthInPx;
|
||||
protected double beamInPx;
|
||||
private static final String SAIL_FILLCOLOR = "#555555";
|
||||
private static final String SAIL_STROKECOLOR = "#000000";
|
||||
|
||||
/** the minimal length of the hull in pixel when the boat is drawn */
|
||||
private static final double minHullLengthInPx = 25;
|
||||
|
||||
private final double overallLengthInPx;
|
||||
private final double hullLengthInPx;
|
||||
private final double beamInPx;
|
||||
|
||||
private final String mainBoatClassName;
|
||||
private final List<String> compatibleBoatClassNames;
|
||||
|
||||
protected final String SAIL_FILLCOLOR = "#555555";
|
||||
protected final String SAIL_STROKECOLOR = "#000000";
|
||||
|
||||
/** the minimal length of the hull in pixel when the boat is drawn */
|
||||
protected double minHullLengthInPx = 25;
|
||||
|
||||
|
||||
BoatClassVectorGraphics(String mainBoatClassName, double overallLengthInPx, double beamInPx, double hullLengthInPx) {
|
||||
this.mainBoatClassName = mainBoatClassName;
|
||||
this.overallLengthInPx = overallLengthInPx;
|
||||
@@ -103,23 +104,15 @@ public abstract class BoatClassVectorGraphics {
|
||||
}
|
||||
}
|
||||
|
||||
public void drawBoatToCanvas(Context2d ctx, LegType legType, Tack tack, boolean isSelected,
|
||||
double width, double height, double angleInDegrees, double scaleFactor, String color) {
|
||||
|
||||
public void drawBoatToCanvas(Context2d ctx, LegType legType, Tack tack, boolean isSelected, double width,
|
||||
double height, double scaleFactor, Color color) {
|
||||
ctx.save();
|
||||
|
||||
double angleInRadians = angleInDegrees / 180.0 * Math.PI;
|
||||
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
ctx.translate(width / 2.0, height / 2.0);
|
||||
ctx.rotate(angleInRadians);
|
||||
ctx.scale(scaleFactor, scaleFactor);
|
||||
ctx.translate(-hullLengthInPx / 2.0,- beamInPx / 2.0);
|
||||
|
||||
drawBoat(ctx, isSelected, color);
|
||||
ctx.translate(-hullLengthInPx / 2.0, -beamInPx / 2.0);
|
||||
drawBoat(ctx, isSelected, color.getAsHtml());
|
||||
drawSails(ctx, legType, tack);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
|
||||
+48
-5
@@ -275,23 +275,35 @@ public abstract class CanvasOverlayV3 {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setCanvasPositionTransition(long durationInMilliseconds) {
|
||||
public void setCanvasPositionAndRotationTransition(long durationInMilliseconds) {
|
||||
if (durationInMilliseconds != transitionTimeInMilliseconds) {
|
||||
setProperty(canvas.getElement().getStyle(), "transition", "left "+durationInMilliseconds+"ms linear, top "+durationInMilliseconds+"ms linear");
|
||||
for (String browserTypePrefix : getBrowserTypePrefixes()) {
|
||||
StringBuilder transformPropertyList = new StringBuilder();
|
||||
transformPropertyList.append("left ");
|
||||
transformPropertyList.append(durationInMilliseconds);
|
||||
transformPropertyList.append("ms linear, top ");
|
||||
transformPropertyList.append(durationInMilliseconds);
|
||||
transformPropertyList.append("ms linear, ");
|
||||
transformPropertyList.append(getBrowserSpecificDashedPropertyName(browserTypePrefix, "transform"));
|
||||
transformPropertyList.append(' ');
|
||||
transformPropertyList.append(durationInMilliseconds);
|
||||
transformPropertyList.append("ms linear");
|
||||
canvas.getElement().getStyle().setProperty(getBrowserSpecificPropertyName(browserTypePrefix, "transition"), transformPropertyList.toString());
|
||||
}
|
||||
transitionTimeInMilliseconds = durationInMilliseconds;
|
||||
}
|
||||
}
|
||||
|
||||
public void removeCanvasPositionTransition() {
|
||||
public void removeCanvasPositionAndRotationTransition() {
|
||||
if (transitionTimeInMilliseconds != -1) {
|
||||
setProperty(canvas.getElement().getStyle(), "transition", "none");
|
||||
transitionTimeInMilliseconds = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void setProperty(Style style, String baseCamelCasePropertyName, String value) {
|
||||
for (String browserTypePrefix : getBrowserTypePrefixes()) {
|
||||
style.setProperty(getBrowserSpecificPropertyName(browserTypePrefix, baseCamelCasePropertyName), value);
|
||||
style.setProperty(getBrowserSpecificPropertyName(browserTypePrefix, baseCamelCasePropertyName), value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,6 +314,32 @@ public abstract class CanvasOverlayV3 {
|
||||
private String[] getBrowserTypePrefixes() {
|
||||
return new String[] { "", /* Firefox */ "moz", /* IE */ "ms", /* Opera */ "o", /* Chrome and Mobile */ "webkit" };
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts something like "transformOrigin" to "-<code>browserType</code>-transform-origin"
|
||||
*
|
||||
* @param browserType
|
||||
* a browser type string as received from {@link #getBrowserTypePrefixes()}. If empty or null, the
|
||||
* original property name is returned unchanged
|
||||
* @param camelCaseString
|
||||
* the original camel-cased property name, such as "transformOrigin"
|
||||
*/
|
||||
private String getBrowserSpecificDashedPropertyName(String browserType, String camelCaseString) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
if (browserType != null && !browserType.isEmpty()) {
|
||||
result.append('-');
|
||||
result.append(browserType);
|
||||
result.append('-');
|
||||
}
|
||||
for (int i=0; i<camelCaseString.length(); i++) {
|
||||
final char c = camelCaseString.charAt(i);
|
||||
if (Character.isUpperCase(c)) {
|
||||
result.append('-');
|
||||
}
|
||||
result.append(Character.toLowerCase(c));
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private String getBrowserSpecificPropertyName(String browserType, String basePropertyName) {
|
||||
final String result;
|
||||
@@ -318,6 +356,11 @@ public abstract class CanvasOverlayV3 {
|
||||
canvas.getElement().getStyle().setTop(y, Unit.PX);
|
||||
}
|
||||
|
||||
protected void setCanvasRotation(double rotationInDegrees) {
|
||||
setProperty(canvas.getElement().getStyle(), "transformOrigin", "50% 50%");
|
||||
setProperty(canvas.getElement().getStyle(), "transform", "rotate("+rotationInDegrees+"deg");
|
||||
}
|
||||
|
||||
protected double calculateRadiusOfBoundingBox(MapCanvasProjection projection, LatLng centerPosition, double lengthInMeter) {
|
||||
Position centerPos = new DegreePosition(centerPosition.getLatitude(), centerPosition.getLongitude());
|
||||
Position translateRhumbX = centerPos.translateRhumb(new DegreeBearingImpl(90), new MeterDistance(lengthInMeter));
|
||||
|
||||
+2
-2
@@ -30,14 +30,14 @@ public class ReplayPathCanvasOverlay extends PathCanvasOverlay {
|
||||
}
|
||||
*/
|
||||
@Override
|
||||
public void timeChanged(final Date date) {
|
||||
public void timeChanged(final Date newTime, Date oldTime) {
|
||||
|
||||
canvas.getContext2d().clearRect(0/* canvas.getAbsoluteLeft() */, 0/* canvas.getAbsoluteTop() */,
|
||||
canvas.getCoordinateSpaceWidth(), canvas.getCoordinateSpaceHeight());
|
||||
|
||||
windDTOToDraw = new ArrayList<SimulatorWindDTO>();
|
||||
for (final SimulatorWindDTO windDTO : windFieldDTO.getMatrix()) {
|
||||
if (windDTO.timepoint <= date.getTime()) {
|
||||
if (windDTO.timepoint <= newTime.getTime()) {
|
||||
windDTOToDraw.add(windDTO);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -805,7 +805,7 @@ public class SimulatorMap extends AbsolutePanel implements RequiresDataInitializ
|
||||
}
|
||||
|
||||
@Override
|
||||
public void timeChanged(Date date) {
|
||||
public void timeChanged(Date newTime, Date oldTime) {
|
||||
if (shallStop()) {
|
||||
LOGGER.info("Stopping the timer");
|
||||
timer.stop();
|
||||
|
||||
+4
-4
@@ -124,7 +124,7 @@ public class WindFieldCanvasOverlay extends FullCanvasOverlay implements TimeLis
|
||||
|
||||
protected void drawWindField() {
|
||||
if (timer != null) {
|
||||
timeChanged(timer.getTime());
|
||||
timeChanged(timer.getTime(), null);
|
||||
} else {
|
||||
drawWindField(windFieldDTO.getMatrix());
|
||||
}
|
||||
@@ -158,17 +158,17 @@ public class WindFieldCanvasOverlay extends FullCanvasOverlay implements TimeLis
|
||||
}
|
||||
|
||||
@Override
|
||||
public void timeChanged(final Date date) {
|
||||
public void timeChanged(final Date newTime, Date oldTime) {
|
||||
|
||||
List<SimulatorWindDTO> windDTOToDraw = new ArrayList<SimulatorWindDTO>();
|
||||
|
||||
final SortedMap<Long, List<SimulatorWindDTO>> headMap = (timePointWindDTOMap.headMap(date.getTime()+1));
|
||||
final SortedMap<Long, List<SimulatorWindDTO>> headMap = (timePointWindDTOMap.headMap(newTime.getTime()+1));
|
||||
|
||||
if (!headMap.isEmpty()) {
|
||||
windDTOToDraw = headMap.get(headMap.lastKey());
|
||||
}
|
||||
logger.info("In WindFieldCanvasOverlay.drawWindField drawing " + windDTOToDraw.size() + " points" + " @ "
|
||||
+ date);
|
||||
+ newTime);
|
||||
|
||||
drawWindField(windDTOToDraw);
|
||||
|
||||
|
||||
+4
-4
@@ -158,15 +158,15 @@ public class WindGridCanvasOverlay extends FullCanvasOverlay implements TimeList
|
||||
}
|
||||
|
||||
@Override
|
||||
public void timeChanged(final Date date) {
|
||||
public void timeChanged(final Date newTime, Date oldTime) {
|
||||
List<SimulatorWindDTO> windDTOToDraw = new ArrayList<SimulatorWindDTO>();
|
||||
|
||||
final SortedMap<Long, List<SimulatorWindDTO>> headMap = (timePointWindDTOMap.headMap(date.getTime() + 1));
|
||||
final SortedMap<Long, List<SimulatorWindDTO>> headMap = (timePointWindDTOMap.headMap(newTime.getTime() + 1));
|
||||
|
||||
if (!headMap.isEmpty()) {
|
||||
windDTOToDraw = headMap.get(headMap.lastKey());
|
||||
}
|
||||
logger.info("In WindGridCanvasOverlay.timeChanged drawing " + windDTOToDraw.size() + " points" + " @ " + date);
|
||||
logger.info("In WindGridCanvasOverlay.timeChanged drawing " + windDTOToDraw.size() + " points" + " @ " + newTime);
|
||||
|
||||
drawWindGrid(windDTOToDraw);
|
||||
}
|
||||
@@ -200,7 +200,7 @@ public class WindGridCanvasOverlay extends FullCanvasOverlay implements TimeList
|
||||
protected void drawWindGrid() {
|
||||
|
||||
if (timer != null) {
|
||||
timeChanged(timer.getTime());
|
||||
timeChanged(timer.getTime(), null);
|
||||
|
||||
} else {
|
||||
drawWindGrid(windFieldDTO.getMatrix());
|
||||
|
||||
+4
-4
@@ -45,7 +45,7 @@ public class WindLineCanvasOverlay extends FullCanvasOverlay implements TimeList
|
||||
}
|
||||
|
||||
@Override
|
||||
public void timeChanged(final Date date) {
|
||||
public void timeChanged(final Date newTime, Date oldTime) {
|
||||
final Map<PositionDTO, SortedMap<Long, List<PositionDTO>>> windLinesMap = windLinesDTO.getWindLinesMap();
|
||||
|
||||
if (windLinesMap == null) {
|
||||
@@ -61,13 +61,13 @@ public class WindLineCanvasOverlay extends FullCanvasOverlay implements TimeList
|
||||
for (final Entry<PositionDTO, SortedMap<Long, List<PositionDTO>>> entry : windLinesMap.entrySet()) {
|
||||
List<PositionDTO> positionDTOToDraw = new ArrayList<PositionDTO>();
|
||||
|
||||
final SortedMap<Long, List<PositionDTO>> headMap = (entry.getValue().headMap(date.getTime() + 1));
|
||||
final SortedMap<Long, List<PositionDTO>> headMap = (entry.getValue().headMap(newTime.getTime() + 1));
|
||||
|
||||
if (!headMap.isEmpty()) {
|
||||
positionDTOToDraw = headMap.get(headMap.lastKey());
|
||||
}
|
||||
logger.info("In WindLineCanvasOverlay.drawWindField drawing " + positionDTOToDraw.size() + " points"
|
||||
+ " @ " + date);
|
||||
+ " @ " + newTime);
|
||||
|
||||
drawWindLine(positionDTOToDraw, ++index);
|
||||
}
|
||||
@@ -140,7 +140,7 @@ public class WindLineCanvasOverlay extends FullCanvasOverlay implements TimeList
|
||||
|
||||
protected void drawWindLine() {
|
||||
if (timer != null) {
|
||||
timeChanged(timer.getTime());
|
||||
timeChanged(timer.getTime(), null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -120,7 +120,7 @@ public class WindStreamletsCanvasOverlay extends FullCanvasOverlay implements Ti
|
||||
|
||||
protected void drawWindField() {
|
||||
if (timer != null) {
|
||||
timeChanged(timer.getTime());
|
||||
timeChanged(timer.getTime(), null);
|
||||
} else {
|
||||
drawWindField(windFieldDTO.getMatrix());
|
||||
}
|
||||
@@ -235,17 +235,17 @@ public class WindStreamletsCanvasOverlay extends FullCanvasOverlay implements Ti
|
||||
}
|
||||
|
||||
@Override
|
||||
public void timeChanged(final Date date) {
|
||||
public void timeChanged(final Date newTime, Date oldTime) {
|
||||
|
||||
List<SimulatorWindDTO> windDTOToDraw = new ArrayList<SimulatorWindDTO>();
|
||||
|
||||
final SortedMap<Long, List<SimulatorWindDTO>> headMap = (timePointWindDTOMap.headMap(date.getTime()+1));
|
||||
final SortedMap<Long, List<SimulatorWindDTO>> headMap = (timePointWindDTOMap.headMap(newTime.getTime()+1));
|
||||
|
||||
if (!headMap.isEmpty()) {
|
||||
windDTOToDraw = headMap.get(headMap.lastKey());
|
||||
}
|
||||
logger.info("In WindFieldCanvasOverlay.drawWindField drawing " + windDTOToDraw.size() + " points" + " @ "
|
||||
+ date);
|
||||
+ newTime);
|
||||
|
||||
drawWindField(windDTOToDraw);
|
||||
|
||||
|
||||
+4
@@ -36,6 +36,10 @@
|
||||
<inherits name='com.github.gwtbootstrap.datetimepicker.DatetimepickerNoResources' />
|
||||
<stylesheet src="../AdminConsoleDateTimePicker.css" />
|
||||
|
||||
<!-- Fancy Progressbar (without the rest of Bootstrap!) -->
|
||||
<!-- GWT-Bootstrap License: Apache License, Version 2.0 -->
|
||||
<stylesheet src="../AdminConsoleProgressBar.css" />
|
||||
|
||||
<super-source path="jre" />
|
||||
|
||||
<!-- Specify the app entry point class. -->
|
||||
|
||||
@@ -17,6 +17,7 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
com.mongodb.driver;bundle-version="2.6.2",
|
||||
org.junit4;bundle-version="4.8.2",
|
||||
com.sap.sailing.domain.test,
|
||||
org.hamcrest;bundle-version="1.1.0"
|
||||
org.hamcrest;bundle-version="1.1.0",
|
||||
org.mockito.mockito-core;bundle-version="1.9.5"
|
||||
Import-Package: org.json.simple
|
||||
Export-Package: com.sap.sailing.server.impl
|
||||
+216
@@ -0,0 +1,216 @@
|
||||
package com.sap.sailing.server.masterdata;
|
||||
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.base.DomainFactory;
|
||||
import com.sap.sailing.domain.base.Event;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.common.MasterDataImportObjectCreationCount;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack.MimeType;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sailing.domain.masterdataimport.TopLevelMasterData;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
|
||||
public class MasterDataImporterMediaTest {
|
||||
|
||||
private static final boolean NO_OVERRIDE = false;
|
||||
private static final boolean OVERRIDE = true;
|
||||
|
||||
private MasterDataImporter importer;
|
||||
private RacingEventService racingEventService;
|
||||
private DomainFactory baseDomainFactory = mock(DomainFactory.class);
|
||||
private Set<LeaderboardGroup> groupsToExport = Collections.emptySet();
|
||||
private Iterable<Event> allEvents = Collections.emptyList();
|
||||
private Map<String, Regatta> regattaForRaceIdString = Collections.emptyMap();
|
||||
private Collection<MediaTrack> existingMediaTracks;
|
||||
private TopLevelMasterData topLevelMasterData ;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
existingMediaTracks = new ArrayList<MediaTrack>();
|
||||
racingEventService = mock(RacingEventService.class);
|
||||
when(racingEventService.getAllMediaTracks()).thenReturn(existingMediaTracks);
|
||||
importer = new MasterDataImporter(baseDomainFactory, racingEventService);
|
||||
}
|
||||
|
||||
private TopLevelMasterData createMasterData(MediaTrack... mediaTracksToImport) {
|
||||
return topLevelMasterData = new TopLevelMasterData(groupsToExport, allEvents, regattaForRaceIdString, Arrays.asList(mediaTracksToImport));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyImportList_NoOverride() throws Exception {
|
||||
createMasterData();
|
||||
MasterDataImportObjectCreationCount importResult = importer.importMasterData(topLevelMasterData,
|
||||
UUID.randomUUID(), NO_OVERRIDE);
|
||||
assertNull(importResult); //according to what the mocked racing event service returns
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyImportList_WithOverride() throws Exception {
|
||||
createMasterData();
|
||||
MasterDataImportObjectCreationCount importResult = importer.importMasterData(topLevelMasterData,
|
||||
UUID.randomUUID(), OVERRIDE);
|
||||
assertNull(importResult); //according to what the mocked racing event service returns
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImportOneTrackToEmptyTarget_WithOverride() throws Exception {
|
||||
MediaTrack mediaTrackToImport = new MediaTrack("dbId", "title", "url", new Date(), 0, MimeType.mp3);
|
||||
createMasterData(mediaTrackToImport);
|
||||
importer.importMasterData(topLevelMasterData, UUID.randomUUID(), OVERRIDE);
|
||||
verify(racingEventService).mediaTrackAdded(mediaTrackToImport);
|
||||
verify(racingEventService, never()).mediaTrackDeleted(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackTitleChanged(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackUrlChanged(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackStartTimeChanged(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackDurationChanged(any(MediaTrack.class));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImportOneTrackToSameTarget_WithOverride() throws Exception {
|
||||
MediaTrack existingMediaTrack = new MediaTrack("dbId", "title", "url", new Date(), 0, MimeType.mp3);
|
||||
existingMediaTracks.add(existingMediaTrack);
|
||||
MediaTrack mediaTrackToImport = new MediaTrack(existingMediaTrack.dbId, existingMediaTrack.title, existingMediaTrack.url, existingMediaTrack.startTime, existingMediaTrack.durationInMillis, existingMediaTrack.mimeType);
|
||||
createMasterData(mediaTrackToImport);
|
||||
importer.importMasterData(topLevelMasterData, UUID.randomUUID(), OVERRIDE);
|
||||
verify(racingEventService, never()).mediaTrackAdded(mediaTrackToImport);
|
||||
verify(racingEventService, never()).mediaTrackDeleted(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackTitleChanged(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackUrlChanged(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackStartTimeChanged(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackDurationChanged(any(MediaTrack.class));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImportOneTrackToExistingOtherTrack_WithOverride() throws Exception {
|
||||
MediaTrack existingMediaTrack = new MediaTrack("dbId", "title", "url", new Date(), 0, MimeType.mp3);
|
||||
existingMediaTracks.add(existingMediaTrack);
|
||||
MediaTrack mediaTrackToImport = new MediaTrack("dbId2", existingMediaTrack.title, existingMediaTrack.url, existingMediaTrack.startTime, existingMediaTrack.durationInMillis, existingMediaTrack.mimeType);
|
||||
createMasterData(mediaTrackToImport);
|
||||
importer.importMasterData(topLevelMasterData, UUID.randomUUID(), OVERRIDE);
|
||||
verify(racingEventService).mediaTrackAdded(mediaTrackToImport);
|
||||
verify(racingEventService, never()).mediaTrackDeleted(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackTitleChanged(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackUrlChanged(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackStartTimeChanged(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackDurationChanged(any(MediaTrack.class));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImportOneTrackToSameTargetWithChangedTitle_WithOverride() throws Exception {
|
||||
MediaTrack existingMediaTrack = new MediaTrack("dbId", "title", "url", new Date(), 0, MimeType.mp3);
|
||||
existingMediaTracks.add(existingMediaTrack);
|
||||
MediaTrack mediaTrackToImport = new MediaTrack(existingMediaTrack.dbId, existingMediaTrack.title + "x", existingMediaTrack.url, existingMediaTrack.startTime, existingMediaTrack.durationInMillis, existingMediaTrack.mimeType);
|
||||
createMasterData(mediaTrackToImport);
|
||||
importer.importMasterData(topLevelMasterData, UUID.randomUUID(), OVERRIDE);
|
||||
verify(racingEventService, never()).mediaTrackAdded(mediaTrackToImport);
|
||||
verify(racingEventService, never()).mediaTrackDeleted(any(MediaTrack.class));
|
||||
verify(racingEventService).mediaTrackTitleChanged(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackUrlChanged(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackStartTimeChanged(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackDurationChanged(any(MediaTrack.class));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImportOneTrackWithNullTitleToSameTargetWithTitle_WithOverride() throws Exception {
|
||||
MediaTrack existingMediaTrack = new MediaTrack("dbId", "title", "url", new Date(), 0, MimeType.mp3);
|
||||
existingMediaTracks.add(existingMediaTrack);
|
||||
MediaTrack mediaTrackToImport = new MediaTrack(existingMediaTrack.dbId, null, existingMediaTrack.url, existingMediaTrack.startTime, existingMediaTrack.durationInMillis, existingMediaTrack.mimeType);
|
||||
createMasterData(mediaTrackToImport);
|
||||
importer.importMasterData(topLevelMasterData, UUID.randomUUID(), OVERRIDE);
|
||||
verify(racingEventService, never()).mediaTrackAdded(mediaTrackToImport);
|
||||
verify(racingEventService, never()).mediaTrackDeleted(any(MediaTrack.class));
|
||||
verify(racingEventService).mediaTrackTitleChanged(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackUrlChanged(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackStartTimeChanged(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackDurationChanged(any(MediaTrack.class));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImportOneTrackToSameTargetWithChangedTitle_NoOverride() throws Exception {
|
||||
MediaTrack existingMediaTrack = new MediaTrack("dbId", "title", "url", new Date(), 0, MimeType.mp3);
|
||||
existingMediaTracks.add(existingMediaTrack);
|
||||
MediaTrack mediaTrackToImport = new MediaTrack(existingMediaTrack.dbId, existingMediaTrack.title + "x", existingMediaTrack.url, existingMediaTrack.startTime, existingMediaTrack.durationInMillis, existingMediaTrack.mimeType);
|
||||
createMasterData(mediaTrackToImport);
|
||||
importer.importMasterData(topLevelMasterData, UUID.randomUUID(), NO_OVERRIDE);
|
||||
verify(racingEventService, never()).mediaTrackAdded(mediaTrackToImport);
|
||||
verify(racingEventService, never()).mediaTrackDeleted(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackTitleChanged(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackUrlChanged(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackStartTimeChanged(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackDurationChanged(any(MediaTrack.class));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImportOneTrackToSameTargetWithChangedUrl_WithOverride() throws Exception {
|
||||
MediaTrack existingMediaTrack = new MediaTrack("dbId", "title", "url", new Date(), 0, MimeType.mp3);
|
||||
existingMediaTracks.add(existingMediaTrack);
|
||||
MediaTrack mediaTrackToImport = new MediaTrack(existingMediaTrack.dbId, existingMediaTrack.title, existingMediaTrack.url + "x", existingMediaTrack.startTime, existingMediaTrack.durationInMillis, existingMediaTrack.mimeType);
|
||||
createMasterData(mediaTrackToImport);
|
||||
importer.importMasterData(topLevelMasterData, UUID.randomUUID(), OVERRIDE);
|
||||
verify(racingEventService, never()).mediaTrackAdded(mediaTrackToImport);
|
||||
verify(racingEventService, never()).mediaTrackDeleted(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackTitleChanged(any(MediaTrack.class));
|
||||
verify(racingEventService).mediaTrackUrlChanged(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackStartTimeChanged(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackDurationChanged(any(MediaTrack.class));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImportOneTrackToSameTargetWithChangedStarttime_WithOverride() throws Exception {
|
||||
MediaTrack existingMediaTrack = new MediaTrack("dbId", "title", "url", new Date(), 0, MimeType.mp3);
|
||||
existingMediaTracks.add(existingMediaTrack);
|
||||
MediaTrack mediaTrackToImport = new MediaTrack(existingMediaTrack.dbId, existingMediaTrack.title, existingMediaTrack.url, new Date(existingMediaTrack.startTime.getTime() + 1), existingMediaTrack.durationInMillis, existingMediaTrack.mimeType);
|
||||
createMasterData(mediaTrackToImport);
|
||||
importer.importMasterData(topLevelMasterData, UUID.randomUUID(), OVERRIDE);
|
||||
verify(racingEventService, never()).mediaTrackAdded(mediaTrackToImport);
|
||||
verify(racingEventService, never()).mediaTrackDeleted(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackTitleChanged(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackUrlChanged(any(MediaTrack.class));
|
||||
verify(racingEventService).mediaTrackStartTimeChanged(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackDurationChanged(any(MediaTrack.class));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImportOneTrackToSameTargetWithChangedDuration_WithOverride() throws Exception {
|
||||
MediaTrack existingMediaTrack = new MediaTrack("dbId", "title", "url", new Date(), 0, MimeType.mp3);
|
||||
existingMediaTracks.add(existingMediaTrack);
|
||||
MediaTrack mediaTrackToImport = new MediaTrack(existingMediaTrack.dbId, existingMediaTrack.title, existingMediaTrack.url, existingMediaTrack.startTime, existingMediaTrack.durationInMillis + 1, existingMediaTrack.mimeType);
|
||||
createMasterData(mediaTrackToImport);
|
||||
importer.importMasterData(topLevelMasterData, UUID.randomUUID(), OVERRIDE);
|
||||
verify(racingEventService, never()).mediaTrackAdded(mediaTrackToImport);
|
||||
verify(racingEventService, never()).mediaTrackDeleted(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackTitleChanged(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackUrlChanged(any(MediaTrack.class));
|
||||
verify(racingEventService, never()).mediaTrackStartTimeChanged(any(MediaTrack.class));
|
||||
verify(racingEventService).mediaTrackDurationChanged(any(MediaTrack.class));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+53
-24
@@ -60,6 +60,7 @@ import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.DataImportProgressImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
@@ -283,6 +284,7 @@ public class MasterDataImportTest {
|
||||
ObjectInputStream ois = null;
|
||||
TopLevelMasterData deserializedMasterData;
|
||||
DomainFactory domainFactory;
|
||||
UUID randomUUID = UUID.randomUUID();
|
||||
try {
|
||||
masterdata.setMasterDataExportFlagOnRaceColumns(true);
|
||||
oos.writeObject(masterdata);
|
||||
@@ -292,7 +294,7 @@ public class MasterDataImportTest {
|
||||
// Delete all data above from the database, to allow recreating all of it on target server
|
||||
deleteCreatedDataFromDatabase();
|
||||
// Import in new service
|
||||
destService = new RacingEventServiceImplMock();
|
||||
destService = new RacingEventServiceImplMock(new DataImportProgressImpl(randomUUID));
|
||||
domainFactory = destService.getBaseDomainFactory();
|
||||
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
||||
|
||||
@@ -307,7 +309,9 @@ public class MasterDataImportTest {
|
||||
|
||||
MasterDataImporter importer = new MasterDataImporter(domainFactory, destService);
|
||||
|
||||
MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData, false);
|
||||
|
||||
MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData,
|
||||
randomUUID, false);
|
||||
|
||||
Assert.assertNotNull(creationCount);
|
||||
Event eventOnTarget = destService.getEvent(eventUUID);
|
||||
@@ -474,6 +478,7 @@ public class MasterDataImportTest {
|
||||
ObjectInputStream ois = null;
|
||||
TopLevelMasterData deserializedMasterData;
|
||||
DomainFactory domainFactory;
|
||||
UUID randomUUID = UUID.randomUUID();
|
||||
try {
|
||||
masterdata.setMasterDataExportFlagOnRaceColumns(true);
|
||||
oos.writeObject(masterdata);
|
||||
@@ -482,7 +487,7 @@ public class MasterDataImportTest {
|
||||
// Delete all data above from the database, to allow recreating all of it on target server
|
||||
deleteCreatedDataFromDatabase();
|
||||
// Import in new service
|
||||
destService = new RacingEventServiceImplMock();
|
||||
destService = new RacingEventServiceImplMock(new DataImportProgressImpl(randomUUID));
|
||||
domainFactory = destService.getBaseDomainFactory();
|
||||
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
||||
|
||||
@@ -494,7 +499,9 @@ public class MasterDataImportTest {
|
||||
ois.close();
|
||||
}
|
||||
MasterDataImporter importer = new MasterDataImporter(domainFactory, destService);
|
||||
MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData, false);
|
||||
|
||||
MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData,
|
||||
randomUUID, false);
|
||||
|
||||
Assert.assertNotNull(creationCount);
|
||||
Event eventOnTarget = destService.getEvent(eventUUID);
|
||||
@@ -610,6 +617,7 @@ public class MasterDataImportTest {
|
||||
ObjectInputStream ois = null;
|
||||
TopLevelMasterData deserializedMasterData;
|
||||
DomainFactory domainFactory;
|
||||
UUID randomUUID = UUID.randomUUID();
|
||||
try {
|
||||
masterdata.setMasterDataExportFlagOnRaceColumns(true);
|
||||
oos.writeObject(masterdata);
|
||||
@@ -618,7 +626,7 @@ public class MasterDataImportTest {
|
||||
// Delete all data above from the database, to allow recreating all of it on target server
|
||||
deleteCreatedDataFromDatabase();
|
||||
// Import in new service
|
||||
destService = new RacingEventServiceImplMock();
|
||||
destService = new RacingEventServiceImplMock(new DataImportProgressImpl(randomUUID));
|
||||
domainFactory = destService.getBaseDomainFactory();
|
||||
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
||||
|
||||
@@ -630,7 +638,9 @@ public class MasterDataImportTest {
|
||||
ois.close();
|
||||
}
|
||||
MasterDataImporter importer = new MasterDataImporter(domainFactory, destService);
|
||||
MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData, false);
|
||||
|
||||
MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData,
|
||||
randomUUID, false);
|
||||
|
||||
Assert.assertNotNull(creationCount);
|
||||
Event eventOnTarget = destService.getEvent(eventUUID);
|
||||
@@ -762,6 +772,7 @@ public class MasterDataImportTest {
|
||||
ObjectInputStream ois = null;
|
||||
TopLevelMasterData deserializedMasterData;
|
||||
DomainFactory domainFactory;
|
||||
UUID randomUUID = UUID.randomUUID();
|
||||
try {
|
||||
masterdata.setMasterDataExportFlagOnRaceColumns(true);
|
||||
oos.writeObject(masterdata);
|
||||
@@ -770,7 +781,7 @@ public class MasterDataImportTest {
|
||||
// Delete all data above from the database, to allow recreating all of it on target server
|
||||
deleteCreatedDataFromDatabase();
|
||||
// Import in new service
|
||||
destService = new RacingEventServiceImplMock();
|
||||
destService = new RacingEventServiceImplMock(new DataImportProgressImpl(randomUUID));
|
||||
domainFactory = destService.getBaseDomainFactory();
|
||||
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
||||
|
||||
@@ -782,7 +793,9 @@ public class MasterDataImportTest {
|
||||
ois.close();
|
||||
}
|
||||
MasterDataImporter importer = new MasterDataImporter(domainFactory, destService);
|
||||
MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData, false);
|
||||
|
||||
MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData,
|
||||
randomUUID, false);
|
||||
|
||||
Assert.assertNotNull(creationCount);
|
||||
Event eventOnTarget = destService.getEvent(eventUUID);
|
||||
@@ -932,6 +945,7 @@ public class MasterDataImportTest {
|
||||
RegattaLeaderboard leaderboardNotToOverride;
|
||||
LeaderboardGroup groupNotToOverride;
|
||||
String raceColumnNameNotToOveride;
|
||||
UUID randomUUID = UUID.randomUUID();
|
||||
try {
|
||||
masterdata.setMasterDataExportFlagOnRaceColumns(true);
|
||||
oos.writeObject(masterdata);
|
||||
@@ -940,7 +954,7 @@ public class MasterDataImportTest {
|
||||
// Delete all data above from the database, to allow recreating all of it on target server
|
||||
deleteCreatedDataFromDatabase();
|
||||
// Import in new service
|
||||
destService = new RacingEventServiceImplMock();
|
||||
destService = new RacingEventServiceImplMock(new DataImportProgressImpl(randomUUID));
|
||||
domainFactory = destService.getBaseDomainFactory();
|
||||
// Create existing data on target
|
||||
venueNameNotToOverride = "doNotOverride";
|
||||
@@ -983,7 +997,9 @@ public class MasterDataImportTest {
|
||||
ois.close();
|
||||
}
|
||||
MasterDataImporter importer = new MasterDataImporter(domainFactory, destService);
|
||||
MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData, false);
|
||||
|
||||
MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData,
|
||||
randomUUID, false);
|
||||
|
||||
// ---Asserts---
|
||||
// Test correct number of creations
|
||||
@@ -1126,6 +1142,7 @@ public class MasterDataImportTest {
|
||||
TopLevelMasterData deserializedMasterData;
|
||||
DomainFactory domainFactory;
|
||||
RegattaAndRaceIdentifier identifierOfRegattaTrackedRace;
|
||||
UUID randomUUID = UUID.randomUUID();
|
||||
try {
|
||||
masterdata.setMasterDataExportFlagOnRaceColumns(true);
|
||||
oos.writeObject(masterdata);
|
||||
@@ -1134,7 +1151,7 @@ public class MasterDataImportTest {
|
||||
// Delete all data above from the database, to allow recreating all of it on target server
|
||||
deleteCreatedDataFromDatabase();
|
||||
// Import in new service
|
||||
destService = new RacingEventServiceImplMock();
|
||||
destService = new RacingEventServiceImplMock(new DataImportProgressImpl(randomUUID));
|
||||
domainFactory = destService.getBaseDomainFactory();
|
||||
// Create existing data on target
|
||||
String venueNameToOverride = "Override";
|
||||
@@ -1182,7 +1199,8 @@ public class MasterDataImportTest {
|
||||
ois.close();
|
||||
}
|
||||
MasterDataImporter importer = new MasterDataImporter(domainFactory, destService);
|
||||
MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData, true);
|
||||
MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData,
|
||||
randomUUID, true);
|
||||
|
||||
// ---Asserts---
|
||||
// Test correct number of creations
|
||||
@@ -1253,6 +1271,7 @@ public class MasterDataImportTest {
|
||||
ObjectInputStream ois = null;
|
||||
TopLevelMasterData deserializedMasterData;
|
||||
DomainFactory domainFactory;
|
||||
UUID randomUUID = UUID.randomUUID();
|
||||
try {
|
||||
masterdata.setMasterDataExportFlagOnRaceColumns(true);
|
||||
oos.writeObject(masterdata);
|
||||
@@ -1261,7 +1280,7 @@ public class MasterDataImportTest {
|
||||
// Delete all data above from the database, to allow recreating all of it on target server
|
||||
deleteCreatedDataFromDatabase();
|
||||
// Import in new service
|
||||
destService = new RacingEventServiceImplMock();
|
||||
destService = new RacingEventServiceImplMock(new DataImportProgressImpl(randomUUID));
|
||||
domainFactory = destService.getBaseDomainFactory();
|
||||
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
||||
|
||||
@@ -1273,7 +1292,7 @@ public class MasterDataImportTest {
|
||||
ois.close();
|
||||
}
|
||||
MasterDataImporter importer = new MasterDataImporter(domainFactory, destService);
|
||||
importer.importMasterData(deserializedMasterData, false);
|
||||
importer.importMasterData(deserializedMasterData, randomUUID, false);
|
||||
|
||||
Regatta importedRegatta = destService.getRegattaByName(regatta.getName());
|
||||
|
||||
@@ -1380,6 +1399,7 @@ public class MasterDataImportTest {
|
||||
ObjectInputStream ois = null;
|
||||
TopLevelMasterData deserializedMasterData;
|
||||
DomainFactory domainFactory;
|
||||
UUID randomUUID = UUID.randomUUID();
|
||||
try {
|
||||
masterdata.setMasterDataExportFlagOnRaceColumns(true);
|
||||
oos.writeObject(masterdata);
|
||||
@@ -1388,7 +1408,7 @@ public class MasterDataImportTest {
|
||||
// Delete all data above from the database, to allow recreating all of it on target server
|
||||
deleteCreatedDataFromDatabase();
|
||||
// Import in new service
|
||||
destService = new RacingEventServiceImplMock();
|
||||
destService = new RacingEventServiceImplMock(new DataImportProgressImpl(randomUUID));
|
||||
domainFactory = destService.getBaseDomainFactory();
|
||||
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
||||
|
||||
@@ -1400,7 +1420,8 @@ public class MasterDataImportTest {
|
||||
ois.close();
|
||||
}
|
||||
MasterDataImporter importer = new MasterDataImporter(domainFactory, destService);
|
||||
MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData, false);
|
||||
MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData,
|
||||
randomUUID, false);
|
||||
|
||||
// ---Asserts---
|
||||
Assert.assertNotNull(creationCount);
|
||||
@@ -1518,6 +1539,7 @@ public class MasterDataImportTest {
|
||||
ObjectInputStream ois = null;
|
||||
TopLevelMasterData deserializedMasterData;
|
||||
DomainFactory domainFactory;
|
||||
UUID randomUUID = UUID.randomUUID();
|
||||
try {
|
||||
masterdata.setMasterDataExportFlagOnRaceColumns(true);
|
||||
oos.writeObject(masterdata);
|
||||
@@ -1526,7 +1548,7 @@ public class MasterDataImportTest {
|
||||
// Delete all data above from the database, to allow recreating all of it on target server
|
||||
deleteCreatedDataFromDatabase();
|
||||
// Import in new service
|
||||
destService = new RacingEventServiceImplMock();
|
||||
destService = new RacingEventServiceImplMock(new DataImportProgressImpl(randomUUID));
|
||||
domainFactory = destService.getBaseDomainFactory();
|
||||
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
||||
|
||||
@@ -1538,7 +1560,8 @@ public class MasterDataImportTest {
|
||||
ois.close();
|
||||
}
|
||||
MasterDataImporter importer = new MasterDataImporter(domainFactory, destService);
|
||||
MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData, false);
|
||||
MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData,
|
||||
randomUUID, false);
|
||||
|
||||
// ---Asserts---
|
||||
|
||||
@@ -1576,6 +1599,7 @@ public class MasterDataImportTest {
|
||||
ObjectInputStream ois = null;
|
||||
TopLevelMasterData deserializedMasterData;
|
||||
DomainFactory domainFactory;
|
||||
UUID randomUUID = UUID.randomUUID();
|
||||
try {
|
||||
masterdata.setMasterDataExportFlagOnRaceColumns(true);
|
||||
oos.writeObject(masterdata);
|
||||
@@ -1584,7 +1608,7 @@ public class MasterDataImportTest {
|
||||
// Delete all data above from the database, to allow recreating all of it on target server
|
||||
deleteCreatedDataFromDatabase();
|
||||
// Import in new service
|
||||
destService = new RacingEventServiceImplMock();
|
||||
destService = new RacingEventServiceImplMock(new DataImportProgressImpl(randomUUID));
|
||||
domainFactory = destService.getBaseDomainFactory();
|
||||
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
||||
|
||||
@@ -1596,7 +1620,8 @@ public class MasterDataImportTest {
|
||||
ois.close();
|
||||
}
|
||||
MasterDataImporter importer = new MasterDataImporter(domainFactory, destService);
|
||||
MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData, false);
|
||||
MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData,
|
||||
randomUUID, false);
|
||||
|
||||
// ---Asserts---
|
||||
|
||||
@@ -1698,6 +1723,7 @@ public class MasterDataImportTest {
|
||||
ObjectInputStream ois = null;
|
||||
TopLevelMasterData deserializedMasterData;
|
||||
DomainFactory domainFactory;
|
||||
UUID randomUUID = UUID.randomUUID();
|
||||
try {
|
||||
masterdata.setMasterDataExportFlagOnRaceColumns(true);
|
||||
oos.writeObject(masterdata);
|
||||
@@ -1706,7 +1732,7 @@ public class MasterDataImportTest {
|
||||
// Delete all data above from the database, to allow recreating all of it on target server
|
||||
deleteCreatedDataFromDatabase();
|
||||
// Import in new service
|
||||
destService = new RacingEventServiceImplMock();
|
||||
destService = new RacingEventServiceImplMock(new DataImportProgressImpl(randomUUID));
|
||||
domainFactory = destService.getBaseDomainFactory();
|
||||
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
||||
|
||||
@@ -1718,7 +1744,8 @@ public class MasterDataImportTest {
|
||||
ois.close();
|
||||
}
|
||||
MasterDataImporter importer = new MasterDataImporter(domainFactory, destService);
|
||||
MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData, false);
|
||||
MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData,
|
||||
randomUUID, false);
|
||||
|
||||
// Test correct number of creations
|
||||
Assert.assertNotNull(creationCount);
|
||||
@@ -1771,6 +1798,7 @@ public class MasterDataImportTest {
|
||||
ObjectInputStream ois = null;
|
||||
TopLevelMasterData deserializedMasterData;
|
||||
DomainFactory domainFactory;
|
||||
UUID randomUUID = UUID.randomUUID();
|
||||
try {
|
||||
masterdata.setMasterDataExportFlagOnRaceColumns(true);
|
||||
oos.writeObject(masterdata);
|
||||
@@ -1779,7 +1807,7 @@ public class MasterDataImportTest {
|
||||
// Delete all data above from the database, to allow recreating all of it on target server
|
||||
deleteCreatedDataFromDatabase();
|
||||
// Import in new service
|
||||
destService = new RacingEventServiceImplMock();
|
||||
destService = new RacingEventServiceImplMock(new DataImportProgressImpl(randomUUID));
|
||||
domainFactory = destService.getBaseDomainFactory();
|
||||
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
||||
|
||||
@@ -1791,7 +1819,8 @@ public class MasterDataImportTest {
|
||||
ois.close();
|
||||
}
|
||||
MasterDataImporter importer = new MasterDataImporter(domainFactory, destService);
|
||||
MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData, false);
|
||||
MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData,
|
||||
randomUUID, false);
|
||||
|
||||
// Test correct number of creations
|
||||
Assert.assertEquals(1, creationCount.getLeaderboardGroupCount());
|
||||
|
||||
+14
@@ -4,15 +4,24 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.common.impl.DataImportProgressImpl;
|
||||
import com.sap.sailing.domain.tracking.RaceTracker;
|
||||
import com.sap.sailing.server.impl.RacingEventServiceImpl;
|
||||
import com.sap.sailing.server.masterdata.DataImportLockWithProgress;
|
||||
|
||||
public class RacingEventServiceImplMock extends RacingEventServiceImpl {
|
||||
|
||||
private DataImportLockWithProgress lock;
|
||||
|
||||
public RacingEventServiceImplMock() {
|
||||
super();
|
||||
}
|
||||
|
||||
public RacingEventServiceImplMock(DataImportProgressImpl dataImportProgressImpl) {
|
||||
lock = new DataImportLockWithProgress();
|
||||
lock.addProgress(dataImportProgressImpl.getOperationId(), dataImportProgressImpl);
|
||||
}
|
||||
|
||||
public Map<String, Regatta> getEventsByNameMap() {
|
||||
return regattasByName;
|
||||
}
|
||||
@@ -28,4 +37,9 @@ public class RacingEventServiceImplMock extends RacingEventServiceImpl {
|
||||
public Map<String, Regatta> getEventsByName() {
|
||||
return regattasByName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataImportLockWithProgress getDataImportLock() {
|
||||
return lock;
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import com.sap.sailing.domain.base.configuration.DeviceConfiguration;
|
||||
import com.sap.sailing.domain.base.configuration.DeviceConfigurationIdentifier;
|
||||
import com.sap.sailing.domain.base.configuration.DeviceConfigurationMatcher;
|
||||
import com.sap.sailing.domain.base.configuration.RegattaConfiguration;
|
||||
import com.sap.sailing.domain.common.DataImportProgress;
|
||||
import com.sap.sailing.domain.common.RaceFetcher;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaFetcher;
|
||||
@@ -57,6 +58,7 @@ import com.sap.sailing.domain.tracking.TrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||
import com.sap.sailing.domain.tracking.TrackerManager;
|
||||
import com.sap.sailing.domain.tracking.WindStore;
|
||||
import com.sap.sailing.server.masterdata.DataImportLockWithProgress;
|
||||
|
||||
/**
|
||||
* An OSGi service that can be used to track boat races using a TracTrac connector that pushes
|
||||
@@ -484,4 +486,22 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch
|
||||
DomainObjectFactory getDomainObjectFactory();
|
||||
|
||||
WindStore getWindStore();
|
||||
|
||||
/**
|
||||
* This lock exists to allow only one master data import at a time to avoid situation where multiple Imports
|
||||
* override each other in unpredictable fashion
|
||||
*/
|
||||
DataImportLockWithProgress getDataImportLock();
|
||||
|
||||
DataImportProgress createOrUpdateDataImportProgressWithReplication(UUID importOperationId,
|
||||
double overallProgressPct,
|
||||
String subProgressName, double subProgressPct);
|
||||
|
||||
DataImportProgress createOrUpdateDataImportProgressWithoutReplication(UUID importOperationId,
|
||||
double overallProgressPct,
|
||||
String subProgressName, double subProgressPct);
|
||||
|
||||
void setDataImportFailedWithReplication(UUID importOperationId, String errorMessage);
|
||||
|
||||
void setDataImportFailedWithoutReplication(UUID importOperationId, String errorMessage);
|
||||
}
|
||||
+62
@@ -54,6 +54,7 @@ import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationMapImpl
|
||||
import com.sap.sailing.domain.base.impl.DynamicCompetitor;
|
||||
import com.sap.sailing.domain.base.impl.EventImpl;
|
||||
import com.sap.sailing.domain.base.impl.RegattaImpl;
|
||||
import com.sap.sailing.domain.common.DataImportProgress;
|
||||
import com.sap.sailing.domain.common.LeaderboardNameConstants;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaIdentifier;
|
||||
@@ -65,6 +66,7 @@ import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.dto.FleetDTO;
|
||||
import com.sap.sailing.domain.common.dto.RegattaCreationParametersDTO;
|
||||
import com.sap.sailing.domain.common.dto.SeriesCreationParametersDTO;
|
||||
import com.sap.sailing.domain.common.impl.DataImportProgressImpl;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||
@@ -120,6 +122,7 @@ import com.sap.sailing.operationaltransformation.Operation;
|
||||
import com.sap.sailing.server.OperationExecutionListener;
|
||||
import com.sap.sailing.server.RacingEventServiceOperation;
|
||||
import com.sap.sailing.server.Replicator;
|
||||
import com.sap.sailing.server.masterdata.DataImportLockWithProgress;
|
||||
import com.sap.sailing.server.operationaltransformation.AddCourseArea;
|
||||
import com.sap.sailing.server.operationaltransformation.AddDefaultRegatta;
|
||||
import com.sap.sailing.server.operationaltransformation.AddMediaTrackOperation;
|
||||
@@ -127,8 +130,10 @@ import com.sap.sailing.server.operationaltransformation.AddRaceDefinition;
|
||||
import com.sap.sailing.server.operationaltransformation.AddSpecificRegatta;
|
||||
import com.sap.sailing.server.operationaltransformation.ConnectTrackedRaceToLeaderboardColumn;
|
||||
import com.sap.sailing.server.operationaltransformation.CreateEvent;
|
||||
import com.sap.sailing.server.operationaltransformation.CreateOrUpdateDataImportProgress;
|
||||
import com.sap.sailing.server.operationaltransformation.CreateOrUpdateDeviceConfiguration;
|
||||
import com.sap.sailing.server.operationaltransformation.CreateTrackedRace;
|
||||
import com.sap.sailing.server.operationaltransformation.DataImportFailed;
|
||||
import com.sap.sailing.server.operationaltransformation.RecordCompetitorGPSFix;
|
||||
import com.sap.sailing.server.operationaltransformation.RecordMarkGPSFix;
|
||||
import com.sap.sailing.server.operationaltransformation.RecordWindFix;
|
||||
@@ -242,6 +247,12 @@ public class RacingEventServiceImpl implements RacingEventServiceWithTestSupport
|
||||
|
||||
private final WindStore windStore;
|
||||
|
||||
/**
|
||||
* Allow only one master data import at a time to avoid situation where multiple Imports override each other in
|
||||
* unpredictable fashion
|
||||
*/
|
||||
private final DataImportLockWithProgress dataImportLock;
|
||||
|
||||
/**
|
||||
* If this service runs in the context of an OSGi environment, the activator should {@link #setBundleContext set the bundle context} on this
|
||||
* object so that service lookups become possible.
|
||||
@@ -313,6 +324,7 @@ public class RacingEventServiceImpl implements RacingEventServiceWithTestSupport
|
||||
this.mediaDB = mediaDb;
|
||||
this.competitorStore = competitorStore;
|
||||
this.windStore = windStore;
|
||||
this.dataImportLock = new DataImportLockWithProgress();
|
||||
|
||||
regattasByName = new ConcurrentHashMap<String, Regatta>();
|
||||
eventsById = new ConcurrentHashMap<Serializable, Event>();
|
||||
@@ -2197,4 +2209,54 @@ public class RacingEventServiceImpl implements RacingEventServiceWithTestSupport
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataImportLockWithProgress getDataImportLock() {
|
||||
return dataImportLock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataImportProgress createOrUpdateDataImportProgressWithReplication(UUID importOperationId,
|
||||
double overallProgressPct, String subProgressName, double subProgressPct) {
|
||||
// Create/Update locally
|
||||
DataImportProgress progress = createOrUpdateDataImportProgressWithoutReplication(importOperationId,
|
||||
overallProgressPct, subProgressName, subProgressPct);
|
||||
// Create/Update on replicas
|
||||
replicate(new CreateOrUpdateDataImportProgress(importOperationId, overallProgressPct, subProgressName,
|
||||
subProgressPct));
|
||||
return progress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataImportProgress createOrUpdateDataImportProgressWithoutReplication(UUID importOperationId,
|
||||
double overallProgressPct, String subProgressName, double subProgressPct) {
|
||||
DataImportProgress progress = dataImportLock.getProgress(importOperationId);
|
||||
boolean newObject = false;
|
||||
if (progress == null) {
|
||||
progress = new DataImportProgressImpl(importOperationId);
|
||||
newObject = true;
|
||||
}
|
||||
progress.setOverAllProgressPct(overallProgressPct);
|
||||
progress.setNameOfCurrentSubProgress(subProgressName);
|
||||
progress.setCurrentSubProgressPct(subProgressPct);
|
||||
if (newObject) {
|
||||
dataImportLock.addProgress(importOperationId, progress);
|
||||
}
|
||||
return progress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataImportFailedWithoutReplication(UUID importOperationId, String errorMessage) {
|
||||
DataImportProgress progress = dataImportLock.getProgress(importOperationId);
|
||||
if (progress != null) {
|
||||
progress.setFailed();
|
||||
progress.setErrorMessage(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataImportFailedWithReplication(UUID importOperationId, String errorMessage) {
|
||||
setDataImportFailedWithoutReplication(importOperationId, errorMessage);
|
||||
replicate(new DataImportFailed(importOperationId, errorMessage));
|
||||
}
|
||||
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
package com.sap.sailing.server.masterdata;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import com.sap.sailing.domain.common.DataImportProgress;
|
||||
|
||||
public class DataImportLockWithProgress extends ReentrantLock {
|
||||
/**
|
||||
* Defaults to 60s (60000ms).
|
||||
*/
|
||||
private static final int TIME_TO_DELETE_PROGRESS_ENTRY_AFTER_OPERATION_FINISHED_IN_MILLIS = 60000;
|
||||
|
||||
private static final long serialVersionUID = -3527221613483691340L;
|
||||
|
||||
private DataImportProgress currentProgress;
|
||||
|
||||
private final Map<UUID, DataImportProgress> progressPerId;
|
||||
|
||||
public DataImportLockWithProgress() {
|
||||
super(true);
|
||||
progressPerId = new HashMap<UUID, DataImportProgress>();
|
||||
}
|
||||
|
||||
public void lock(UUID operationId) {
|
||||
super.lock();
|
||||
currentProgress = progressPerId.get(operationId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock() {
|
||||
setDeleteFromMapTimer(currentProgress);
|
||||
currentProgress = null;
|
||||
super.unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* This timer ensures that operation results are deleted from memory after some time. Just deleting the entry when
|
||||
* the operation is done does not ensure that the entry is deleted from every replica, since the last progress
|
||||
* request will only reach one server.
|
||||
*/
|
||||
private void setDeleteFromMapTimer(final DataImportProgress progressToDelete) {
|
||||
TimerTask deleteTask = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (progressPerId) {
|
||||
progressPerId.remove(progressToDelete.getOperationId());
|
||||
}
|
||||
}
|
||||
};
|
||||
Timer timer = new Timer();
|
||||
timer.schedule(deleteTask, TIME_TO_DELETE_PROGRESS_ENTRY_AFTER_OPERATION_FINISHED_IN_MILLIS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param operationId
|
||||
* @return the progress identified by the ID. Otherwise null.
|
||||
*/
|
||||
public DataImportProgress getProgress(UUID operationId) {
|
||||
DataImportProgress progress;
|
||||
synchronized (progressPerId) {
|
||||
progress = progressPerId.get(operationId);
|
||||
}
|
||||
return progress;
|
||||
}
|
||||
|
||||
public void addProgress(UUID operationId, DataImportProgress progress) {
|
||||
synchronized (progressPerId) {
|
||||
progressPerId.put(operationId, progress);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+31
-11
@@ -3,10 +3,12 @@ package com.sap.sailing.server.masterdata;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.sap.sailing.domain.base.DomainFactory;
|
||||
import com.sap.sailing.domain.common.MasterDataImportObjectCreationCount;
|
||||
import com.sap.sailing.domain.common.impl.MasterDataImportObjectCreationCountImpl;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.domain.masterdataimport.TopLevelMasterData;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
@@ -22,9 +24,11 @@ public class MasterDataImporter {
|
||||
this.racingEventService = racingEventService;
|
||||
}
|
||||
|
||||
public MasterDataImportObjectCreationCount importMasterData(TopLevelMasterData topLevelMasterData, boolean override) {
|
||||
public MasterDataImportObjectCreationCount importMasterData(TopLevelMasterData topLevelMasterData,
|
||||
UUID importOperationId, boolean override) {
|
||||
MasterDataImportObjectCreationCountImpl creationCount = new MasterDataImportObjectCreationCountImpl();
|
||||
ImportMasterDataOperation op = new ImportMasterDataOperation(topLevelMasterData, override, creationCount,
|
||||
ImportMasterDataOperation op = new ImportMasterDataOperation(topLevelMasterData, importOperationId, override,
|
||||
creationCount,
|
||||
baseDomainFactory);
|
||||
creationCount = racingEventService.apply(op);
|
||||
createMediaTracks(topLevelMasterData, override);
|
||||
@@ -33,23 +37,39 @@ public class MasterDataImporter {
|
||||
}
|
||||
|
||||
private void createMediaTracks(TopLevelMasterData topLevelMasterData, boolean override) {
|
||||
Collection<MediaTrack> tracks = topLevelMasterData.getAllMediaTracks();
|
||||
Collection<MediaTrack> tracksToImport = topLevelMasterData.getAllMediaTracks();
|
||||
Collection<MediaTrack> existingMediaTracks = racingEventService.getAllMediaTracks();
|
||||
Map<String, MediaTrack> existingMap = new HashMap<String, MediaTrack>();
|
||||
|
||||
for (MediaTrack oneTrack : existingMediaTracks) {
|
||||
existingMap.put(oneTrack.dbId, oneTrack);
|
||||
for (MediaTrack existingTrack : existingMediaTracks) {
|
||||
existingMap.put(existingTrack.dbId, existingTrack);
|
||||
}
|
||||
|
||||
for (MediaTrack oneNewTrack : tracks) {
|
||||
if (existingMap.containsKey(oneNewTrack.dbId)) {
|
||||
for (MediaTrack trackToImport : tracksToImport) {
|
||||
MediaTrack existingTrack = existingMap.get(trackToImport.dbId);
|
||||
if (existingTrack == null) {
|
||||
racingEventService.mediaTrackAdded(trackToImport);
|
||||
} else {
|
||||
if (override) {
|
||||
racingEventService.mediaTrackDeleted(existingMap.get(oneNewTrack.dbId));
|
||||
} else {
|
||||
continue;
|
||||
|
||||
// Using fine-grained update methods.
|
||||
// Rationale: Changes on more than one track property are rare
|
||||
// and don't justify the introduction of a new set
|
||||
// of methods (including replication).
|
||||
if (!Util.equalsWithNull(existingTrack.title, trackToImport.title)) {
|
||||
racingEventService.mediaTrackTitleChanged(trackToImport);
|
||||
}
|
||||
if (!Util.equalsWithNull(existingTrack.url, trackToImport.url)) {
|
||||
racingEventService.mediaTrackUrlChanged(trackToImport);
|
||||
}
|
||||
if (!Util.equalsWithNull(existingTrack.startTime, trackToImport.startTime)) {
|
||||
racingEventService.mediaTrackStartTimeChanged(trackToImport);
|
||||
}
|
||||
if (existingTrack.durationInMillis != trackToImport.durationInMillis) {
|
||||
racingEventService.mediaTrackDurationChanged(trackToImport);
|
||||
}
|
||||
}
|
||||
}
|
||||
racingEventService.mediaTrackAdded(oneNewTrack);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.sap.sailing.server.operationaltransformation;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sailing.server.RacingEventServiceOperation;
|
||||
|
||||
public class CreateOrUpdateDataImportProgress extends AbstractRacingEventServiceOperation<Void> {
|
||||
|
||||
private static final long serialVersionUID = 7619972832594152077L;
|
||||
|
||||
private UUID importOperationId;
|
||||
private double overallProgressPct;
|
||||
private String subProgressName;
|
||||
private double subProgressPct;
|
||||
|
||||
public CreateOrUpdateDataImportProgress(UUID importOperationId, double overallProgressPct, String subProgressName,
|
||||
double subProgressPct) {
|
||||
this.importOperationId = importOperationId;
|
||||
this.overallProgressPct = overallProgressPct;
|
||||
this.subProgressName = subProgressName;
|
||||
this.subProgressPct = subProgressPct;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void internalApplyTo(RacingEventService toState) throws Exception {
|
||||
toState.createOrUpdateDataImportProgressWithoutReplication(importOperationId, overallProgressPct,
|
||||
subProgressName, subProgressPct);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RacingEventServiceOperation<?> transformClientOp(RacingEventServiceOperation<?> serverOp) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RacingEventServiceOperation<?> transformServerOp(RacingEventServiceOperation<?> clientOp) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.sap.sailing.server.operationaltransformation;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sailing.server.RacingEventServiceOperation;
|
||||
|
||||
public class DataImportFailed extends AbstractRacingEventServiceOperation<Void> {
|
||||
|
||||
private static final long serialVersionUID = -3509389848341980239L;
|
||||
private UUID importOperationId;
|
||||
private String errorMessage;
|
||||
|
||||
public DataImportFailed(UUID importOperationId, String errorMessage) {
|
||||
this.importOperationId = importOperationId;
|
||||
this.errorMessage = errorMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void internalApplyTo(RacingEventService toState) throws Exception {
|
||||
toState.setDataImportFailedWithoutReplication(importOperationId, errorMessage);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RacingEventServiceOperation<?> transformClientOp(RacingEventServiceOperation<?> serverOp) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RacingEventServiceOperation<?> transformServerOp(RacingEventServiceOperation<?> clientOp) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
+34
-6
@@ -20,6 +20,7 @@ import com.sap.sailing.domain.base.RaceColumn;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.Series;
|
||||
import com.sap.sailing.domain.common.DataImportProgress;
|
||||
import com.sap.sailing.domain.common.RaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||
@@ -59,22 +60,44 @@ public class ImportMasterDataOperation extends
|
||||
|
||||
private final boolean override;
|
||||
|
||||
public ImportMasterDataOperation(TopLevelMasterData topLevelMasterData, boolean override,
|
||||
private final UUID importOperationId;
|
||||
|
||||
private DataImportProgress progress;
|
||||
|
||||
public ImportMasterDataOperation(TopLevelMasterData topLevelMasterData, UUID importOperationId, boolean override,
|
||||
MasterDataImportObjectCreationCountImpl existingCreationCount, DomainFactory baseDomainFactory) {
|
||||
this.creationCount = new MasterDataImportObjectCreationCountImpl();
|
||||
this.creationCount.add(existingCreationCount);
|
||||
this.baseDomainFactory = baseDomainFactory;
|
||||
this.masterData = topLevelMasterData;
|
||||
this.override = override;
|
||||
this.importOperationId = importOperationId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MasterDataImportObjectCreationCountImpl internalApplyTo(RacingEventService toState) throws Exception {
|
||||
for (LeaderboardGroup leaderboardGroup : masterData.getLeaderboardGroups()) {
|
||||
createLeaderboardGroupWithAllRelatedObjects(toState, leaderboardGroup);
|
||||
this.progress = toState.getDataImportLock().getProgress(importOperationId);
|
||||
progress.setNameOfCurrentSubProgress("Waiting for other data import operations to finish");
|
||||
toState.getDataImportLock().lock(importOperationId);
|
||||
try {
|
||||
progress.setNameOfCurrentSubProgress("Importing leaderboard groups");
|
||||
progress.setCurrentSubProgressPct(0);
|
||||
int numOfGroupsToImport = masterData.getLeaderboardGroups().size();
|
||||
int i = 0;
|
||||
for (LeaderboardGroup leaderboardGroup : masterData.getLeaderboardGroups()) {
|
||||
createLeaderboardGroupWithAllRelatedObjects(toState, leaderboardGroup);
|
||||
i++;
|
||||
progress.setCurrentSubProgressPct((double) i / numOfGroupsToImport);
|
||||
}
|
||||
progress.setNameOfCurrentSubProgress("Importing wind tracks");
|
||||
progress.setOverAllProgressPct(0.5);
|
||||
progress.setCurrentSubProgressPct(0);
|
||||
createWindTracks(toState);
|
||||
toState.getDataImportLock().getProgress(importOperationId).setResult(creationCount);
|
||||
return creationCount;
|
||||
} finally {
|
||||
toState.getDataImportLock().unlock();
|
||||
}
|
||||
createWindTracks(toState);
|
||||
return creationCount;
|
||||
}
|
||||
|
||||
private void createLeaderboardGroupWithAllRelatedObjects(final RacingEventService toState,
|
||||
@@ -241,12 +264,17 @@ public class ImportMasterDataOperation extends
|
||||
}
|
||||
|
||||
private void createWindTracks(RacingEventService toState) {
|
||||
int numOfWindTracks = masterData.getWindTrackMasterData().size();
|
||||
int i = 0;
|
||||
for (WindTrackMasterData windMasterData : masterData.getWindTrackMasterData()) {
|
||||
DummyTrackedRace trackedRaceWithNameAndId = new DummyTrackedRace(windMasterData.getRaceName(), windMasterData.getRaceId());
|
||||
WindTrack windTrack = toState.getWindStore().getWindTrack(windMasterData.getRegattaName(), trackedRaceWithNameAndId, windMasterData.getWindSource(), 0, -1);
|
||||
for (Wind fix : windMasterData.getFixes()) {
|
||||
windTrack.add(fix);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
progress.setCurrentSubProgressPct((double) i / numOfWindTracks);
|
||||
progress.setOverAllProgressPct(0.5 + (0.5) * ((double) i / numOfWindTracks));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -368,7 +368,7 @@ public class ESSCourseDesignDialog extends RaceDialogFragment {
|
||||
+ courseElement.getRightMark().getName();
|
||||
ControlPointWithTwoMarks cpwtm = new ControlPointWithTwoMarksImpl(courseElement.getLeftMark(),
|
||||
courseElement.getRightMark(), cpwtmName);
|
||||
Waypoint waypoint = new WaypointImpl(cpwtm);
|
||||
Waypoint waypoint = new WaypointImpl(cpwtm, courseElement.getPassingInstructions());
|
||||
|
||||
waypoints.add(waypoint);
|
||||
} else {
|
||||
|
||||
Reference in new issue
Block a user