mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-09 13:50:57 +00:00
Merge branch 'master' of ssh://sapsailing.com/home/trac/git
This commit is contained in:
commit
4fec3fba8d
74 files changed
+2965
-499
No files matched your search
@@ -1,2 +1,3 @@
|
||||
bin
|
||||
.gwt
|
||||
/bin
|
||||
+2
-2
@@ -901,7 +901,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
public void storeCompetitor(Competitor competitor) {
|
||||
DBCollection collection = database.getCollection(CollectionNames.COMPETITORS.name());
|
||||
JSONObject json = competitorSerializer.serialize(competitor);
|
||||
DBObject query = (DBObject) JSON.parse(competitorSerializer.getCompetitorIdQuery(competitor).toString());
|
||||
DBObject query = (DBObject) JSON.parse(CompetitorJsonSerializer.getCompetitorIdQuery(competitor).toString());
|
||||
DBObject entry = (DBObject) JSON.parse(json.toString());
|
||||
collection.update(query, entry, /* upsrt */true, /* multi */false, WriteConcern.SAFE);
|
||||
}
|
||||
@@ -917,7 +917,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
public void removeCompetitor(Competitor competitor) {
|
||||
logger.info("Removing persistent competitor info for competitor "+competitor.getName()+" with ID "+competitor.getId());
|
||||
DBCollection collection = database.getCollection(CollectionNames.COMPETITORS.name());
|
||||
DBObject query = (DBObject) JSON.parse(competitorSerializer.getCompetitorIdQuery(competitor).toString());
|
||||
DBObject query = (DBObject) JSON.parse(CompetitorJsonSerializer.getCompetitorIdQuery(competitor).toString());
|
||||
collection.remove(query);
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
/bin
|
||||
/bin
|
||||
+1
-1
@@ -20,7 +20,7 @@ public class MarkPassingByTimeComparator implements Comparator<MarkPassing>, Ser
|
||||
|
||||
@Override
|
||||
public int compare(MarkPassing o1, MarkPassing o2) {
|
||||
int result = o1 == null ? o2 == null ? 0 : -1 : o2 == null ? 1 : o1.getTimePoint().compareTo(o2.getTimePoint());
|
||||
int result = o1 == null ? o2 == null ? 0 : -1 : o2 == null ? 1 : o1.getTimePoint() == null ? (o2.getTimePoint() == null ? 0 : -1) : o2.getTimePoint() == null ? 1 : o1.getTimePoint().compareTo(o2.getTimePoint());
|
||||
if (result == 0 && o1 != null) {
|
||||
assert o2 != null;
|
||||
Object c1ID = o1.getCompetitor().getId();
|
||||
|
||||
@@ -372,6 +372,18 @@ body ::-webkit-scrollbar-track {
|
||||
.timePanel-controls-time .dateLabel,
|
||||
.timePanel-controls-time .timeLabel {
|
||||
padding: 4px 20px 0 0;
|
||||
float:left;
|
||||
}
|
||||
|
||||
.timePanel-controls-timeToStart {
|
||||
float:left;
|
||||
padding: 0 0 0 0;
|
||||
border-left: 1px solid #fcbb22;
|
||||
}
|
||||
|
||||
.timePanel-controls-timeToStart .timeToStartLabel {
|
||||
float:left;
|
||||
padding: 4px 20px 0 20px;
|
||||
}
|
||||
|
||||
.timePanel-controls-timeDelay {
|
||||
|
||||
+1
@@ -28,6 +28,7 @@ public abstract class AbstractEventManagementPanel extends AbstractRegattaPanel
|
||||
// TrackedEventsComposite should exist in every *ManagementPanel.
|
||||
trackedRacesListComposite = new TrackedRacesListComposite(sailingService, errorReporter, regattaRefresher,
|
||||
raceSelectionProvider, stringMessages, /* multiselection */ true);
|
||||
trackedRacesListComposite.ensureDebugId("TrackedRaces");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-2
@@ -126,7 +126,7 @@ public abstract class AbstractTrackedRacesListComposite extends SimplePanel impl
|
||||
|
||||
AdminConsoleTableResources tableRes = GWT.create(AdminConsoleTableResources.class);
|
||||
raceTable = new CellTable<RaceDTO>(/* pageSize */10000, tableRes);
|
||||
raceTable.ensureDebugId("TrackedRaces");
|
||||
raceTable.ensureDebugId("TrackedRacesTable");
|
||||
ListHandler<RaceDTO> columnSortHandler = setupTableColumns(stringMessages);
|
||||
raceTable.setWidth("300px");
|
||||
raceTable.setSelectionModel(selectionModel);
|
||||
@@ -152,7 +152,6 @@ public abstract class AbstractTrackedRacesListComposite extends SimplePanel impl
|
||||
}
|
||||
});
|
||||
filterablePanelRaces = new LabeledAbstractFilterablePanel<RaceDTO>(lblFilterRaces, allRaces, raceTable, raceList) {
|
||||
|
||||
@Override
|
||||
public List<String> getSearchableStrings(RaceDTO t) {
|
||||
List<String> strings = new ArrayList<String>();
|
||||
@@ -163,6 +162,7 @@ public abstract class AbstractTrackedRacesListComposite extends SimplePanel impl
|
||||
return strings;
|
||||
}
|
||||
};
|
||||
filterablePanelRaces.getTextBox().ensureDebugId("TrackedRacesFilter");
|
||||
filterPanel.add(filterablePanelRaces);
|
||||
HorizontalPanel trackedRacesButtonPanel = new HorizontalPanel();
|
||||
trackedRacesButtonPanel.setSpacing(10);
|
||||
|
||||
+23
@@ -12,6 +12,29 @@ public class DateAndTimeFormatterUtil {
|
||||
public static DateTimeFormatRenderer defaultTimeFormatter = new DateTimeFormatRenderer(
|
||||
DateTimeFormat.getFormat(PredefinedFormat.TIME_LONG));
|
||||
|
||||
private static DateTimeFormatRenderer secondsTimeFormatter = new DateTimeFormatRenderer(
|
||||
DateTimeFormat.getFormat("m:ss"));
|
||||
private static DateTimeFormatRenderer minutesAndSecondsTimeFormatter = new DateTimeFormatRenderer(
|
||||
DateTimeFormat.getFormat("mm:ss"));
|
||||
private static DateTimeFormatRenderer hoursAndMinutesAndSecondsTimeFormatter = new DateTimeFormatRenderer(
|
||||
DateTimeFormat.getFormat("HH:mm:ss"));
|
||||
|
||||
public static String formatElapsedTime(long timeInMilliseconds) {
|
||||
String result = "";
|
||||
int seconds = (int) (timeInMilliseconds / 1000) % 60 ;
|
||||
int minutes = (int) ((timeInMilliseconds / (1000*60)) % 60);
|
||||
int hours = (int) ((timeInMilliseconds / (1000*60*60)) % 24);
|
||||
if(hours > 0) {
|
||||
result = hoursAndMinutesAndSecondsTimeFormatter.render(new Date(timeInMilliseconds));
|
||||
} else if (minutes > 0) {
|
||||
result = minutesAndSecondsTimeFormatter.render(new Date(timeInMilliseconds));
|
||||
} else if (seconds > 0) {
|
||||
result = secondsTimeFormatter.render(new Date(timeInMilliseconds));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String formatDateAndTime(Date date) {
|
||||
String result = "";
|
||||
if(date != null) {
|
||||
|
||||
+1
@@ -16,6 +16,7 @@ public class FlexibleLeaderboardCreateDialog extends FlexibleLeaderboardDialog {
|
||||
nameTextBox = createTextBox(null);
|
||||
nameTextBox.ensureDebugId("LeaderboardNameField");
|
||||
displayNameTextBox = createTextBox(null);
|
||||
displayNameTextBox.ensureDebugId("LeaderboardDisplayNameField");
|
||||
nameTextBox.setVisibleLength(50);
|
||||
displayNameTextBox.setVisibleLength(50);
|
||||
|
||||
|
||||
+4
@@ -435,6 +435,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
|
||||
raceSelectionProvider = new RaceSelectionModel();
|
||||
trackedRacesListComposite = new TrackedRacesListComposite(sailingService, errorReporter, adminConsole,
|
||||
raceSelectionProvider, stringMessages, /* multiselection */false);
|
||||
trackedRacesListComposite.ensureDebugId("TrackedRaces");
|
||||
trackedRacesPanel.add(trackedRacesListComposite);
|
||||
trackedRacesListComposite.addTrackedRaceChangeListener(this);
|
||||
raceSelectionProvider.addRaceSelectionChangeListener(this);
|
||||
@@ -539,6 +540,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
|
||||
Label lblRaceNamesIn = new Label(stringMessages.races());
|
||||
vPanel.add(lblRaceNamesIn);
|
||||
raceColumnTable = new CellTable<RaceColumnDTOAndFleetDTOWithNameBasedEquality>(/* pageSize */200, tableRes);
|
||||
raceColumnTable.ensureDebugId("RaceColumnTable");
|
||||
raceColumnTable.addColumn(raceLinkColumn, stringMessages.name());
|
||||
raceColumnTable.addColumn(fleetNameColumn, stringMessages.fleet());
|
||||
raceColumnTable.addColumn(isMedalRaceCheckboxColumn, stringMessages.medalRace());
|
||||
@@ -561,6 +563,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
|
||||
vPanel.add(selectedLeaderboardRaceButtonPanel);
|
||||
|
||||
addRaceColumnsButton = new Button(stringMessages.actionAddRaces() + "...");
|
||||
addRaceColumnsButton.ensureDebugId("AddRaceColumnsButton");
|
||||
selectedLeaderboardRaceButtonPanel.add(addRaceColumnsButton);
|
||||
addRaceColumnsButton.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
@@ -994,6 +997,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
|
||||
updateRaceColumnsOfLeaderboard(leaderboardName, existingRaceColumns, result);
|
||||
}
|
||||
});
|
||||
raceDialog.ensureDebugId("RaceColumnsInLeaderboardDialog");
|
||||
raceDialog.show();
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -81,6 +81,7 @@ public class RaceColumnsInLeaderboardDialog extends DataEntryDialog<List<RaceCol
|
||||
this.existingRaces = existingRaces;
|
||||
this.stringMessages = stringMessages;
|
||||
addRacesListBox = createListBox(false);
|
||||
addRacesListBox.ensureDebugId("AddRacesListBox");
|
||||
raceNamePrefixTextBox = createTextBox(null);
|
||||
raceNameEntryFields = new ArrayList<TextBox>();
|
||||
isMedalRaceCheckboxes = new ArrayList<CheckBox>();
|
||||
@@ -135,6 +136,7 @@ public class RaceColumnsInLeaderboardDialog extends DataEntryDialog<List<RaceCol
|
||||
raceNamePrefixTextBox.setWidth("20px");
|
||||
addRacesPanel.add(raceNamePrefixTextBox);
|
||||
addRacesBtn = new Button(stringMessages.add());
|
||||
addRacesBtn.ensureDebugId("AddRacesButton");
|
||||
addRacesBtn.addStyleName("inlineButton");
|
||||
addRacesBtn.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
|
||||
+1
@@ -288,6 +288,7 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
|
||||
Label racesFilterLabel = new Label(stringMessages.filterRacesByName() + ":");
|
||||
AdminConsoleTableResources tableResources = GWT.create(AdminConsoleTableResources.class);
|
||||
racesTable = new CellTable<TracTracRaceRecordDTO>(10000, tableResources);
|
||||
racesTable.ensureDebugId("RacesTable");
|
||||
this.racesFilterablePanel = new LabeledAbstractFilterablePanel<TracTracRaceRecordDTO>(racesFilterLabel, availableTracTracRaces, racesTable, raceList) {
|
||||
@Override
|
||||
public List<String> getSearchableStrings(TracTracRaceRecordDTO t) {
|
||||
|
||||
+1
-1
@@ -102,7 +102,7 @@ public class TrackedRacesListComposite extends AbstractTrackedRacesListComposite
|
||||
@Override
|
||||
protected void addControlButtons(HorizontalPanel trackedRacesButtonPanel) {
|
||||
btnRemoveRace = new Button(stringMessages.remove());
|
||||
btnRemoveRace.ensureDebugId("RemoveRave");
|
||||
btnRemoveRace.ensureDebugId("RemoveRace");
|
||||
btnRemoveRace.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
|
||||
+12
-8
@@ -7,6 +7,7 @@ import java.util.Map;
|
||||
import com.google.gwt.i18n.client.NumberFormat;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.gwt.ui.adminconsole.DateAndTimeFormatterUtil;
|
||||
import com.sap.sailing.gwt.ui.client.Timer.PlayModes;
|
||||
import com.sap.sailing.gwt.ui.client.Timer.PlayStates;
|
||||
import com.sap.sailing.gwt.ui.client.shared.components.SettingsDialogComponent;
|
||||
@@ -29,17 +30,20 @@ public class RaceTimePanel extends TimePanel<RaceTimePanelSettings> implements R
|
||||
}
|
||||
|
||||
/**
|
||||
* If the race's start time is already known and the <code>time</code> is before the start, append a count-down to the label
|
||||
* If the race's start time is already known and the <code>time</code> is before the start we can set the count-down label
|
||||
*/
|
||||
@Override
|
||||
protected String getTimeLabelText(Date time) {
|
||||
final String result;
|
||||
protected String getTimeToStartLabelText(Date time) {
|
||||
String result = null;
|
||||
RaceTimesInfoDTO selectedRaceTimes = raceTimesInfoProvider.getRaceTimesInfo(selectedRace);
|
||||
if (selectedRaceTimes.startOfRace != null && time.before(selectedRaceTimes.startOfRace)) {
|
||||
result = super.getTimeLabelText(time) + ", " + stringMessages.countDownInMillis(
|
||||
NumberFormat.getFormat("0.00").format(((double) selectedRaceTimes.startOfRace.getTime()-time.getTime()) / 1000.));
|
||||
} else {
|
||||
result = super.getTimeLabelText(time);
|
||||
if (selectedRaceTimes.startOfRace != null) {
|
||||
if(time.before(selectedRaceTimes.startOfRace)) {
|
||||
String timeToStartInSeconds = NumberFormat.getFormat("0.0").format(((double) selectedRaceTimes.startOfRace.getTime()-time.getTime()) / 1000.) + "s";
|
||||
result = stringMessages.timeToStart(timeToStartInSeconds);
|
||||
} else if(time.after(selectedRaceTimes.startOfRace)) {
|
||||
long timeSinceStartInMs = time.getTime() - selectedRaceTimes.startOfRace.getTime();
|
||||
result = stringMessages.timeSinceStart(DateAndTimeFormatterUtil.formatElapsedTime(timeSinceStartInMs));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
+2
-1
@@ -941,7 +941,8 @@ public interface StringMessages extends Messages {
|
||||
String importWindFromIgtimi();
|
||||
String errorImportingIgtimiWind(String message);
|
||||
String resultFromIgtimiWindImport(String string);
|
||||
String countDownInMillis(String timeToStartInFractionalSeconds);
|
||||
String timeToStart(String timeToStart);
|
||||
String timeSinceStart(String timeSince);
|
||||
String distanceToLine();
|
||||
String beatAngleTooltip();
|
||||
String beatAngle();
|
||||
|
||||
+2
-1
@@ -930,7 +930,8 @@ seeIgtimiTabForAccountSettings=See the ''Igtimi'' tab for account settings deter
|
||||
importWindFromIgtimi=Import Wind from Igtimi
|
||||
errorImportingIgtimiWind=Error importing wind data from Igtimi: {0}
|
||||
resultFromIgtimiWindImport=The following number of fixes were imported for the listed races: {0}
|
||||
countDownInMillis={0}s to start
|
||||
timeToStart={0} to start
|
||||
timeSinceStart={0} since start
|
||||
distanceToLine=Distance to start line
|
||||
beatAngleTooltip=The angle between the competitors direction and the wind
|
||||
beatAngle=Beat Angle
|
||||
|
||||
+2
-1
@@ -926,7 +926,8 @@ seeIgtimiTabForAccountSettings=Siehe den ''Igtimi'' Reiter für die Einstellunge
|
||||
importWindFromIgtimi=Wind von Igtimi importieren
|
||||
errorImportingIgtimiWind=Fehler beim Importieren von Wind-Daten von Igtimi: {0}
|
||||
resultFromIgtimiWindImport=Die folgenden Anzahlen von Windmessungen wurden für die aufgelisteten Wettfahrten importiert: {0}
|
||||
countDownInMillis={0}s bis zum Start
|
||||
timeToStart={0} bis zum Start
|
||||
timeSinceStart={0} seit dem Start
|
||||
distanceToLine=Abstand zur Startlinie
|
||||
beatAngleTooltip=Der Winkel zwischen Windrichtung und Fahrtrichtung des Teilnehmers
|
||||
beatAngle=Winkel zum Wind
|
||||
|
||||
+22
-3
@@ -47,6 +47,8 @@ public class TimePanel<T extends TimePanelSettings> extends SimplePanel implemen
|
||||
private final Label timeDelayLabel;
|
||||
private final Label timeLabel;
|
||||
private final Label dateLabel;
|
||||
private final Label timeToStartLabel;
|
||||
private final FlowPanel timeToStartControlPanel;
|
||||
private final Label playModeLabel;
|
||||
protected final TimeSlider timeSlider;
|
||||
private final Button backToLivePlayButton;
|
||||
@@ -186,10 +188,15 @@ public class TimePanel<T extends TimePanelSettings> extends SimplePanel implemen
|
||||
timeControlPanel.add(dateLabel);
|
||||
timeControlPanel.add(timeLabel);
|
||||
|
||||
dateLabel.getElement().getStyle().setFloat(Style.Float.LEFT);
|
||||
dateLabel.getElement().setClassName("dateLabel");
|
||||
timeLabel.getElement().getStyle().setFloat(Style.Float.LEFT);
|
||||
timeLabel.getElement().setClassName("timeLabel");
|
||||
|
||||
// time to start control
|
||||
timeToStartControlPanel = new FlowPanel();
|
||||
timeToStartControlPanel.setStyleName("timePanel-controls-timeToStart");
|
||||
timeToStartLabel = new Label();
|
||||
timeToStartControlPanel.add(timeToStartLabel);
|
||||
timeToStartLabel.getElement().setClassName("timeToStartLabel");
|
||||
|
||||
FlowPanel playModeControlPanel = new FlowPanel();
|
||||
playModeControlPanel.setStyleName("timePanel-controls-playmode");
|
||||
@@ -276,11 +283,11 @@ public class TimePanel<T extends TimePanelSettings> extends SimplePanel implemen
|
||||
setWidget(timePanelInnerWrapper);
|
||||
playStateChanged(timer.getPlayState(), timer.getPlayMode());
|
||||
|
||||
|
||||
controlsPanel.add(playSpeedControlPanel);
|
||||
controlsPanel.add(playModeControlPanel );
|
||||
controlsPanel.add(timeDelayPanel);
|
||||
controlsPanel.add(timeControlPanel);
|
||||
controlsPanel.add(timeToStartControlPanel);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -309,6 +316,18 @@ public class TimePanel<T extends TimePanelSettings> extends SimplePanel implemen
|
||||
}
|
||||
dateLabel.setText(getDateLabelText(time));
|
||||
timeLabel.setText(getTimeLabelText(time));
|
||||
String timeToStartLabelText = getTimeToStartLabelText(time);
|
||||
if(timeToStartLabelText != null && !timeToStartLabelText.isEmpty()) {
|
||||
timeToStartControlPanel.setVisible(true);
|
||||
timeToStartLabel.setText(getTimeToStartLabelText(time));
|
||||
} else {
|
||||
timeToStartControlPanel.setVisible(false);
|
||||
timeToStartLabel.setText("");
|
||||
}
|
||||
}
|
||||
|
||||
protected String getTimeToStartLabelText(Date time) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected String getTimeLabelText(Date time) {
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package com.sap.sailing.gwt.ui.client.shared.racemap;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.gwt.ui.shared.racemap.BoatClassVectorGraphics;
|
||||
import com.sap.sailing.gwt.ui.shared.racemap.Extreme40VectorGraphics;
|
||||
import com.sap.sailing.gwt.ui.shared.racemap.LaserVectorGraphics;
|
||||
import com.sap.sailing.gwt.ui.shared.racemap.SmallMultihullVectorGraphics;
|
||||
import com.sap.sailing.gwt.ui.shared.racemap._49erVectorGraphics;
|
||||
|
||||
/**
|
||||
* A resolver utility for finding a suitable vector graphics for a given boat class
|
||||
* @author Frank Mittag (C5163874)
|
||||
*/
|
||||
public class BoatClassVectorGraphicsResolver {
|
||||
private static Map<String, BoatClassVectorGraphics> boatVectorGraphicsMap;
|
||||
private static Map<String, BoatClassVectorGraphics> compatibleBoatVectorGraphicsMap;
|
||||
private static BoatClassVectorGraphics defaultBoatVectorGraphics;
|
||||
|
||||
static {
|
||||
boatVectorGraphicsMap = new HashMap<String, BoatClassVectorGraphics>();
|
||||
compatibleBoatVectorGraphicsMap = new HashMap<String, BoatClassVectorGraphics>();
|
||||
|
||||
BoatClassVectorGraphics laser = new LaserVectorGraphics("470", "470er");
|
||||
BoatClassVectorGraphics _49er = new _49erVectorGraphics("49erFX", "49FX");
|
||||
BoatClassVectorGraphics extreme40 = new Extreme40VectorGraphics("Extreme");
|
||||
BoatClassVectorGraphics smallMultihull = new SmallMultihullVectorGraphics("Nacra 17", "Formula 16", "Formula 18",
|
||||
"Hobie Wild Cat", "Hobie Tiger", "A-Catamaran", "Tornado");
|
||||
|
||||
defaultBoatVectorGraphics = laser;
|
||||
boatVectorGraphicsMap.put(laser.getMainBoatClassName(), laser);
|
||||
boatVectorGraphicsMap.put(_49er.getMainBoatClassName(), _49er);
|
||||
boatVectorGraphicsMap.put(extreme40.getMainBoatClassName(), extreme40);
|
||||
boatVectorGraphicsMap.put(smallMultihull.getMainBoatClassName(), smallMultihull);
|
||||
}
|
||||
|
||||
public static BoatClassVectorGraphics resolveBoatClassVectorGraphics(String boatClassName) {
|
||||
BoatClassVectorGraphics result = defaultBoatVectorGraphics;
|
||||
if(boatVectorGraphicsMap.containsKey(boatClassName)) {
|
||||
result = boatVectorGraphicsMap.get(boatClassName);
|
||||
} else if (compatibleBoatVectorGraphicsMap.containsKey(boatClassName)) {
|
||||
result = compatibleBoatVectorGraphicsMap.get(boatClassName);
|
||||
} else {
|
||||
// now try to find compatible boat class images
|
||||
for(BoatClassVectorGraphics boatClassImageData: boatVectorGraphicsMap.values()) {
|
||||
if(boatClassImageData.isBoatClassNameCompatible(boatClassName)) {
|
||||
result = boatClassImageData;
|
||||
compatibleBoatVectorGraphicsMap.put(boatClassName, boatClassImageData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+47
-49
@@ -1,15 +1,19 @@
|
||||
package com.sap.sailing.gwt.ui.client.shared.racemap;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gwt.maps.client.MapWidget;
|
||||
import com.google.gwt.maps.client.base.LatLng;
|
||||
import com.google.gwt.maps.client.base.LatLngBounds;
|
||||
import com.google.gwt.maps.client.base.Point;
|
||||
import com.google.gwt.maps.client.base.Size;
|
||||
import com.google.gwt.maps.client.geometrylib.SphericalUtils;
|
||||
import com.sap.sailing.domain.common.Color;
|
||||
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;
|
||||
import com.sap.sailing.gwt.ui.shared.GPSFixDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.SpeedWithBearingDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.racemap.BoatClassVectorGraphics;
|
||||
import com.sap.sailing.gwt.ui.shared.racemap.CanvasOverlayV3;
|
||||
|
||||
/**
|
||||
@@ -33,25 +37,35 @@ public class BoatOverlay extends CanvasOverlayV3 {
|
||||
*/
|
||||
private static double ORIGINAL_BOAT_IMAGE_ROTATIION_ANGLE = 90.0;
|
||||
|
||||
private final BoatClassImageData boatClassImageData;
|
||||
private int canvasWidth;
|
||||
private int canvasHeight;
|
||||
|
||||
public BoatOverlay(final MapWidget map, int zIndex, final CompetitorDTO competitorDTO) {
|
||||
private Color color;
|
||||
|
||||
private Map<Integer, Pair<Double, Size>> boatScaleAndSizePerZoomCache;
|
||||
|
||||
private final BoatClassVectorGraphics boatVectorGraphics;
|
||||
|
||||
public BoatOverlay(final MapWidget map, int zIndex, final CompetitorDTO competitorDTO, Color color) {
|
||||
super(map, zIndex);
|
||||
this.boatClass = competitorDTO.getBoatClass();
|
||||
this.boatClassImageData = BoatClassImageDataResolver.resolveBoatClassImages(boatClass.getName());
|
||||
this.color = color;
|
||||
|
||||
boatScaleAndSizePerZoomCache = new HashMap<Integer, Pair<Double,Size>>();
|
||||
boatVectorGraphics = BoatClassVectorGraphicsResolver.resolveBoatClassVectorGraphics(boatClass.getName());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void draw() {
|
||||
if (mapProjection != null && boatFix != null) {
|
||||
ImageTransformer boatImageTransformer;
|
||||
if (boatFix.legType != null) {
|
||||
boatImageTransformer = boatClassImageData.getBoatImageTransformerByLegTypeAndTack(boatFix.legType,
|
||||
boatFix.tack, isSelected());
|
||||
} else {
|
||||
boatImageTransformer = boatClassImageData.getBoatImageTransformerByTack(boatFix.tack, isSelected());
|
||||
// the possible zoom level range is 0 to 21 (zoom level 0 would show the whole world)
|
||||
int zoom = map.getZoom();
|
||||
Pair<Double, Size> boatScaleAndSize = boatScaleAndSizePerZoomCache.get(zoom);
|
||||
if (boatScaleAndSize == null) {
|
||||
boatScaleAndSize = getBoatScaleAndSize(boatClass);
|
||||
boatScaleAndSizePerZoomCache.put(zoom, boatScaleAndSize);
|
||||
}
|
||||
double realBoatSizeScaleFactor = getRealBoatSizeScaleFactor(boatImageTransformer.getImageSize());
|
||||
double boatSizeScaleFactor = boatScaleAndSize.getA();
|
||||
SpeedWithBearingDTO speedWithBearing = boatFix.speedWithBearing;
|
||||
if (speedWithBearing == null) {
|
||||
speedWithBearing = new SpeedWithBearingDTO(0, 0);
|
||||
@@ -60,7 +74,11 @@ public class BoatOverlay extends CanvasOverlayV3 {
|
||||
if (boatDrawingAngle < 0) {
|
||||
boatDrawingAngle += 360;
|
||||
}
|
||||
boatImageTransformer.drawToCanvas(getCanvas(), boatDrawingAngle, realBoatSizeScaleFactor);
|
||||
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());
|
||||
LatLng latLngPosition = LatLng.newInstance(boatFix.position.latDeg, boatFix.position.lngDeg);
|
||||
Point boatPositionInPx = mapProjection.fromLatLngToDivPixel(latLngPosition);
|
||||
setCanvasPosition(boatPositionInPx.getX() - getCanvas().getCoordinateSpaceWidth() / 2,
|
||||
@@ -76,42 +94,22 @@ public class BoatOverlay extends CanvasOverlayV3 {
|
||||
}
|
||||
this.boatFix = boatFix;
|
||||
}
|
||||
|
||||
public double getRealBoatSizeScaleFactor(Size imageSize) {
|
||||
// the possible zoom level range is 0 to 21 (zoom level 0 would show the whole world)
|
||||
int zoomLevel = map == null ? 1 : map.getZoom();
|
||||
int boatLengthInPixel = boatClassImageData.getBoatClassImageLengthInPx();
|
||||
double minScaleFactor = 0.45;
|
||||
double maxScaleFactor = 2.0;
|
||||
if (boatLengthInPixel > 50 && boatLengthInPixel <= 100) {
|
||||
minScaleFactor = 0.40;
|
||||
} else if (boatLengthInPixel > 100) {
|
||||
minScaleFactor = 0.33;
|
||||
}
|
||||
|
||||
double realBoatSizeScaleFactor = minScaleFactor;
|
||||
double hullLengthInMeters = boatClass.getHullLengthInMeters();
|
||||
// to scale the boats to a realistic size we need the length of the boat in pixel,
|
||||
// but it does not work to just take the image size, because the images for the different boat states can be different
|
||||
if (zoomLevel > 5) {
|
||||
LatLngBounds bounds = map.getBounds();
|
||||
if (bounds != null) {
|
||||
LatLng upperRight = bounds.getNorthEast();
|
||||
LatLng bottomLeft = bounds.getSouthWest();
|
||||
LatLng upperLeft = LatLng.newInstance(upperRight.getLatitude(), bottomLeft.getLongitude());
|
||||
double distXInMeters = SphericalUtils.computeDistanceBetween(upperLeft, upperRight);
|
||||
int widthInPixel = map.getElement().getClientWidth(); // check...
|
||||
double realBoatSizeInPixel = (widthInPixel * hullLengthInMeters) / distXInMeters;
|
||||
realBoatSizeScaleFactor = realBoatSizeInPixel / (double) boatLengthInPixel;
|
||||
if (realBoatSizeScaleFactor < minScaleFactor) {
|
||||
realBoatSizeScaleFactor = minScaleFactor;
|
||||
}
|
||||
if (realBoatSizeScaleFactor > maxScaleFactor) {
|
||||
realBoatSizeScaleFactor = maxScaleFactor;
|
||||
}
|
||||
}
|
||||
}
|
||||
public Pair<Double, Size> getBoatScaleAndSize(BoatClassDTO boatClass) {
|
||||
double minBoatLength = 25;
|
||||
|
||||
Size boatSizeInPixel = calculateBoundingBox(mapProjection,
|
||||
LatLng.newInstance(boatFix.position.latDeg, boatFix.position.lngDeg),
|
||||
boatVectorGraphics.getBoatLengthInMeters(), boatVectorGraphics.getBoatBeamInMeters());
|
||||
|
||||
return realBoatSizeScaleFactor;
|
||||
double boatLengthInPixel = boatSizeInPixel.getWidth();
|
||||
if(boatLengthInPixel < minBoatLength)
|
||||
boatLengthInPixel = minBoatLength;
|
||||
|
||||
// The coordinates of the canvas drawing methods are based on the 'centimeter' unit (1px = 1cm).
|
||||
// To calculate the display real boat size the scale factor from canvas units to the real
|
||||
double boatSizeScaleFactor = boatLengthInPixel / (boatVectorGraphics.getBoatLengthInMeters() * 100);
|
||||
|
||||
return new Pair<Double, Size>(boatSizeScaleFactor, Size.newInstance(boatLengthInPixel + boatLengthInPixel / 2.0, boatLengthInPixel + boatLengthInPixel / 2.0));
|
||||
}
|
||||
}
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
package com.sap.sailing.gwt.ui.client.shared.racemap;
|
||||
|
||||
import com.google.gwt.canvas.dom.client.Context2d;
|
||||
import com.google.gwt.canvas.dom.client.CssColor;
|
||||
import com.google.gwt.canvas.dom.client.TextMetrics;
|
||||
import com.google.gwt.maps.client.MapWidget;
|
||||
import com.google.gwt.maps.client.base.LatLng;
|
||||
import com.google.gwt.maps.client.base.Point;
|
||||
import com.sap.sailing.domain.common.Color;
|
||||
import com.sap.sailing.domain.common.dto.PositionDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.racemap.CanvasOverlayV3;
|
||||
|
||||
/**
|
||||
* A google map overlay based on a HTML5 canvas for drawing a competitor info on a map at a given position.
|
||||
*
|
||||
* @author Frank Mittag
|
||||
*/
|
||||
public class CompetitorInfoOverlay extends CanvasOverlayV3 {
|
||||
|
||||
/**
|
||||
* The text to display in the canvas
|
||||
*/
|
||||
private String infoText;
|
||||
|
||||
/**
|
||||
* The current GPS fix of the boat position of the competitor.
|
||||
*/
|
||||
private PositionDTO position;
|
||||
|
||||
private int canvasWidth;
|
||||
private int canvasHeight;
|
||||
private int infoBoxHeight = 20;
|
||||
|
||||
private Color competitorColor;
|
||||
|
||||
public CompetitorInfoOverlay(MapWidget map, int zIndex, Color competitorColor, String infoText) {
|
||||
super(map, zIndex);
|
||||
this.competitorColor = competitorColor;
|
||||
this.infoText = infoText;
|
||||
canvasWidth = 100;
|
||||
canvasHeight = 100;
|
||||
|
||||
setCanvasSize(canvasWidth, canvasHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void draw() {
|
||||
if (mapProjection != null && position != null) {
|
||||
LatLng latLngPosition = LatLng.newInstance(position.latDeg, position.lngDeg);
|
||||
Context2d ctx = getCanvas().getContext2d();
|
||||
CssColor grayTransparentColor = CssColor.make("rgba(255,255,255,0.75)");
|
||||
|
||||
ctx.setFont("12px bold Verdana sans-serif");
|
||||
TextMetrics measureText = ctx.measureText(infoText);
|
||||
double textWidth = measureText.getWidth();
|
||||
|
||||
canvasWidth = (int) textWidth + 10 + infoBoxHeight;
|
||||
setCanvasSize(canvasWidth, canvasHeight);
|
||||
|
||||
ctx.save();
|
||||
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
|
||||
|
||||
ctx.setLineWidth(1.0);
|
||||
ctx.setFillStyle(grayTransparentColor);
|
||||
if(competitorColor != null) {
|
||||
ctx.setStrokeStyle(competitorColor.getAsHtml());
|
||||
} else {
|
||||
ctx.setStrokeStyle("#888888");
|
||||
}
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(1.72,0.787);
|
||||
ctx.lineTo(0.543,0.787);
|
||||
ctx.lineTo(0.936,101);
|
||||
ctx.lineTo(0.936,101);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(1.0,1.0);
|
||||
ctx.lineTo(canvasWidth,1.0);
|
||||
ctx.lineTo(canvasWidth-infoBoxHeight,infoBoxHeight);
|
||||
ctx.lineTo(1.0,infoBoxHeight);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
// show a second measure
|
||||
// ctx.beginPath();
|
||||
// ctx.moveTo(1.0,26.4);
|
||||
// ctx.lineTo(66.2,26.4);
|
||||
// ctx.lineTo(53.1,39.3);
|
||||
// ctx.lineTo(1.0,39.3);
|
||||
// ctx.closePath();
|
||||
// ctx.fill();
|
||||
// ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.setFillStyle("black");
|
||||
ctx.fillText(infoText, 8, 14);
|
||||
ctx.stroke();
|
||||
|
||||
ctx.restore();
|
||||
|
||||
Point objectPositionInPx = mapProjection.fromLatLngToDivPixel(latLngPosition);
|
||||
setCanvasPosition(objectPositionInPx.getX(), objectPositionInPx.getY() - canvasHeight);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param position the new position of the overlay
|
||||
* @param timeForPositionTransitionMillis use -1 to not animate the position transition, e.g., during map zoom or non-play
|
||||
*/
|
||||
|
||||
public void setPosition(PositionDTO position, long timeForPositionTransitionMillis) {
|
||||
if (timeForPositionTransitionMillis == -1) {
|
||||
removeCanvasPositionTransition();
|
||||
} else {
|
||||
setCanvasPositionTransition(timeForPositionTransitionMillis);
|
||||
}
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the text to show
|
||||
*/
|
||||
public void setInfoText(String infoText) {
|
||||
this.infoText = infoText;
|
||||
}
|
||||
}
|
||||
+48
-24
@@ -1,16 +1,20 @@
|
||||
package com.sap.sailing.gwt.ui.client.shared.racemap;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gwt.canvas.dom.client.Context2d;
|
||||
import com.google.gwt.canvas.dom.client.CssColor;
|
||||
import com.google.gwt.canvas.dom.client.ImageData;
|
||||
import com.google.gwt.maps.client.MapWidget;
|
||||
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.MarkType;
|
||||
import com.sap.sailing.domain.common.dto.PositionDTO;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.gwt.ui.shared.MarkDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.racemap.CanvasOverlayV3;
|
||||
import com.sap.sailing.gwt.ui.shared.racemap.MarkVectorGraphics;
|
||||
|
||||
/**
|
||||
* A google map overlay based on a HTML5 canvas for drawing course marks (images) and the buoy zone if the mark is a buoy.
|
||||
@@ -28,35 +32,45 @@ public class CourseMarkOverlay extends CanvasOverlayV3 {
|
||||
|
||||
private boolean showBuoyZone;
|
||||
|
||||
private final MarkImageDescriptor markImageDescriptor;
|
||||
|
||||
private final ImageCanvas markImageCanvas;
|
||||
|
||||
private final int MIN_BUOYZONE_RADIUS_IN_PX = 25;
|
||||
|
||||
public CourseMarkOverlay(MapWidget map, int zIndex, final RaceMapImageManager raceMapImageManager, MarkDTO markDTO) {
|
||||
|
||||
private final MarkVectorGraphics markVectorGraphics;
|
||||
|
||||
private Map<Integer, Pair<Double, Size>> markScaleAndSizePerZoomCache;
|
||||
|
||||
public CourseMarkOverlay(MapWidget map, int zIndex, MarkDTO markDTO) {
|
||||
super(map, zIndex);
|
||||
this.mark = markDTO;
|
||||
this.position = markDTO.position;
|
||||
this.buoyZoneRadiusInMeter = 0.0;
|
||||
this.showBuoyZone = false;
|
||||
|
||||
markImageDescriptor = raceMapImageManager.resolveMarkImage(markDTO.type, markDTO.color, markDTO.shape, markDTO.pattern);
|
||||
markImageCanvas = new ImageCanvas(markImageDescriptor.getImgageResource());
|
||||
markVectorGraphics = new MarkVectorGraphics(markDTO.type, markDTO.color, markDTO.shape, markDTO.pattern);
|
||||
markScaleAndSizePerZoomCache = new HashMap<Integer, Pair<Double,Size>>();
|
||||
|
||||
setCanvasSize(50, 50);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void draw() {
|
||||
if (mapProjection != null && mark != null && position != null && markImageCanvas.isImageLoaded()) {
|
||||
if (mapProjection != null && mark != null && position != null) {
|
||||
int zoom = map.getZoom();
|
||||
|
||||
Pair<Double, Size> markScaleAndSize = markScaleAndSizePerZoomCache.get(zoom);
|
||||
if(markScaleAndSize == null) {
|
||||
markScaleAndSize = getMarkScaleAndSize(position);
|
||||
markScaleAndSizePerZoomCache.put(zoom, markScaleAndSize);
|
||||
}
|
||||
double markSizeScaleFactor = markScaleAndSize.getA();
|
||||
|
||||
getCanvas().setTitle(getTitle());
|
||||
|
||||
LatLng latLngPosition = LatLng.newInstance(position.latDeg, position.lngDeg);
|
||||
|
||||
// calculate canvas size
|
||||
Size imageSize = markImageCanvas.getImageSize();
|
||||
double canvasWidth = imageSize.getWidth();
|
||||
double canvasHeight = imageSize.getHeight();
|
||||
double canvasWidth = markScaleAndSize.getB().getWidth();
|
||||
double canvasHeight = markScaleAndSize.getB().getHeight();
|
||||
double buoyZoneRadiusInPixel = -1;
|
||||
if(showBuoyZone && mark.type == MarkType.BUOY) {
|
||||
buoyZoneRadiusInPixel = calculateRadiusOfBoundingBox(mapProjection, latLngPosition, buoyZoneRadiusInMeter);
|
||||
@@ -68,20 +82,14 @@ public class CourseMarkOverlay extends CanvasOverlayV3 {
|
||||
setCanvasSize((int) canvasWidth, (int) canvasHeight);
|
||||
|
||||
Context2d context2d = getCanvas().getContext2d();
|
||||
context2d.clearRect(0, 0, canvasWidth, canvasHeight);
|
||||
|
||||
// draw the course mark
|
||||
markImageCanvas.drawImage();
|
||||
ImageData imageData = markImageCanvas.getImageData();
|
||||
|
||||
markVectorGraphics.drawMarkToCanvas(context2d, showBuoyZone, canvasWidth, canvasHeight, markSizeScaleFactor);
|
||||
|
||||
Point buoyPositionInPx = mapProjection.fromLatLngToDivPixel(latLngPosition);
|
||||
Point markAnchorPoint = markImageDescriptor.getAnchorPoint();
|
||||
|
||||
// draw the buoy zone
|
||||
if(showBuoyZone && mark.type == MarkType.BUOY && buoyZoneRadiusInPixel > MIN_BUOYZONE_RADIUS_IN_PX) {
|
||||
context2d.putImageData(imageData, buoyZoneRadiusInPixel - markAnchorPoint.getX(),
|
||||
buoyZoneRadiusInPixel - markAnchorPoint.getY());
|
||||
|
||||
CssColor grayTransparentColor = CssColor.make("rgba(50,90,135,0.75)");
|
||||
|
||||
// this translation is important for drawing lines with a real line width of 1 pixel
|
||||
@@ -94,13 +102,29 @@ public class CourseMarkOverlay extends CanvasOverlayV3 {
|
||||
|
||||
setCanvasPosition(buoyPositionInPx.getX() - buoyZoneRadiusInPixel, buoyPositionInPx.getY() - buoyZoneRadiusInPixel);
|
||||
} else {
|
||||
context2d.putImageData(imageData, 0, 0);
|
||||
|
||||
setCanvasPosition(buoyPositionInPx.getX() - markAnchorPoint.getX(), buoyPositionInPx.getY() - markAnchorPoint.getY());
|
||||
setCanvasPosition(buoyPositionInPx.getX() - canvasWidth / 2.0, buoyPositionInPx.getY() - canvasHeight / 2.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Pair<Double, Size> getMarkScaleAndSize(PositionDTO markPosition) {
|
||||
double minMarkHeight = 25;
|
||||
|
||||
Size markSizeInPixel = calculateBoundingBox(mapProjection,
|
||||
LatLng.newInstance(markPosition.latDeg, markPosition.lngDeg),
|
||||
markVectorGraphics.getMarkWidthInMeters(), markVectorGraphics.getMarkHeightInMeters());
|
||||
|
||||
double markHeightInPixel = markSizeInPixel.getHeight();
|
||||
if(markHeightInPixel < minMarkHeight)
|
||||
markHeightInPixel = minMarkHeight;
|
||||
|
||||
// The coordinates of the canvas drawing methods are based on the 'centimeter' unit (1px = 1cm).
|
||||
// To calculate the display real mark size the scale factor from canvas units to the real
|
||||
double markSizeScaleFactor = markHeightInPixel / (markVectorGraphics.getMarkHeightInMeters() * 100);
|
||||
|
||||
return new Pair<Double, Size>(markSizeScaleFactor, Size.newInstance(markHeightInPixel * 2.0, markHeightInPixel * 2.0));
|
||||
}
|
||||
|
||||
private String getTitle() {
|
||||
return mark.getName();
|
||||
}
|
||||
|
||||
+45
-19
@@ -13,6 +13,7 @@ import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.gwt.canvas.dom.client.CssColor;
|
||||
import com.google.gwt.dom.client.Style;
|
||||
import com.google.gwt.i18n.client.NumberFormat;
|
||||
import com.google.gwt.maps.client.LoadApi;
|
||||
@@ -175,7 +176,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
/**
|
||||
* html5 canvases used for competitor info display on the map
|
||||
*/
|
||||
private final Map<CompetitorDTO, SmallTransparentInfoOverlay> competitorInfoOverlays;
|
||||
private final Map<CompetitorDTO, CompetitorInfoOverlay> competitorInfoOverlays;
|
||||
|
||||
private SmallTransparentInfoOverlay countDownOverlay;
|
||||
|
||||
@@ -277,7 +278,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
markDTOs = new HashMap<String, MarkDTO>();
|
||||
courseSidelines = new HashMap<SidelineDTO, Polygon>();
|
||||
boatOverlays = new HashMap<CompetitorDTO, BoatOverlay>();
|
||||
competitorInfoOverlays = new HashMap<CompetitorDTO, SmallTransparentInfoOverlay>();
|
||||
competitorInfoOverlays = new HashMap<CompetitorDTO, CompetitorInfoOverlay>();
|
||||
windSensorOverlays = new HashMap<WindSource, WindSensorOverlay>();
|
||||
courseMarkOverlays = new HashMap<String, CourseMarkOverlay>();
|
||||
this.competitorSelection = competitorSelection;
|
||||
@@ -364,7 +365,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
boatOverlay.removeCanvasPositionTransition();
|
||||
}
|
||||
// remove the canvas animations for the info overlays of the selected boats
|
||||
for(SmallTransparentInfoOverlay infoOverlay: competitorInfoOverlays.values()) {
|
||||
for(CompetitorInfoOverlay infoOverlay: competitorInfoOverlays.values()) {
|
||||
infoOverlay.removeCanvasPositionTransition();
|
||||
}
|
||||
}
|
||||
@@ -661,7 +662,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
if (fixesAndTails.hasFixesFor(competitorDTO)) {
|
||||
GPSFixDTO lastBoatFix = getBoatFix(competitorDTO, date);
|
||||
if (lastBoatFix != null) {
|
||||
SmallTransparentInfoOverlay competitorInfoOverlay = competitorInfoOverlays.get(competitorDTO);
|
||||
CompetitorInfoOverlay competitorInfoOverlay = competitorInfoOverlays.get(competitorDTO);
|
||||
if (competitorInfoOverlay == null) {
|
||||
competitorInfoOverlay = createCompetitorInfoOverlay(RaceMapOverlaysZIndexes.INFO_OVERLAY_ZINDEX, competitorDTO);
|
||||
competitorInfoOverlays.put(competitorDTO, competitorInfoOverlay);
|
||||
@@ -676,13 +677,13 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
}
|
||||
}
|
||||
for (CompetitorDTO toRemoveCompetorDTO : toRemoveCompetorInfoOverlays) {
|
||||
SmallTransparentInfoOverlay competitorInfoOverlay = competitorInfoOverlays.get(toRemoveCompetorDTO);
|
||||
CompetitorInfoOverlay competitorInfoOverlay = competitorInfoOverlays.get(toRemoveCompetorDTO);
|
||||
competitorInfoOverlay.removeFromMap();
|
||||
competitorInfoOverlays.remove(toRemoveCompetorDTO);
|
||||
}
|
||||
} else {
|
||||
// remove all overlays
|
||||
for (SmallTransparentInfoOverlay competitorInfoOverlay : competitorInfoOverlays.values()) {
|
||||
for (CompetitorInfoOverlay competitorInfoOverlay : competitorInfoOverlays.values()) {
|
||||
competitorInfoOverlay.removeFromMap();
|
||||
}
|
||||
competitorInfoOverlays.clear();
|
||||
@@ -708,6 +709,8 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
fixesAndTails.updateTail(tail, competitorDTO, tailsFromTime, tailsToTime,
|
||||
(int) (timeForPositionTransitionMillis==-1?-1:timeForPositionTransitionMillis/2));
|
||||
competitorDTOsOfUnusedTails.remove(competitorDTO);
|
||||
PolylineOptions newOptions = createTailStyle(competitorDTO, displayHighlighted(competitorDTO));
|
||||
tail.setOptions(newOptions);
|
||||
}
|
||||
boolean usedExistingBoatCanvas = updateBoatCanvasForCompetitor(competitorDTO, date,
|
||||
timeForPositionTransitionMillis);
|
||||
@@ -1059,10 +1062,10 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
}
|
||||
} else {
|
||||
final String countDownText = "-"+NumberFormat.getFormat("0.0").format(
|
||||
Math.round(((double) lastRaceTimesInfo.startOfRace.getTime() - timer.getTime().getTime()) / 100.)/10.);
|
||||
Math.round(((double) lastRaceTimesInfo.startOfRace.getTime() - timer.getTime().getTime()) / 100.)/10.) + "s";
|
||||
if (countDownOverlay == null) {
|
||||
countDownOverlay = new SmallTransparentInfoOverlay(map, RaceMapOverlaysZIndexes.INFO_OVERLAY_ZINDEX,
|
||||
countDownText, raceMapImageManager);
|
||||
countDownText);
|
||||
countDownOverlay.addToMap();
|
||||
} else {
|
||||
countDownOverlay.setInfoText(countDownText);
|
||||
@@ -1112,6 +1115,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
boatOverlay.draw();
|
||||
}
|
||||
}
|
||||
|
||||
return usedExistingCanvas;
|
||||
}
|
||||
|
||||
@@ -1120,7 +1124,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
}
|
||||
|
||||
protected CourseMarkOverlay createCourseMarkOverlay(int zIndex, final MarkDTO markDTO) {
|
||||
final CourseMarkOverlay courseMarkOverlay = new CourseMarkOverlay(map, zIndex, raceMapImageManager, markDTO);
|
||||
final CourseMarkOverlay courseMarkOverlay = new CourseMarkOverlay(map, zIndex, markDTO);
|
||||
courseMarkOverlay.addClickHandler(new ClickMapHandler() {
|
||||
@Override
|
||||
public void onEvent(ClickMapEvent event) {
|
||||
@@ -1131,14 +1135,13 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
return courseMarkOverlay;
|
||||
}
|
||||
|
||||
private SmallTransparentInfoOverlay createCompetitorInfoOverlay(int zIndex, final CompetitorDTO competitorDTO) {
|
||||
return new SmallTransparentInfoOverlay(map, zIndex,
|
||||
/* infoText */ (competitorDTO.getSailID() == null || competitorDTO.getSailID().isEmpty()) ? competitorDTO.getName() : competitorDTO.getSailID(),
|
||||
raceMapImageManager);
|
||||
private CompetitorInfoOverlay createCompetitorInfoOverlay(int zIndex, final CompetitorDTO competitorDTO) {
|
||||
String infoText = competitorDTO.getSailID() == null || competitorDTO.getSailID().isEmpty() ? competitorDTO.getName() : competitorDTO.getSailID();
|
||||
return new CompetitorInfoOverlay(map, zIndex, competitorSelection.getColor(competitorDTO), infoText);
|
||||
}
|
||||
|
||||
private BoatOverlay createBoatOverlay(int zIndex, final CompetitorDTO competitorDTO, boolean highlighted) {
|
||||
final BoatOverlay boatCanvas = new BoatOverlay(map, zIndex, competitorDTO);
|
||||
final BoatOverlay boatCanvas = new BoatOverlay(map, zIndex, competitorDTO, competitorSelection.getColor(competitorDTO));
|
||||
boatCanvas.setSelected(highlighted);
|
||||
boatCanvas.addClickHandler(new ClickMapHandler() {
|
||||
@Override
|
||||
@@ -1523,7 +1526,15 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
timeChanged(timer.getTime());
|
||||
}
|
||||
}
|
||||
//Trigger auto-zoom if needed
|
||||
// Now update tails for all competitors because selection change may also affect all unselected competitors
|
||||
for (CompetitorDTO oneOfAllCompetitors : competitorSelection.getAllCompetitors()) {
|
||||
Polyline tail = fixesAndTails.getTail(oneOfAllCompetitors);
|
||||
if (tail != null) {
|
||||
PolylineOptions newOptions = createTailStyle(oneOfAllCompetitors, displayHighlighted(oneOfAllCompetitors));
|
||||
tail.setOptions(newOptions);
|
||||
}
|
||||
}
|
||||
// Trigger auto-zoom if needed
|
||||
RaceMapZoomSettings zoomSettings = settings.getZoomSettings();
|
||||
if (!zoomSettings.containsZoomType(ZoomTypes.NONE) && zoomSettings.isZoomToSelectedCompetitors()) {
|
||||
zoomMapToNewBounds(zoomSettings.getNewBounds(this));
|
||||
@@ -1790,14 +1801,29 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
}
|
||||
|
||||
@Override
|
||||
public Polyline createTail(final CompetitorDTO competitor, List<LatLng> points) {
|
||||
public PolylineOptions createTailStyle(CompetitorDTO competitor, boolean isHighlighted) {
|
||||
PolylineOptions options = PolylineOptions.newInstance();
|
||||
options.setClickable(true);
|
||||
options.setGeodesic(true);
|
||||
options.setStrokeWeight(1);
|
||||
options.setStrokeOpacity(0.5);
|
||||
options.setStrokeColor(competitorSelection.getColor(competitor).getAsHtml());
|
||||
options.setStrokeOpacity(1.0);
|
||||
boolean noCompetitorSelected = Util.isEmpty(competitorSelection.getSelectedCompetitors());
|
||||
if (isHighlighted || noCompetitorSelected) {
|
||||
options.setStrokeColor(competitorSelection.getColor(competitor).getAsHtml());
|
||||
} else {
|
||||
options.setStrokeColor(CssColor.make(200, 200, 200).toString());
|
||||
}
|
||||
if (isHighlighted) {
|
||||
options.setStrokeWeight(2);
|
||||
} else {
|
||||
options.setStrokeWeight(1);
|
||||
}
|
||||
options.setZindex(RaceMapOverlaysZIndexes.BOATTAILS_ZINDEX);
|
||||
return options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Polyline createTail(final CompetitorDTO competitor, List<LatLng> points) {
|
||||
PolylineOptions options = createTailStyle(competitor, displayHighlighted(competitor));
|
||||
Polyline result = Polyline.newInstance(options);
|
||||
|
||||
MVCArray<LatLng> pointsAsArray = MVCArray.newInstance(points.toArray(new LatLng[0]));
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package com.sap.sailing.gwt.ui.client.shared.racemap;
|
||||
|
||||
/**
|
||||
* The base class for graphics of race supporters like umpires, race managers
|
||||
* camera boats, etc. based on SVG graphics drawn to a HTML5 canvas
|
||||
* @author Frank
|
||||
*
|
||||
*/
|
||||
public class RaceSupportersVectorGraphics {
|
||||
|
||||
}
|
||||
+4
-3
@@ -34,7 +34,7 @@ public class SmallTransparentInfoOverlay extends CanvasOverlayV3 {
|
||||
private int infoBoxWidth;
|
||||
private double cornerRadius;
|
||||
|
||||
public SmallTransparentInfoOverlay(MapWidget map, int zIndex, String infoText, RaceMapImageManager raceMapImageManager) {
|
||||
public SmallTransparentInfoOverlay(MapWidget map, int zIndex, String infoText) {
|
||||
super(map, zIndex);
|
||||
this.infoText = infoText;
|
||||
canvasWidth = 20;
|
||||
@@ -49,6 +49,8 @@ public class SmallTransparentInfoOverlay extends CanvasOverlayV3 {
|
||||
getCanvas().setCoordinateSpaceWidth(canvasWidth);
|
||||
getCanvas().setCoordinateSpaceHeight(canvasHeight);
|
||||
}
|
||||
|
||||
// setCanvasSize(canvasWidth, canvasHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -108,7 +110,7 @@ public class SmallTransparentInfoOverlay extends CanvasOverlayV3 {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param position the new psoition of the overlay
|
||||
* @param position the new position of the overlay
|
||||
* @param timeForPositionTransitionMillis use -1 to not animate the position transition, e.g., during map zoom or non-play
|
||||
*/
|
||||
|
||||
@@ -126,6 +128,5 @@ public class SmallTransparentInfoOverlay extends CanvasOverlayV3 {
|
||||
*/
|
||||
public void setInfoText(String infoText) {
|
||||
this.infoText = infoText;
|
||||
draw();
|
||||
}
|
||||
}
|
||||
+3
@@ -4,8 +4,11 @@ import java.util.List;
|
||||
|
||||
import com.google.gwt.maps.client.base.LatLng;
|
||||
import com.google.gwt.maps.client.overlays.Polyline;
|
||||
import com.google.gwt.maps.client.overlays.PolylineOptions;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
|
||||
public interface TailFactory {
|
||||
Polyline createTail(CompetitorDTO competitor, List<LatLng> points);
|
||||
|
||||
PolylineOptions createTailStyle(CompetitorDTO competitor, boolean isHighlighted);
|
||||
}
|
||||
+1
@@ -1403,6 +1403,7 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
|
||||
TOTAL_COLUMN_STYLE = tableResources.cellTableStyle().cellTableTotalColumn();
|
||||
leaderboardTable = new SortedCellTableWithStylableHeaders<LeaderboardRowDTO>(
|
||||
/* pageSize */10000, tableResources);
|
||||
leaderboardTable.ensureDebugId("LeaderboardTable");
|
||||
getLeaderboardTable().setWidth("100%");
|
||||
leaderboardSelectionModel = new MultiSelectionModel<LeaderboardRowDTO>();
|
||||
leaderboardSelectionModel.addSelectionChangeHandler(new Handler() {
|
||||
|
||||
+1
@@ -23,6 +23,7 @@ public class LeaderboardEditPage extends AbstractEntryPoint {
|
||||
logoAndTitlePanel.addStyleName("LogoAndTitlePanel");
|
||||
EditableLeaderboardPanel leaderboardPanel = new EditableLeaderboardPanel(sailingService, new AsyncActionsExecutor(), leaderboardName, null,
|
||||
LeaderboardEditPage.this, stringMessages, userAgent);
|
||||
leaderboardPanel.ensureDebugId("EditableLeaderboardPanel");
|
||||
RootPanel.get().add(logoAndTitlePanel);
|
||||
RootPanel.get().add(leaderboardPanel);
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -3623,7 +3623,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
@Override
|
||||
public Pair<Date, Integer> getStartTime(String leaderboardName, String raceColumnName, String fleetName) {
|
||||
Pair<TimePoint, Integer> result = getService().getStartTime(leaderboardName, raceColumnName, fleetName);
|
||||
if (result == null) {
|
||||
if (result == null || result.getA() == null) {
|
||||
return null;
|
||||
}
|
||||
return new Pair<Date, Integer>(result.getA().asDate(), result.getB());
|
||||
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
package com.sap.sailing.gwt.ui.shared.racemap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.canvas.dom.client.Context2d;
|
||||
import com.sap.sailing.domain.common.LegType;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
|
||||
/**
|
||||
* The base class for boat graphics based on SVG graphics drawn to a HTML5 canvas.
|
||||
* The drawing of the graphics is implemented as a list of graphics command on the Context2D,
|
||||
* We created the drawing commands not manually but used a SVG graphics with a well defined scale as a basis in combination
|
||||
* with a tool which translates this SVG graphics into the list of drawing commands.
|
||||
* See http://wiki.sapsailing.com/wiki/boatgraphicssvg for further details.
|
||||
*
|
||||
* @author Frank
|
||||
*
|
||||
*/
|
||||
public abstract class BoatClassVectorGraphics {
|
||||
protected double boatLengthInMeters;
|
||||
protected double boatBeamInMeters;
|
||||
protected double boatCenterAlongLengthInMeters;
|
||||
|
||||
private final String mainBoatClassName;
|
||||
private final List<String> compatibleBoatClassNames;
|
||||
|
||||
protected final String SAIL_FILLCOLOR = "#555555";
|
||||
protected final String SAIL_STROKECOLOR = "#000000";
|
||||
|
||||
BoatClassVectorGraphics(String mainBoatClassName, double boatLengthInMeters, double boatBeamInMeters, double boatCenterAlongLengthInMeters) {
|
||||
this.mainBoatClassName = mainBoatClassName;
|
||||
this.boatLengthInMeters = boatLengthInMeters;
|
||||
this.boatBeamInMeters = boatBeamInMeters;
|
||||
this.boatCenterAlongLengthInMeters = boatCenterAlongLengthInMeters;
|
||||
this.compatibleBoatClassNames = new ArrayList<String>();
|
||||
}
|
||||
|
||||
BoatClassVectorGraphics(String mainBoatClassName, double boatLengthInMeters, double boatBeamInMeters, double boatCenterAlongLengthInMeters,
|
||||
String...compatibleBoatClassNames) {
|
||||
this(mainBoatClassName, boatLengthInMeters, boatBeamInMeters, boatCenterAlongLengthInMeters);
|
||||
for(String compatibleBoatClass: compatibleBoatClassNames) {
|
||||
this.compatibleBoatClassNames.add(compatibleBoatClass);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void drawBoat(Context2d ctx, boolean isSelected, String color);
|
||||
|
||||
protected abstract void drawDownwindPortTackSails(Context2d ctx);
|
||||
|
||||
protected abstract void drawDownwindStarboardTackSails(Context2d ctx);
|
||||
|
||||
protected abstract void drawUpwindPortTackSails(Context2d ctx);
|
||||
|
||||
protected abstract void drawUpwindStarboardTackSails(Context2d ctx);
|
||||
|
||||
protected abstract void drawReachingPortTackSails(Context2d ctx);
|
||||
|
||||
protected abstract void drawReachingStarboardTackSails(Context2d ctx);
|
||||
|
||||
protected abstract void drawUnknownLegTypeStarboardTackSails(Context2d ctx);
|
||||
|
||||
protected abstract void drawUnknownLegTypePortTackSails(Context2d ctx);
|
||||
|
||||
protected abstract void drawKillingSails(Context2d ctx);
|
||||
|
||||
protected void drawSails(Context2d ctx, LegType legType, Tack tack) {
|
||||
if(tack != null && legType != null) {
|
||||
ctx.setFillStyle(SAIL_FILLCOLOR);
|
||||
ctx.setStrokeStyle(SAIL_STROKECOLOR);
|
||||
|
||||
switch (tack) {
|
||||
case PORT:
|
||||
switch (legType) {
|
||||
case DOWNWIND:
|
||||
drawDownwindPortTackSails(ctx);
|
||||
break;
|
||||
case REACHING:
|
||||
drawReachingPortTackSails(ctx);
|
||||
break;
|
||||
case UPWIND:
|
||||
drawUpwindPortTackSails(ctx);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STARBOARD:
|
||||
switch (legType) {
|
||||
case DOWNWIND:
|
||||
drawDownwindStarboardTackSails(ctx);
|
||||
break;
|
||||
case REACHING:
|
||||
drawReachingStarboardTackSails(ctx);
|
||||
break;
|
||||
case UPWIND:
|
||||
drawUpwindStarboardTackSails(ctx);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void drawBoatToCanvas(Context2d ctx, LegType legType, Tack tack, boolean isSelected,
|
||||
double width, double height, double angleInDegrees, double scaleFactor, String color) {
|
||||
|
||||
ctx.save();
|
||||
|
||||
double angleInRadians = angleInDegrees / 180.0 * Math.PI;
|
||||
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
|
||||
ctx.translate(width / 2.0, height / 2.0);
|
||||
ctx.rotate(angleInRadians);
|
||||
ctx.scale(scaleFactor, scaleFactor);
|
||||
ctx.translate(-boatCenterAlongLengthInMeters * 100,- boatBeamInMeters * 100 / 2.0);
|
||||
|
||||
drawBoat(ctx, isSelected, color);
|
||||
drawSails(ctx, legType, tack);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
public double getBoatLengthInMeters() {
|
||||
return boatLengthInMeters;
|
||||
}
|
||||
|
||||
public double getBoatBeamInMeters() {
|
||||
return boatBeamInMeters;
|
||||
}
|
||||
|
||||
public double getBoatCenterAlongLengthInMeters() {
|
||||
return boatCenterAlongLengthInMeters;
|
||||
}
|
||||
|
||||
public boolean isBoatClassNameCompatible(String boatClass) {
|
||||
boolean result = false;
|
||||
// remove all white space characters
|
||||
String boatClassToCheck = boatClass.replaceAll("\\s","");
|
||||
// remove all '-' characters
|
||||
boatClassToCheck = boatClass.replaceAll("-","");
|
||||
|
||||
if(mainBoatClassName.equalsIgnoreCase(boatClassToCheck)) {
|
||||
result = true;
|
||||
} else {
|
||||
for(String compatibleName: compatibleBoatClassNames) {
|
||||
if(compatibleName.equalsIgnoreCase(boatClassToCheck)) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getMainBoatClassName() {
|
||||
return mainBoatClassName;
|
||||
}
|
||||
|
||||
public List<String> getCompatibleBoatClassNames() {
|
||||
return compatibleBoatClassNames;
|
||||
}
|
||||
|
||||
}
|
||||
+16
@@ -16,6 +16,7 @@ import com.google.gwt.event.shared.HandlerRegistration;
|
||||
import com.google.gwt.maps.client.MapWidget;
|
||||
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.google.gwt.maps.client.events.click.ClickEventFormatter;
|
||||
import com.google.gwt.maps.client.events.click.ClickMapHandler;
|
||||
import com.google.gwt.maps.client.events.dblclick.DblClickEventFormatter;
|
||||
@@ -319,6 +320,21 @@ public abstract class CanvasOverlayV3 {
|
||||
|
||||
return Math.min(diffX, diffY);
|
||||
}
|
||||
|
||||
protected Size calculateBoundingBox(MapCanvasProjection projection, LatLng position, double distanceXInMeter, double distanceYInMeter) {
|
||||
Position pos = new DegreePosition(position.getLatitude(), position.getLongitude());
|
||||
Position translateRhumbX = pos.translateRhumb(new DegreeBearingImpl(90), new MeterDistance(distanceXInMeter));
|
||||
Position translateRhumbY = pos.translateRhumb(new DegreeBearingImpl(0), new MeterDistance(distanceYInMeter));
|
||||
|
||||
LatLng posWithDistanceX = LatLng.newInstance(translateRhumbX.getLatDeg(), translateRhumbX.getLngDeg());
|
||||
LatLng posWithDistanceY = LatLng.newInstance(translateRhumbY.getLatDeg(), translateRhumbY.getLngDeg());
|
||||
|
||||
Point pointCenter = projection.fromLatLngToDivPixel(position);
|
||||
Point pointX = projection.fromLatLngToDivPixel(posWithDistanceX);
|
||||
Point pointY = projection.fromLatLngToDivPixel(posWithDistanceY);
|
||||
|
||||
return Size.newInstance(Math.abs(pointX.getX() - pointCenter.getX()), Math.abs(pointY.getY() - pointCenter.getY()));
|
||||
}
|
||||
|
||||
protected void setCanvasSize(int newWidthInPx, int newHeightInPx) {
|
||||
if (getCanvas() != null) {
|
||||
|
||||
+260
@@ -0,0 +1,260 @@
|
||||
package com.sap.sailing.gwt.ui.shared.racemap;
|
||||
|
||||
import com.google.gwt.canvas.dom.client.Context2d;
|
||||
import com.google.gwt.canvas.dom.client.Context2d.LineJoin;
|
||||
|
||||
public class Extreme40VectorGraphics extends BoatClassVectorGraphics {
|
||||
|
||||
public Extreme40VectorGraphics(String... compatibleBoatClassNames) {
|
||||
super("EXTREME40", 16.0, 7.6, 6.1, compatibleBoatClassNames);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawBoat(Context2d ctx, boolean isSelected, String color) {
|
||||
// outer net
|
||||
if(isSelected) {
|
||||
ctx.setFillStyle(color);
|
||||
ctx.setStrokeStyle(color);
|
||||
} else {
|
||||
ctx.setFillStyle ("#FFFFFF");
|
||||
ctx.setStrokeStyle("#FFFFFF");
|
||||
}
|
||||
ctx.setLineWidth(1.0);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(195,72);
|
||||
ctx.lineTo(744,72);
|
||||
ctx.quadraticCurveTo(744,72,744,72);
|
||||
ctx.lineTo(744,622);
|
||||
ctx.quadraticCurveTo(744,622,744,622);
|
||||
ctx.lineTo(195,622);
|
||||
ctx.quadraticCurveTo(195,622,195,622);
|
||||
ctx.lineTo(195,72);
|
||||
ctx.quadraticCurveTo(195,72,195,72);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
// inner net
|
||||
if(isSelected) {
|
||||
ctx.setFillStyle("#FFFFFF");
|
||||
ctx.setStrokeStyle("#FFFFFF");
|
||||
} else {
|
||||
ctx.setFillStyle(color);
|
||||
ctx.setStrokeStyle(color);
|
||||
}
|
||||
ctx.setLineWidth(1.0);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(271,163);
|
||||
ctx.lineTo(671,163);
|
||||
ctx.quadraticCurveTo(671,163,671,163);
|
||||
ctx.lineTo(671,543);
|
||||
ctx.quadraticCurveTo(671,543,671,543);
|
||||
ctx.lineTo(271,543);
|
||||
ctx.quadraticCurveTo(271,543,271,543);
|
||||
ctx.lineTo(271,163);
|
||||
ctx.quadraticCurveTo(271,163,271,163);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
// hull - left and right part
|
||||
if(isSelected) {
|
||||
ctx.setFillStyle(color);
|
||||
ctx.setStrokeStyle(color);
|
||||
} else {
|
||||
ctx.setFillStyle("#FFFFFF");
|
||||
ctx.setStrokeStyle("#000000");
|
||||
}
|
||||
ctx.setLineWidth(5.0);
|
||||
ctx.setLineJoin(LineJoin.ROUND);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(3.54,2);
|
||||
ctx.lineTo(801,2);
|
||||
ctx.lineTo(1170,37);
|
||||
ctx.lineTo(801,72);
|
||||
ctx.lineTo(3.54,72);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.setLineWidth(5.0);
|
||||
ctx.setLineJoin(LineJoin.ROUND);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(3.54,622);
|
||||
ctx.lineTo(798,622);
|
||||
ctx.lineTo(1170,657);
|
||||
ctx.lineTo(798,692);
|
||||
ctx.lineTo(3.54,692);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
// Ausleger
|
||||
ctx.setFillStyle("rgba(0, 0, 0, 0)");
|
||||
ctx.setStrokeStyle("rgba(0, 0, 0, 255)");
|
||||
ctx.setLineWidth(3.0);
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(1580,356);
|
||||
ctx.lineTo(747,356);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(1050,651);
|
||||
ctx.lineTo(1050,49);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(1170,37);
|
||||
ctx.lineTo(1580,356);
|
||||
ctx.lineTo(1170,657);
|
||||
ctx.lineTo(1170,657);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawDownwindPortTackSails(Context2d ctx) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(1580,355);
|
||||
ctx.lineTo(778,-229);
|
||||
ctx.bezierCurveTo(778,-229,1220,-175,1350,-47.6);
|
||||
ctx.bezierCurveTo(1490,81.4,1580,355,1580,355);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(1050,354);
|
||||
ctx.lineTo(791,183);
|
||||
ctx.bezierCurveTo(791,183,997,236,1030,277);
|
||||
ctx.bezierCurveTo(1070,314,1050,354,1050,354);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(744,355);
|
||||
ctx.lineTo(199,247);
|
||||
ctx.bezierCurveTo(199,247,542,185,646,238);
|
||||
ctx.bezierCurveTo(749,294,744,355,744,355);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.setFillStyle("rgba(0, 0, 0, 0)");
|
||||
ctx.setStrokeStyle("rgba(0, 0, 0, 255)");
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(479,675);
|
||||
ctx.lineTo(567,55.2);
|
||||
ctx.lineTo(780,-225);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawDownwindStarboardTackSails(Context2d ctx) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(744,357);
|
||||
ctx.lineTo(200,465);
|
||||
ctx.bezierCurveTo(200,465,542,527,646,474);
|
||||
ctx.bezierCurveTo(749,418,744,357,744,357);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(1050,359);
|
||||
ctx.lineTo(792,529);
|
||||
ctx.bezierCurveTo(792,529,998,476,1030,436);
|
||||
ctx.bezierCurveTo(1070,399,1050,359,1050,359);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(1580,360);
|
||||
ctx.lineTo(780,944);
|
||||
ctx.bezierCurveTo(780,944,1210,890,1340,763);
|
||||
ctx.bezierCurveTo(1490,634,1580,360,1580,360);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.setFillStyle("rgba(0, 0, 0, 0)");
|
||||
ctx.setStrokeStyle("rgba(0, 0, 0, 255)");
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(479,40.9);
|
||||
ctx.lineTo(567,661);
|
||||
ctx.lineTo(780,944);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawUpwindPortTackSails(Context2d ctx) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(1050,355);
|
||||
ctx.lineTo(751,307);
|
||||
ctx.bezierCurveTo(751,307,959,268,1010,293);
|
||||
ctx.bezierCurveTo(1070,303,1050,355,1050,355);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(745,357);
|
||||
ctx.lineTo(194,297);
|
||||
ctx.bezierCurveTo(194,297,529,205,637,249);
|
||||
ctx.bezierCurveTo(745,296,745,357,745,357);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawUpwindStarboardTackSails(Context2d ctx) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(1050,360);
|
||||
ctx.lineTo(751,408);
|
||||
ctx.bezierCurveTo(751,408,959,447,1010,422);
|
||||
ctx.bezierCurveTo(1070,412,1050,360,1050,360);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(744,358);
|
||||
ctx.lineTo(193,418);
|
||||
ctx.bezierCurveTo(193,418,528,510,636,466);
|
||||
ctx.bezierCurveTo(744,419,744,358,744,358);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawReachingPortTackSails(Context2d ctx) {
|
||||
drawUpwindPortTackSails(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawReachingStarboardTackSails(Context2d ctx) {
|
||||
drawUpwindStarboardTackSails(ctx);;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawUnknownLegTypeStarboardTackSails(Context2d ctx) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawUnknownLegTypePortTackSails(Context2d ctx) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawKillingSails(Context2d ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
package com.sap.sailing.gwt.ui.shared.racemap;
|
||||
|
||||
import com.google.gwt.canvas.dom.client.Context2d;
|
||||
|
||||
public class LaserVectorGraphics extends BoatClassVectorGraphics {
|
||||
|
||||
public LaserVectorGraphics(String... compatibleBoatClassNames) {
|
||||
super("LASER", 4.23, 1.37, 2.1, compatibleBoatClassNames);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawBoat(Context2d ctx, boolean isSelected, String color) {
|
||||
if(isSelected) {
|
||||
ctx.setFillStyle("#FF0000");
|
||||
} else {
|
||||
ctx.setFillStyle("#FFFFFF");
|
||||
}
|
||||
ctx.setStrokeStyle(color);
|
||||
ctx.setLineWidth(2.0);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(1.72,27);
|
||||
ctx.lineTo(1.44,105);
|
||||
ctx.bezierCurveTo(1.44,105,82.6,133,171,133);
|
||||
ctx.bezierCurveTo(258,133,422,81.5,422,70.1);
|
||||
ctx.bezierCurveTo(422,55.7,261,1.11,171,1.11);
|
||||
ctx.bezierCurveTo(85.8,1.11,1.72,27,1.72,27);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.setFillStyle(color);
|
||||
ctx.setStrokeStyle(color);
|
||||
ctx.setLineWidth(1.0);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(48.2,44.2);
|
||||
ctx.lineTo(47.9,90.1);
|
||||
ctx.bezierCurveTo(47.9,90.1,107,107,171,107);
|
||||
ctx.bezierCurveTo(235,107,354,78.7,354,70.1);
|
||||
ctx.bezierCurveTo(352,61.4,235,29.9,171,29.9);
|
||||
ctx.bezierCurveTo(109,29.9,48.2,44.2,48.2,44.2);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawDownwindPortTackSails(Context2d ctx) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(300,71.2);
|
||||
ctx.lineTo(182,312);
|
||||
ctx.bezierCurveTo(182,312,319,188,326,144);
|
||||
ctx.bezierCurveTo(332,99,300,71.2,300,71.2);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawDownwindStarboardTackSails(Context2d ctx) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(300,69.8);
|
||||
ctx.lineTo(182,-171);
|
||||
ctx.bezierCurveTo(182,-171,319,-47.0,326,-3.15);
|
||||
ctx.bezierCurveTo(332,41.6,300,69.8,300,69.8);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawUpwindPortTackSails(Context2d ctx) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(301, 71.4);
|
||||
ctx.lineTo(40.3, 134);
|
||||
ctx.bezierCurveTo(40.3, 134, 221, 149, 259, 126);
|
||||
ctx.bezierCurveTo(297, 102, 301, 71.4, 301, 71.4);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawUpwindStarboardTackSails(Context2d ctx) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(300, 68.9);
|
||||
ctx.lineTo(39.4, 5.94);
|
||||
ctx.bezierCurveTo(39.4, 5.94, 220, -9.1, 258, 13.9);
|
||||
ctx.bezierCurveTo(296, 37.9, 300, 68.9, 300, 68.9);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawReachingPortTackSails(Context2d ctx) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(301,72.1);
|
||||
ctx.lineTo(92.1,240);
|
||||
ctx.bezierCurveTo(92.1,240,269,186,294,149);
|
||||
ctx.bezierCurveTo(318,111,301,72.1,301,72.1);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawReachingStarboardTackSails(Context2d ctx) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(301, 70);
|
||||
ctx.lineTo(92.2, -97.1);
|
||||
ctx.bezierCurveTo(92.2, -97.1, 269, -43.6, 294, -6.7);
|
||||
ctx.bezierCurveTo(318, 31.1, 301, 70, 301, 70);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawUnknownLegTypeStarboardTackSails(Context2d ctx) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawUnknownLegTypePortTackSails(Context2d ctx) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawKillingSails(Context2d ctx) {
|
||||
}
|
||||
|
||||
}
|
||||
-78
@@ -1,78 +0,0 @@
|
||||
package com.sap.sailing.gwt.ui.shared.racemap;
|
||||
|
||||
import com.google.gwt.maps.client.overlays.MarkerImage;
|
||||
import com.sap.sailing.domain.common.MarkType;
|
||||
|
||||
/**
|
||||
* A descriptor class for display properties of a mark icon.
|
||||
*/
|
||||
public class MarkIconDescriptor {
|
||||
private final MarkerImage markerImage;
|
||||
private final String color;
|
||||
private final String shape;
|
||||
private final String pattern;
|
||||
private final MarkType type;
|
||||
|
||||
public MarkIconDescriptor(MarkerImage markerImage, MarkType type, String color, String shape, String pattern) {
|
||||
this.markerImage = markerImage;
|
||||
this.type = type;
|
||||
this.color = color;
|
||||
this.shape = shape;
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
public MarkerImage getMarkerImage() {
|
||||
return markerImage;
|
||||
}
|
||||
|
||||
public String getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public String getShape() {
|
||||
return shape;
|
||||
}
|
||||
|
||||
public String getPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
public MarkType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* An utility method to check if the mark icon has compatible display properties.
|
||||
* In case of null values at least one valid display property must exist and fit.
|
||||
*/
|
||||
public boolean isCompatible(MarkType typeToCheck, String colorToCheck, String shapeToCheck, String patternToCheck) {
|
||||
boolean result = false;
|
||||
|
||||
if((typeToCheck != null && type == null) || (typeToCheck == null && type != null)) {
|
||||
result = false;
|
||||
} else if(typeToCheck != null && type != null) {
|
||||
result = type == typeToCheck;
|
||||
}
|
||||
|
||||
if((colorToCheck != null && color == null) || (colorToCheck == null && color != null)) {
|
||||
result = false;
|
||||
} else if(colorToCheck != null && color != null) {
|
||||
result = color.equalsIgnoreCase(colorToCheck) ? true : false;
|
||||
}
|
||||
|
||||
if((shapeToCheck != null && shape == null) || (shapeToCheck == null && shape != null)) {
|
||||
result = false;
|
||||
} else if(shapeToCheck != null && shape != null) {
|
||||
result = shape.equalsIgnoreCase(shapeToCheck) ? true : false;
|
||||
}
|
||||
|
||||
if((patternToCheck != null && pattern == null) || (patternToCheck == null && pattern != null)) {
|
||||
result = false;
|
||||
} else if(patternToCheck != null && pattern != null) {
|
||||
result = pattern.equalsIgnoreCase(patternToCheck) ? true : false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
+503
@@ -0,0 +1,503 @@
|
||||
package com.sap.sailing.gwt.ui.shared.racemap;
|
||||
|
||||
import com.google.gwt.canvas.dom.client.Context2d;
|
||||
import com.sap.sailing.domain.common.MarkType;
|
||||
|
||||
/**
|
||||
* A class for course mark graphics based on SVG graphics drawn to a HTML5 canvas
|
||||
* @author Frank
|
||||
*
|
||||
*/
|
||||
public class MarkVectorGraphics {
|
||||
protected double markHeightInMeters;
|
||||
protected double markWidthInMeters;
|
||||
|
||||
private final String color;
|
||||
private final String shape;
|
||||
private final String pattern;
|
||||
private final MarkType type;
|
||||
|
||||
private static final double doublePi = 2 * Math.PI;
|
||||
|
||||
private double anchorPointX = 0.44;
|
||||
private double anchorPointY = 1.67;
|
||||
|
||||
private final static String DEFAULT_MARK_COLOR = "#f9ac00";
|
||||
private final static String DEFAULT_MARK_BG_COLOR = "#f0f0f0";
|
||||
|
||||
public MarkVectorGraphics(MarkType type, String color, String shape, String pattern) {
|
||||
this.type = type;
|
||||
this.color = color;
|
||||
this.shape = shape;
|
||||
this.pattern = pattern;
|
||||
this.markHeightInMeters = 2.1;
|
||||
this.markWidthInMeters = 1.5;
|
||||
}
|
||||
|
||||
public void drawMarkToCanvas(Context2d ctx, boolean isSelected,
|
||||
double width, double height, double scaleFactor) {
|
||||
|
||||
ctx.save();
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
|
||||
ctx.translate(width / 2.0, height / 2.0);
|
||||
ctx.scale(scaleFactor, scaleFactor);
|
||||
|
||||
ctx.translate(-anchorPointX * 100,- anchorPointY * 100);
|
||||
|
||||
String markColor = color != null ? color : DEFAULT_MARK_COLOR;
|
||||
drawMark(ctx, isSelected, markColor);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
protected void drawMark(Context2d ctx, boolean isSelected, String color) {
|
||||
switch(type) {
|
||||
case BUOY:
|
||||
if(shape != null) {
|
||||
if("Cylinder".equalsIgnoreCase(shape) && pattern != null && "Checkered".equalsIgnoreCase(pattern)) {
|
||||
drawBuoyWithFinishFlag(ctx, isSelected, color);
|
||||
} else if ("Conical".equalsIgnoreCase(shape)) {
|
||||
drawConicalBuoy(ctx, isSelected, color);
|
||||
} else {
|
||||
drawSimpleBuoy(ctx, isSelected, color);
|
||||
}
|
||||
} else {
|
||||
drawSimpleBuoy(ctx, isSelected, color);
|
||||
}
|
||||
break;
|
||||
case FINISHBOAT:
|
||||
drawFinishBoat(ctx, isSelected, color);
|
||||
break;
|
||||
case LANDMARK:
|
||||
drawLandmark(ctx, isSelected, color);
|
||||
break;
|
||||
case STARTBOAT:
|
||||
drawStartBoat(ctx, isSelected, color);
|
||||
break;
|
||||
case UMPIREBOAT:
|
||||
case CAMERABOAT:
|
||||
// umpire and camera boats are not course marks -> see TrackedAssetVectorGraphics
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected void drawSimpleBuoy(Context2d ctx, boolean isSelected, String color) {
|
||||
ctx.setStrokeStyle("rgba(0,0,0,0)");
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle(color);
|
||||
ctx.transform(12.5,0,0,12.5,-578,22.2);
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(49.7,12.8,2.66,0,doublePi,false);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle(DEFAULT_MARK_BG_COLOR);
|
||||
ctx.transform(12.5,0,0,12.5,-578,22.2);
|
||||
ctx.beginPath();
|
||||
ctx.arc(49.7,11.3,3.37,0,doublePi,false);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle(color);
|
||||
ctx.transform(12.5,0,0,12.5,-578,22.2);
|
||||
ctx.beginPath();
|
||||
ctx.arc(49.6,10.6,2.66,0,doublePi,false);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle(DEFAULT_MARK_BG_COLOR);
|
||||
ctx.transform(4.98,0,0,10.8,-205,50.4);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(50.8,9.84);
|
||||
ctx.lineTo(48.5,9.84);
|
||||
ctx.lineTo(48.5,1.44);
|
||||
ctx.lineTo(50.8,1.9);
|
||||
ctx.lineTo(50.8,9.84);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.transform(12.5,0,0,12.5,-570,22.2);
|
||||
ctx.save();
|
||||
ctx.setFillStyle(color);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(48.8,3.82);
|
||||
ctx.lineTo(48.8,-1.32);
|
||||
ctx.lineTo(57,1.05);
|
||||
ctx.lineTo(48.8,3.82);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle(DEFAULT_MARK_BG_COLOR);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(48.5,4.16);
|
||||
ctx.lineTo(48.5,-1.65);
|
||||
ctx.lineTo(57.8,1.03);
|
||||
ctx.lineTo(48.5,4.16);
|
||||
ctx.closePath();
|
||||
ctx.moveTo(49,-0.994);
|
||||
ctx.lineTo(49,3.47);
|
||||
ctx.lineTo(56.2,1.07);
|
||||
ctx.lineTo(49,-0.994);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
protected void drawBuoyWithFinishFlag(Context2d ctx, boolean isSelected, String color) {
|
||||
ctx.setStrokeStyle("rgba(0,0,0,0)");
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle(color);
|
||||
ctx.transform(12.5,0,0,12.5,-578,22.2);
|
||||
ctx.beginPath();
|
||||
ctx.arc(49.7,12.8,2.66,0,doublePi,false);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle(DEFAULT_MARK_BG_COLOR);
|
||||
ctx.transform(12.5,0,0,12.5,-578,22.2);
|
||||
ctx.beginPath();
|
||||
ctx.arc(49.7,11.3,3.37,0,doublePi,false);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle(color);
|
||||
ctx.transform(12.5,0,0,12.5,-578,22.2);
|
||||
ctx.beginPath();
|
||||
ctx.arc(49.6,10.6,2.66,0,doublePi,false);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle(DEFAULT_MARK_BG_COLOR);
|
||||
ctx.transform(4.98,0,0,10.8,-205,50.4);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(50.8,9.84);
|
||||
ctx.lineTo(48.5,9.84);
|
||||
ctx.lineTo(48.5,1.44);
|
||||
ctx.lineTo(50.8,1.9);
|
||||
ctx.lineTo(50.8,9.84);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle(DEFAULT_MARK_BG_COLOR);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(36.9,-0.5);
|
||||
ctx.lineTo(141.9,-0.5);
|
||||
ctx.quadraticCurveTo(141.9,-0.5,141.9,-0.5);
|
||||
ctx.lineTo(141.9,71.2);
|
||||
ctx.quadraticCurveTo(141.9,71.2,141.9,71.2);
|
||||
ctx.lineTo(36.9,71.2);
|
||||
ctx.quadraticCurveTo(36.9,71.2,36.9,71.2);
|
||||
ctx.lineTo(36.9,-0.5);
|
||||
ctx.quadraticCurveTo(36.9,-0.5,36.9,-0.5);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle(color);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(46,4.04);
|
||||
ctx.lineTo(76.3,4.04);
|
||||
ctx.quadraticCurveTo(76.3,4.04,76.3,4.04);
|
||||
ctx.lineTo(76.3,34.34);
|
||||
ctx.quadraticCurveTo(76.3,34.34,76.3,34.34);
|
||||
ctx.lineTo(46,34.34);
|
||||
ctx.quadraticCurveTo(46,34.34,46,34.34);
|
||||
ctx.lineTo(46,4.04);
|
||||
ctx.quadraticCurveTo(46,4.04,46,4.04);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle(DEFAULT_MARK_BG_COLOR);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(46.1,34.3);
|
||||
ctx.lineTo(76.4,34.3);
|
||||
ctx.quadraticCurveTo(76.4,34.3,76.4,34.3);
|
||||
ctx.lineTo(76.4,64.6);
|
||||
ctx.quadraticCurveTo(76.4,64.6,76.4,64.6);
|
||||
ctx.lineTo(46.1,64.6);
|
||||
ctx.quadraticCurveTo(46.1,64.6,46.1,64.6);
|
||||
ctx.lineTo(46.1,34.3);
|
||||
ctx.quadraticCurveTo(46.1,34.3,46.1,34.3);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle(DEFAULT_MARK_BG_COLOR);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(76,3.95);
|
||||
ctx.lineTo(106.3,3.95);
|
||||
ctx.quadraticCurveTo(106.3,3.95,106.3,3.95);
|
||||
ctx.lineTo(106.3,34.25);
|
||||
ctx.quadraticCurveTo(106.3,34.25,106.3,34.25);
|
||||
ctx.lineTo(76,34.25);
|
||||
ctx.quadraticCurveTo(76,34.25,76,34.25);
|
||||
ctx.lineTo(76,3.95);
|
||||
ctx.quadraticCurveTo(76,3.95,76,3.95);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle(color);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(76.1,34.2);
|
||||
ctx.lineTo(106.4,34.2);
|
||||
ctx.quadraticCurveTo(106.4,34.2,106.4,34.2);
|
||||
ctx.lineTo(106.4,64.5);
|
||||
ctx.quadraticCurveTo(106.4,64.5,106.4,64.5);
|
||||
ctx.lineTo(76.1,64.5);
|
||||
ctx.quadraticCurveTo(76.1,64.5,76.1,64.5);
|
||||
ctx.lineTo(76.1,34.2);
|
||||
ctx.quadraticCurveTo(76.1,34.2,76.1,34.2);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle(color);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(106,3.96);
|
||||
ctx.lineTo(136.3,3.96);
|
||||
ctx.quadraticCurveTo(136.3,3.96,136.3,3.96);
|
||||
ctx.lineTo(136.3,34.26);
|
||||
ctx.quadraticCurveTo(136.3,34.26,136.3,34.26);
|
||||
ctx.lineTo(106,34.26);
|
||||
ctx.quadraticCurveTo(106,34.26,106,34.26);
|
||||
ctx.lineTo(106,3.96);
|
||||
ctx.quadraticCurveTo(106,3.96,106,3.96);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle(DEFAULT_MARK_BG_COLOR);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(106,34.3);
|
||||
ctx.lineTo(136.3,34.3);
|
||||
ctx.quadraticCurveTo(136.3,34.3,136.3,34.3);
|
||||
ctx.lineTo(136.3,64.6);
|
||||
ctx.quadraticCurveTo(136.3,64.6,136.3,64.6);
|
||||
ctx.lineTo(106,64.6);
|
||||
ctx.quadraticCurveTo(106,64.6,106,64.6);
|
||||
ctx.lineTo(106,34.3);
|
||||
ctx.quadraticCurveTo(106,34.3,106,34.3);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
protected void drawLandmark(Context2d ctx, boolean isSelected, String color) {
|
||||
ctx.setStrokeStyle("rgba(0,0,0,0)");
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle(DEFAULT_MARK_BG_COLOR);
|
||||
ctx.transform(4.98,0,0,10.8,-205,50.4);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(50.8,9.84);
|
||||
ctx.lineTo(48.5,9.84);
|
||||
ctx.lineTo(48.5,1.44);
|
||||
ctx.lineTo(50.8,1.9);
|
||||
ctx.lineTo(50.8,9.84);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.transform(12.5,0,0,12.5,-570,22.2);
|
||||
ctx.save();
|
||||
ctx.setFillStyle(color);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(48.8,3.82);
|
||||
ctx.lineTo(48.8,-1.32);
|
||||
ctx.lineTo(57,1.05);
|
||||
ctx.lineTo(48.8,3.82);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle(DEFAULT_MARK_BG_COLOR);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(48.5,4.16);
|
||||
ctx.lineTo(48.5,-1.65);
|
||||
ctx.lineTo(57.8,1.03);
|
||||
ctx.lineTo(48.5,4.16);
|
||||
ctx.closePath();
|
||||
ctx.moveTo(49,-0.994);
|
||||
ctx.lineTo(49,3.47);
|
||||
ctx.lineTo(56.2,1.07);
|
||||
ctx.lineTo(49,-0.994);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle(color);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(83.9,209);
|
||||
ctx.bezierCurveTo(83.9,209,68.6,183,43.0,183);
|
||||
ctx.bezierCurveTo(12.3,183,7.1,209,7.1,209);
|
||||
ctx.lineTo(7.1,157);
|
||||
ctx.lineTo(83.9,157);
|
||||
ctx.lineTo(83.9,209);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
protected void drawConicalBuoy(Context2d ctx, boolean isSelected, String color) {
|
||||
ctx.setStrokeStyle("rgba(0,0,0,0)");
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle(color);
|
||||
ctx.transform(12.5,0,0,12.5,-578,22.2);
|
||||
ctx.beginPath();
|
||||
ctx.arc(49.7,12.8,2.66,0,doublePi,false);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle(DEFAULT_MARK_BG_COLOR);
|
||||
ctx.transform(12.5,0,0,12.5,-578,22.2);
|
||||
ctx.beginPath();
|
||||
ctx.arc(49.7,11.3,3.37,0,doublePi,false);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle(color);
|
||||
ctx.transform(12.5,0,0,12.5,-578,22.2);
|
||||
ctx.beginPath();
|
||||
ctx.arc(49.6,10.6,2.66,0,doublePi,false);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle(DEFAULT_MARK_BG_COLOR);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(36.9,98);
|
||||
ctx.lineTo(47.5,98);
|
||||
ctx.quadraticCurveTo(47.5,98,47.5,98);
|
||||
ctx.lineTo(47.5,154.5);
|
||||
ctx.quadraticCurveTo(47.5,154.5,47.5,154.5);
|
||||
ctx.lineTo(36.9,154.5);
|
||||
ctx.quadraticCurveTo(36.9,154.5,36.9,154.5);
|
||||
ctx.lineTo(36.9,98);
|
||||
ctx.quadraticCurveTo(36.9,98,36.9,98);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle(DEFAULT_MARK_BG_COLOR);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(43.6,0.372);
|
||||
ctx.lineTo(87.3,102);
|
||||
ctx.lineTo(-0.714,102);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle(color);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(43.6,14.7);
|
||||
ctx.lineTo(78.5,96.6);
|
||||
ctx.lineTo(8.07,96.6);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
protected void drawStartBoat(Context2d ctx, boolean isSelected, String color2) {
|
||||
}
|
||||
|
||||
protected void drawFinishBoat(Context2d ctx, boolean isSelected, String color2) {
|
||||
}
|
||||
|
||||
public double getMarkHeightInMeters() {
|
||||
return markHeightInMeters;
|
||||
}
|
||||
|
||||
public double getMarkWidthInMeters() {
|
||||
return markWidthInMeters;
|
||||
}
|
||||
|
||||
public String getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public String getShape() {
|
||||
return shape;
|
||||
}
|
||||
|
||||
public String getPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
public MarkType getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
+245
@@ -0,0 +1,245 @@
|
||||
package com.sap.sailing.gwt.ui.shared.racemap;
|
||||
|
||||
import com.google.gwt.canvas.dom.client.Context2d;
|
||||
import com.google.gwt.canvas.dom.client.Context2d.LineJoin;
|
||||
|
||||
public class SmallMultihullVectorGraphics extends BoatClassVectorGraphics {
|
||||
|
||||
public SmallMultihullVectorGraphics(String... compatibleBoatClassNames) {
|
||||
super("Multihull", 7.1, 2.6, 2.62, compatibleBoatClassNames);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawBoat(Context2d ctx, boolean isSelected, String color) {
|
||||
// outer net
|
||||
if(isSelected) {
|
||||
ctx.setFillStyle(color);
|
||||
ctx.setStrokeStyle(color);
|
||||
} else {
|
||||
ctx.setFillStyle ("#FFFFFF");
|
||||
ctx.setStrokeStyle("#FFFFFF");
|
||||
}
|
||||
|
||||
ctx.setLineWidth(1.0);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(88.6,37.7);
|
||||
ctx.lineTo(275.6,37.7);
|
||||
ctx.quadraticCurveTo(275.6,37.7,275.6,37.7);
|
||||
ctx.lineTo(275.6,224.7);
|
||||
ctx.quadraticCurveTo(275.6,224.7,275.6,224.7);
|
||||
ctx.lineTo(88.6,224.7);
|
||||
ctx.quadraticCurveTo(88.6,224.7,88.6,224.7);
|
||||
ctx.lineTo(88.6,37.7);
|
||||
ctx.quadraticCurveTo(88.6,37.7,88.6,37.7);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
// inner net
|
||||
if(isSelected) {
|
||||
ctx.setFillStyle("#FFFFFF");
|
||||
ctx.setStrokeStyle("#FFFFFF");
|
||||
} else {
|
||||
ctx.setFillStyle(color);
|
||||
ctx.setStrokeStyle(color);
|
||||
}
|
||||
ctx.setLineWidth(1.0);
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(114,71.7);
|
||||
ctx.lineTo(250,71.7);
|
||||
ctx.quadraticCurveTo(250,71.7,250,71.7);
|
||||
ctx.lineTo(250,199.7);
|
||||
ctx.quadraticCurveTo(250,199.7,250,199.7);
|
||||
ctx.lineTo(114,199.7);
|
||||
ctx.quadraticCurveTo(114,199.7,114,199.7);
|
||||
ctx.lineTo(114,71.7);
|
||||
ctx.quadraticCurveTo(114,71.7,114,71.7);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
// hull - left and right part
|
||||
if(isSelected) {
|
||||
ctx.setFillStyle(color);
|
||||
ctx.setStrokeStyle(color);
|
||||
} else {
|
||||
ctx.setFillStyle("#FFFFFF");
|
||||
ctx.setStrokeStyle("#000000");
|
||||
}
|
||||
|
||||
ctx.setLineWidth(5.0);
|
||||
ctx.setLineJoin(LineJoin.ROUND);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(1.98,1.67);
|
||||
ctx.lineTo(362,1.67);
|
||||
ctx.lineTo(529,21.7);
|
||||
ctx.lineTo(362,41.7);
|
||||
ctx.lineTo(1.98,41.7);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.setLineWidth(5.0);
|
||||
ctx.setLineJoin(LineJoin.ROUND);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(1.98,222);
|
||||
ctx.lineTo(361,222);
|
||||
ctx.lineTo(529,242);
|
||||
ctx.lineTo(361,262);
|
||||
ctx.lineTo(1.98,262);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
// Ausleger
|
||||
ctx.setFillStyle("rgba(0, 0, 0, 0)");
|
||||
ctx.setStrokeStyle("rgba(0, 0, 0, 255)");
|
||||
ctx.setLineWidth(3.0);
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(707,132);
|
||||
ctx.lineTo(266,132);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(475,242);
|
||||
ctx.lineTo(475,27.7);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(529,21.7);
|
||||
ctx.lineTo(709,132);
|
||||
ctx.lineTo(529,242);
|
||||
ctx.lineTo(529,242);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawDownwindPortTackSails(Context2d ctx) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(336,132);
|
||||
ctx.lineTo(90.6,182);
|
||||
ctx.bezierCurveTo(90.6,182,246,212,291,192);
|
||||
ctx.bezierCurveTo(339,162,336,132,336,132);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(473,132);
|
||||
ctx.lineTo(356,202);
|
||||
ctx.bezierCurveTo(356,202,448,182,464,162);
|
||||
ctx.bezierCurveTo(482,142,473,132,473,132);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(706,132);
|
||||
ctx.lineTo(321,355);
|
||||
ctx.bezierCurveTo(321,355,517,355,581,302);
|
||||
ctx.bezierCurveTo(656,242,706,132,706,132);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawDownwindStarboardTackSails(Context2d ctx) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(706,132);
|
||||
ctx.lineTo(320,-88.3);
|
||||
ctx.bezierCurveTo(320,-88.3,521,-88.3,585,-38.3);
|
||||
ctx.bezierCurveTo(656,21.7,706,132,706,132);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(473,132);
|
||||
ctx.lineTo(355,61.7);
|
||||
ctx.bezierCurveTo(355,61.7,448,81.7,464,102);
|
||||
ctx.bezierCurveTo(482,122,473,132,473,132);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(336,132);
|
||||
ctx.lineTo(90.6,91.7);
|
||||
ctx.bezierCurveTo(90.6,91.7,246,61.7,291,81.7);
|
||||
ctx.bezierCurveTo(339,112,336,132,336,132);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawUpwindPortTackSails(Context2d ctx) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(473,132);
|
||||
ctx.lineTo(337,152);
|
||||
ctx.bezierCurveTo(337,152,431,162,455,152);
|
||||
ctx.bezierCurveTo(482,152,473,132,473,132);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(336,132);
|
||||
ctx.lineTo(87.6,152);
|
||||
ctx.bezierCurveTo(87.6,152,239,192,288,172);
|
||||
ctx.bezierCurveTo(336,152,336,132,336,132);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawUpwindStarboardTackSails(Context2d ctx) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(473,132);
|
||||
ctx.lineTo(337,112);
|
||||
ctx.bezierCurveTo(337,112,431,91.7,455,112);
|
||||
ctx.bezierCurveTo(482,112,473,132,473,132);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(337,132);
|
||||
ctx.lineTo(87.6,112);
|
||||
ctx.bezierCurveTo(87.6,112,239,71.7,288,91.7);
|
||||
ctx.bezierCurveTo(337,112,337,132,337,132);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawReachingPortTackSails(Context2d ctx) {
|
||||
drawUpwindPortTackSails(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawReachingStarboardTackSails(Context2d ctx) {
|
||||
drawUpwindStarboardTackSails(ctx);;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawUnknownLegTypeStarboardTackSails(Context2d ctx) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawUnknownLegTypePortTackSails(Context2d ctx) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawKillingSails(Context2d ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
package com.sap.sailing.gwt.ui.shared.racemap;
|
||||
|
||||
import com.google.gwt.canvas.dom.client.Context2d;
|
||||
import com.sap.sailing.domain.common.MarkType;
|
||||
|
||||
/**
|
||||
* A class for arbitrary tracked assets (e.g umpire boats, camera boats, etc.) based on SVG graphics drawn to a HTML5 canvas
|
||||
* @author Frank
|
||||
*
|
||||
*/
|
||||
public class TrackedAssetVectorGraphics {
|
||||
protected double assetHeightInMeters;
|
||||
protected double assetWidthInMeters;
|
||||
|
||||
private final String color;
|
||||
private final MarkType type;
|
||||
|
||||
private final static String DEFAULT_ASSET_COLOR = "#f9ac00";
|
||||
|
||||
public TrackedAssetVectorGraphics(MarkType type, String color) {
|
||||
this.type = type;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public void drawMarkToCanvas(Context2d ctx, boolean isSelected,
|
||||
double width, double height, double scaleFactor) {
|
||||
|
||||
ctx.save();
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
|
||||
ctx.translate(width / 2.0, height / 2.0);
|
||||
ctx.scale(scaleFactor, scaleFactor);
|
||||
|
||||
ctx.translate(-assetWidthInMeters * 100 / 2.0,- assetHeightInMeters * 100 / 2.0);
|
||||
|
||||
String markColor = color != null ? color : DEFAULT_ASSET_COLOR;
|
||||
drawMark(ctx, isSelected, markColor);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
protected void drawMark(Context2d ctx, boolean isSelected, String color) {
|
||||
switch(type) {
|
||||
case CAMERABOAT:
|
||||
drawCameraBoat(ctx, isSelected, color);
|
||||
break;
|
||||
case UMPIREBOAT:
|
||||
drawUmpireBoat(ctx, isSelected, color);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected void drawCameraBoat(Context2d ctx, boolean isSelected, String color) {
|
||||
}
|
||||
|
||||
protected void drawUmpireBoat(Context2d ctx, boolean isSelected, String color) {
|
||||
}
|
||||
|
||||
public double getAssetHeightInMeters() {
|
||||
return assetHeightInMeters;
|
||||
}
|
||||
|
||||
public double getAssetWidthInMeters() {
|
||||
return assetWidthInMeters;
|
||||
}
|
||||
|
||||
public String getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public MarkType getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
+340
@@ -0,0 +1,340 @@
|
||||
package com.sap.sailing.gwt.ui.shared.racemap;
|
||||
|
||||
import com.google.gwt.canvas.dom.client.Context2d;
|
||||
import com.google.gwt.canvas.dom.client.Context2d.LineJoin;
|
||||
|
||||
public class _49erVectorGraphics extends BoatClassVectorGraphics {
|
||||
|
||||
public _49erVectorGraphics(String... compatibleBoatClassNames) {
|
||||
super("49ER", 4.99, 2.90, 2.50, compatibleBoatClassNames);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawBoat(Context2d ctx, boolean isSelected, String color) {
|
||||
if(isSelected) {
|
||||
ctx.setFillStyle(color);
|
||||
ctx.setStrokeStyle(color);
|
||||
} else {
|
||||
ctx.setFillStyle ("#FFFFFF");
|
||||
ctx.setStrokeStyle("#FFFFFF");
|
||||
}
|
||||
|
||||
ctx.setLineJoin(LineJoin.ROUND);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(2.04,2.47);
|
||||
ctx.lineTo(232,2.47);
|
||||
ctx.lineTo(235,36.5);
|
||||
ctx.lineTo(239,68.5);
|
||||
ctx.bezierCurveTo(239,68.5,296,81.4,325,88.5);
|
||||
ctx.bezierCurveTo(363,98,439,119,439,119);
|
||||
ctx.lineTo(499,137);
|
||||
ctx.lineTo(499,151);
|
||||
ctx.bezierCurveTo(499,151,448,169,422,177);
|
||||
ctx.bezierCurveTo(391,186,360,195,328,202);
|
||||
ctx.bezierCurveTo(299,209,239,219,239,219);
|
||||
ctx.lineTo(234,258);
|
||||
ctx.lineTo(230,288);
|
||||
ctx.lineTo(2.04,288);
|
||||
ctx.bezierCurveTo(2.04,288,27.9,282,42.5,266);
|
||||
ctx.bezierCurveTo(51.7,255,56.2,210,56.2,210);
|
||||
ctx.lineTo(30.3,192);
|
||||
ctx.lineTo(30.3,93.5);
|
||||
ctx.lineTo(56.2,76.5);
|
||||
ctx.bezierCurveTo(56.2,76.5,53.9,37.5,45,24.5);
|
||||
ctx.bezierCurveTo(34.9,9.5,2.04,2.47,2.04,2.47);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.setFillStyle("#000000");
|
||||
ctx.setStrokeStyle("#000000");
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(65.1,220);
|
||||
ctx.lineTo(224,220);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(66.7,68.5);
|
||||
ctx.lineTo(226,68.5);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
if(isSelected) {
|
||||
ctx.setFillStyle ("#FFFFFF");
|
||||
ctx.setStrokeStyle("#FFFFFF");
|
||||
} else {
|
||||
ctx.setFillStyle(color);
|
||||
ctx.setStrokeStyle(color);
|
||||
}
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(59.6,98);
|
||||
ctx.lineTo(92.4,70.2);
|
||||
ctx.lineTo(239,70.2);
|
||||
ctx.lineTo(298,83.9);
|
||||
ctx.bezierCurveTo(298,83.9,277,121,277,142);
|
||||
ctx.bezierCurveTo(277,165,299,207,299,207);
|
||||
ctx.lineTo(238,218);
|
||||
ctx.lineTo(91.9,218);
|
||||
ctx.lineTo(59.6,190);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
// drawAlien(ctx); idea for a game: draw an alien into the boat once per race for 1 second -> find the alien
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawDownwindPortTackSails(Context2d ctx) {
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(499,148);
|
||||
ctx.lineTo(286,250);
|
||||
ctx.bezierCurveTo(286,250,444,231,472,202);
|
||||
ctx.bezierCurveTo(499,176,499,148,499,148);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(275,150);
|
||||
ctx.lineTo(44.8,285);
|
||||
ctx.bezierCurveTo(44.8,285,217,248,248,214);
|
||||
ctx.bezierCurveTo(277,180,275,150,275,150);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(655,148);
|
||||
ctx.lineTo(316,304);
|
||||
ctx.bezierCurveTo(316,304,509,336,564,300);
|
||||
ctx.bezierCurveTo(627,262,655,148,655,148);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.setFillStyle("rgba(0, 0, 0, 0)");
|
||||
ctx.setStrokeStyle("rgba(0, 0, 0, 255)");
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(315,304);
|
||||
ctx.lineTo(179,257);
|
||||
ctx.lineTo(179,40.2);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
ctx.save();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawDownwindStarboardTackSails(Context2d ctx) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(499,146);
|
||||
ctx.lineTo(286,43.5);
|
||||
ctx.bezierCurveTo(286,43.5,444,62.4,472,91.6);
|
||||
ctx.bezierCurveTo(499,118,499,146,499,146);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(275,144);
|
||||
ctx.lineTo(43.8,8.4);
|
||||
ctx.bezierCurveTo(43.8,8.4,217,45.5,248,79.5);
|
||||
ctx.bezierCurveTo(277,114,275,144,275,144);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(655,146);
|
||||
ctx.lineTo(316,-10.5);
|
||||
ctx.bezierCurveTo(316,-10.5,509,-42.1,564,-6.49);
|
||||
ctx.bezierCurveTo(627,31.5,655,146,655,146);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.setFillStyle("rgba(0, 0, 0, 0)");
|
||||
ctx.setStrokeStyle("rgba(0, 0, 0, 255)");
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(316,-10.5);
|
||||
ctx.lineTo(180,36.5);
|
||||
ctx.lineTo(180,253);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawUpwindPortTackSails(Context2d ctx) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(496,148);
|
||||
ctx.lineTo(284,183);
|
||||
ctx.bezierCurveTo(284,183,427,207,457,189);
|
||||
ctx.bezierCurveTo(489,172,496,148,496,148);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(275,149);
|
||||
ctx.lineTo(23.2,191);
|
||||
ctx.bezierCurveTo(23.2,191,192,218,230,198);
|
||||
ctx.bezierCurveTo(269,176,275,149,275,149);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawUpwindStarboardTackSails(Context2d ctx) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(496,147);
|
||||
ctx.lineTo(284,112);
|
||||
ctx.bezierCurveTo(284,112,427,88.4,457,106);
|
||||
ctx.bezierCurveTo(489,123,496,147,496,147);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(275,146);
|
||||
ctx.lineTo(23.3,104);
|
||||
ctx.bezierCurveTo(23.3,104,192,77.4,230,97.4);
|
||||
ctx.bezierCurveTo(269,119,275,146,275,146);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawReachingPortTackSails(Context2d ctx) {
|
||||
drawUpwindPortTackSails(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawReachingStarboardTackSails(Context2d ctx) {
|
||||
drawUpwindStarboardTackSails(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawUnknownLegTypeStarboardTackSails(Context2d ctx) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawUnknownLegTypePortTackSails(Context2d ctx) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawKillingSails(Context2d ctx) {
|
||||
}
|
||||
|
||||
protected void drawAlien(Context2d ctx) {
|
||||
ctx.save();
|
||||
ctx.setFillStyle("#88bd64");
|
||||
ctx.transform(0.015,1,-1,0.015,722,-135);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(268,564);
|
||||
ctx.bezierCurveTo(283.1878306203468,564,295.5,583.699471007445,295.5,608);
|
||||
ctx.bezierCurveTo(295.5,632.300528992555,283.1878306203468,652,268,652);
|
||||
ctx.bezierCurveTo(252.81216937965317,652,240.5,632.300528992555,240.5,608);
|
||||
ctx.bezierCurveTo(240.5,583.699471007445,252.81216937965317,564,268,564);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle("#fafafa");
|
||||
ctx.transform(0.015,1,-1,0.015,722,-135);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(255,578.5);
|
||||
ctx.bezierCurveTo(260.10863393593485,578.5,264.25,587.2304473782996,264.25,598);
|
||||
ctx.bezierCurveTo(264.25,608.7695526217004,260.10863393593485,617.5,255,617.5);
|
||||
ctx.bezierCurveTo(249.89136606406515,617.5,245.75,608.7695526217004,245.75,598);
|
||||
ctx.bezierCurveTo(245.75,587.2304473782996,249.89136606406515,578.5,255,578.5);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle("#fafafa");
|
||||
ctx.transform(0.015,1,-1,0.015,722,-135);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(282,580.5);
|
||||
ctx.bezierCurveTo(287.10863393593485,580.5,291.25,589.2304473782996,291.25,600);
|
||||
ctx.bezierCurveTo(291.25,610.7695526217004,287.10863393593485,619.5,282,619.5);
|
||||
ctx.bezierCurveTo(276.89136606406515,619.5,272.75,610.7695526217004,272.75,600);
|
||||
ctx.bezierCurveTo(272.75,589.2304473782996,276.89136606406515,580.5,282,580.5);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.setFillStyle("#010202");
|
||||
ctx.transform(0.011,0.741,-0.783,0.011,594,-59.8);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(281,580);
|
||||
ctx.bezierCurveTo(285.69442037356174,580,289.5,583.5817220013537,289.5,588);
|
||||
ctx.bezierCurveTo(289.5,592.4182779986463,285.69442037356174,596,281,596);
|
||||
ctx.bezierCurveTo(276.30557962643826,596,272.5,592.4182779986463,272.5,588);
|
||||
ctx.bezierCurveTo(272.5,583.5817220013537,276.30557962643826,580,281,580);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
ctx.setFillStyle("#010202");
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(94.1,129);
|
||||
ctx.bezierCurveTo(94.1,129,88.1,155,97.1,159);
|
||||
ctx.bezierCurveTo(106,163,79.1,148,94.1,129);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.setFillStyle("#88bd64");
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(59.1,98);
|
||||
ctx.bezierCurveTo(59.1,98,54.1,188,65.1,185);
|
||||
ctx.bezierCurveTo(76.1,182,80.1,160,82.1,147);
|
||||
ctx.bezierCurveTo(84.1,134,68.1,99,59.099999999999994,98);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.setFillStyle("#010202");
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(146,144);
|
||||
ctx.bezierCurveTo(146,144,189,168,144,187);
|
||||
ctx.bezierCurveTo(99,205,184,180,146,144);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(148,140);
|
||||
ctx.bezierCurveTo(148,140,190,114,144,97);
|
||||
ctx.bezierCurveTo(99,79,185,102,148,140);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.save();
|
||||
ctx.transform(0.011,0.741,-0.783,0.011,595,-87.8);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(281,580);
|
||||
ctx.bezierCurveTo(285.69442037356174,580,289.5,583.5817220013537,289.5,588);
|
||||
ctx.bezierCurveTo(289.5,592.4182779986463,285.69442037356174,596,281,596);
|
||||
ctx.bezierCurveTo(276.30557962643826,596,272.5,592.4182779986463,272.5,588);
|
||||
ctx.bezierCurveTo(272.5,583.5817220013537,276.30557962643826,580,281,580);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
+1
@@ -10,6 +10,7 @@
|
||||
<!-- the theme of your GWT application by uncommenting -->
|
||||
<!-- any one of the following lines. -->
|
||||
<inherits name='com.google.gwt.user.theme.clean.Clean'/>
|
||||
<inherits name='com.google.gwt.debug.Debug'/>
|
||||
<!-- <inherits name='com.google.gwt.user.theme.standard.Standard'/> -->
|
||||
<!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->
|
||||
<!-- <inherits name='com.google.gwt.user.theme.dark.Dark'/> -->
|
||||
|
||||
@@ -6,6 +6,7 @@ Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
|
||||
Require-Bundle: org.junit4;bundle-version="4.8.2",
|
||||
org.openqa.selenium.osgi;bundle-version="2.34.0",
|
||||
org.openqa.selenium.osgi;bundle-version="2.39.0",
|
||||
com.sap.sailing.mongodb;bundle-version="1.0.0",
|
||||
com.mongodb.driver;bundle-version="2.6.2"
|
||||
com.mongodb.driver;bundle-version="2.6.2",
|
||||
com.sap.sailing.domain.common
|
||||
+4
@@ -6,6 +6,10 @@
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||
<listEntry value="4"/>
|
||||
</listAttribute>
|
||||
<mapAttribute key="org.eclipse.debug.core.preferred_launchers">
|
||||
<mapEntry key="[debug]" value="org.eclipse.jdt.junit.launchconfig"/>
|
||||
<mapEntry key="[run]" value="org.eclipse.jdt.junit.launchconfig"/>
|
||||
</mapAttribute>
|
||||
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=com.sap.sailing.selenium.test"/>
|
||||
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
|
||||
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
|
||||
|
||||
@@ -38,12 +38,10 @@
|
||||
<name>webdriver.chrome.driver</name>
|
||||
<value>C:\apps\ChromeSeleniumDriver\chromedriver.exe</value>
|
||||
</system-property>
|
||||
<!--
|
||||
<system-property>
|
||||
<name>webdriver.firefox.bin</name>
|
||||
<value>c:/Program Files (x86)/Mozilla Firefox/firefox.exe</value>
|
||||
<value>/usr/bin/firefox</value>
|
||||
</system-property>
|
||||
-->
|
||||
</system-properties>
|
||||
|
||||
|
||||
@@ -55,22 +53,10 @@
|
||||
The capabilities section can be used for fine tuning of the driver (e.g. version). For more informations see the
|
||||
pages mentioned above.
|
||||
-->
|
||||
<!-- -->
|
||||
<driver-definition class="org.openqa.selenium.firefox.FirefoxDriver">
|
||||
<!-- -->
|
||||
<!--
|
||||
<capabilities>
|
||||
<capability>
|
||||
<name>version</name>
|
||||
<value>14.0.0</value>
|
||||
</capability>
|
||||
</capabilities>
|
||||
-->
|
||||
<!-- -->
|
||||
</driver-definition>
|
||||
<!-- -->
|
||||
|
||||
<!--
|
||||
<driver-definition class="org.openqa.selenium.chrome.ChromeDriver" />
|
||||
<!--
|
||||
<driver-definition class="org.openqa.selenium.chrome.ChromeDriver">
|
||||
</driver-definition>
|
||||
-->
|
||||
</test-environment>
|
||||
+1
-1
@@ -20,7 +20,7 @@ public class AjaxCallsComplete implements ExpectedCondition<Boolean> {
|
||||
*/
|
||||
public static final String CATEGORY_GLOBAL = ""; //$NON-NLS-1$
|
||||
|
||||
private static final String JAVASCRIPT = "return (window.PENDING_AJAX_CALLS.numberOfPendingCalls(%s) === 0)"; //$NON-NLS-1$
|
||||
private static final String JAVASCRIPT = "return (window.PENDING_AJAX_CALLS == null || window.PENDING_AJAX_CALLS.numberOfPendingCalls(%s) === 0)"; //$NON-NLS-1$
|
||||
|
||||
private String category;
|
||||
|
||||
|
||||
@@ -2,35 +2,27 @@ package com.sap.sailing.selenium.core;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.junit.runner.Description;
|
||||
|
||||
import org.junit.runner.notification.Failure;
|
||||
import org.junit.runner.notification.RunNotifier;
|
||||
|
||||
import org.junit.runners.BlockJUnit4ClassRunner;
|
||||
import org.junit.runners.ParentRunner;
|
||||
|
||||
import org.junit.runners.model.InitializationError;
|
||||
import org.junit.runners.model.FrameworkField;
|
||||
import org.junit.runners.model.FrameworkMethod;
|
||||
import org.junit.runners.model.InitializationError;
|
||||
import org.junit.runners.model.TestClass;
|
||||
|
||||
import org.openqa.selenium.Capabilities;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
import org.openqa.selenium.remote.DesiredCapabilities;
|
||||
|
||||
import com.sap.sailing.selenium.core.Selenium.SeleniumJUnit4ClassRunner;
|
||||
import com.sap.sailing.selenium.core.TestEnvironmentConfiguration.DriverDefinition;
|
||||
|
||||
import com.sap.sailing.selenium.core.impl.TestEnvironmentImpl;
|
||||
|
||||
/**
|
||||
@@ -142,17 +134,17 @@ public class Selenium extends ParentRunner<SeleniumJUnit4ClassRunner> {
|
||||
}
|
||||
|
||||
private String createDriverDescription() {
|
||||
return descripeDriver() + descripeCapabilities();
|
||||
return describeDriver() + describeCapabilities();
|
||||
}
|
||||
|
||||
private String descripeDriver() {
|
||||
private String describeDriver() {
|
||||
String driver = this.definition.getDriver();
|
||||
int index = driver.lastIndexOf('.');
|
||||
|
||||
return (index != -1 ? driver.substring(index + 1) : driver);
|
||||
}
|
||||
|
||||
private String descripeCapabilities() {
|
||||
private String describeCapabilities() {
|
||||
Map<String, String> capabilities = this.definition.getCapabilities();
|
||||
|
||||
if (capabilities.isEmpty())
|
||||
@@ -177,12 +169,11 @@ public class Selenium extends ParentRunner<SeleniumJUnit4ClassRunner> {
|
||||
private TestEnvironmentImpl createTestEnvironment() throws Exception {
|
||||
try {
|
||||
String driverClassname = this.definition.getDriver();
|
||||
Map<String, String> capabilityDefenitions = this.definition.getCapabilities();
|
||||
Map<String, String> capabilityDefinitions = this.definition.getCapabilities();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<WebDriver> clazz = (Class<WebDriver>) Class.forName(driverClassname);
|
||||
Capabilities capabilities = new DesiredCapabilities(capabilityDefenitions);
|
||||
|
||||
DesiredCapabilities capabilities = new DesiredCapabilities(capabilityDefinitions);
|
||||
Constructor<WebDriver> constructor = clazz.getConstructor(Capabilities.class);
|
||||
WebDriver driver = constructor.newInstance(capabilities);
|
||||
|
||||
|
||||
+11
-11
@@ -46,11 +46,11 @@ public class SeleniumElementLocator implements ElementLocator {
|
||||
* The context for search of the element or the list of elements.
|
||||
* @param field
|
||||
* The field for which an element or an element list should be lazily locate.
|
||||
* @param timeOut
|
||||
* The maximum amount of time to wait for the element or the list of elements.
|
||||
* @param timeOutSeconds
|
||||
* The maximum amount of time to wait for the element or the list of elements in seconds
|
||||
*/
|
||||
public SeleniumElementLocator(SearchContext context, Field field, int timeOut) {
|
||||
this(context, field, timeOut, 250);
|
||||
public SeleniumElementLocator(SearchContext context, Field field, int timeOutSeconds) {
|
||||
this(context, field, timeOutSeconds, 250);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,17 +61,17 @@ public class SeleniumElementLocator implements ElementLocator {
|
||||
* The context for search of the element or the list of elements.
|
||||
* @param field
|
||||
* The field for which an element or an element list should be lazily locate.
|
||||
* @param timeOut
|
||||
* The maximum amount of time to wait for the element or the list of elements.
|
||||
* @param interval
|
||||
* The frequency with which to check the search context.
|
||||
* @param timeOutSeconds
|
||||
* The maximum amount of time to wait for the element or the list of elements in seconds
|
||||
* @param intervalMillis
|
||||
* The frequency with which to check the search context in milliseconds
|
||||
*/
|
||||
public SeleniumElementLocator(SearchContext context, Field field, int timeOut, int interval) {
|
||||
public SeleniumElementLocator(SearchContext context, Field field, int timeOutSeconds, int intervalMillis) {
|
||||
this.context = context;
|
||||
|
||||
this.wait = new FluentWait<>(this.context);
|
||||
this.wait.withTimeout(timeOut, TimeUnit.SECONDS);
|
||||
this.wait.pollingEvery(interval, TimeUnit.MILLISECONDS);
|
||||
this.wait.withTimeout(timeOutSeconds, TimeUnit.SECONDS);
|
||||
this.wait.pollingEvery(intervalMillis, TimeUnit.MILLISECONDS);
|
||||
this.wait.ignoring(NoSuchElementException.class);
|
||||
|
||||
Annotations annotations = new Annotations(field);
|
||||
|
||||
+11
-10
@@ -37,15 +37,15 @@ public class SeleniumElementLocatorFactory implements ElementLocatorFactory {
|
||||
*
|
||||
* @param context
|
||||
* The context for search of an element or a list of elements.
|
||||
* @param timeOut
|
||||
* The maximum amount of time to wait for the element or the list of elements.
|
||||
* @param interval
|
||||
* The frequency with which to check the search context.
|
||||
* @param timeOutSeconds
|
||||
* The maximum amount of time to wait for the element or the list of elements in seconds
|
||||
* @param intervalMilliseconds
|
||||
* The frequency with which to check the search context in milliseconds
|
||||
*/
|
||||
public SeleniumElementLocatorFactory(SearchContext context, int timeOut, int interval) {
|
||||
public SeleniumElementLocatorFactory(SearchContext context, int timeOutSeconds, int intervalMilliseconds) {
|
||||
this.context = context;
|
||||
this.timeOut = timeOut;
|
||||
this.interval = interval;
|
||||
this.timeOut = timeOutSeconds;
|
||||
this.interval = intervalMilliseconds;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,9 +58,10 @@ public class SeleniumElementLocatorFactory implements ElementLocatorFactory {
|
||||
*/
|
||||
@Override
|
||||
public ElementLocator createLocator(Field field) {
|
||||
if (!Annotations.isAnnotationPresent(field))
|
||||
if (!Annotations.isAnnotationPresent(field)) {
|
||||
return null;
|
||||
|
||||
return new SeleniumElementLocator(this.context, field, this.timeOut, this.interval);
|
||||
} else {
|
||||
return new SeleniumElementLocator(this.context, field, this.timeOut, this.interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-11
@@ -140,7 +140,7 @@ public class TestEnvironmentConfiguration {
|
||||
String contextRoot = XMLHelper.getContentTextNS(testEnvironmentNode, CONTEXT_ROOT, NAMESPACE_URI);
|
||||
String screenshotsFolder = XMLHelper.getContentTextNS(testEnvironmentNode, SCREENSHOTS_FOLDER, NAMESPACE_URI);
|
||||
Map<String, String> systemProperties = createSystemProperties(testEnvironmentNode);
|
||||
List<DriverDefinition> driverDefenitions = createDriverDefenitions(testEnvironmentNode);
|
||||
List<DriverDefinition> driverDefenitions = createDriverDefinitions(testEnvironmentNode);
|
||||
|
||||
return new TestEnvironmentConfiguration(contextRoot, screenshotsFolder, systemProperties, driverDefenitions);
|
||||
}
|
||||
@@ -183,17 +183,13 @@ public class TestEnvironmentConfiguration {
|
||||
return properties;
|
||||
}
|
||||
|
||||
private static List<DriverDefinition> createDriverDefenitions(Element testEnvironmentNode) {
|
||||
List<DriverDefinition> defenitions = new LinkedList<>();
|
||||
|
||||
List<Element> driverDefinitionNodes = XMLHelper.getElementsNS(testEnvironmentNode, DRIVER_DEFINITION,
|
||||
NAMESPACE_URI);
|
||||
|
||||
for(Element driverDefinitionNode : driverDefinitionNodes) {
|
||||
defenitions.add(createDriverDefinition(driverDefinitionNode));
|
||||
private static List<DriverDefinition> createDriverDefinitions(Element testEnvironmentNode) {
|
||||
List<DriverDefinition> definitions = new LinkedList<>();
|
||||
List<Element> driverDefinitionNodes = XMLHelper.getElementsNS(testEnvironmentNode, DRIVER_DEFINITION, NAMESPACE_URI);
|
||||
for (Element driverDefinitionNode : driverDefinitionNodes) {
|
||||
definitions.add(createDriverDefinition(driverDefinitionNode));
|
||||
}
|
||||
|
||||
return defenitions;
|
||||
return definitions;
|
||||
}
|
||||
|
||||
private static DriverDefinition createDriverDefinition(Element driverDefinitionNode) {
|
||||
|
||||
+32
-10
@@ -114,25 +114,47 @@ public class AdminConsolePage extends HostPage {
|
||||
String expression = TAB_EXPRESSION.format(new Object[] {label});
|
||||
WebElement tab = this.tabPanel.findElement(By.xpath(expression));
|
||||
int maxScrollActions = 20;
|
||||
FluentWait<WebElement> wait = new FluentWait<>(this.tabPanel);
|
||||
wait.withTimeout(10, TimeUnit.SECONDS);
|
||||
wait.pollingEvery(2, TimeUnit.SECONDS);
|
||||
WebElement scroller;
|
||||
while (!tab.isDisplayed() && maxScrollActions-- > 0) {
|
||||
FluentWait<WebElement> wait = new FluentWait<>(this.tabPanel);
|
||||
wait.withTimeout(10, TimeUnit.SECONDS);
|
||||
wait.pollingEvery(2, TimeUnit.SECONDS);
|
||||
WebElement scroller = wait.until(ElementSearchConditions.visibilityOfElementLocated(
|
||||
By.className("gwt-ScrolledTabLayoutPanel-scrollRight")));
|
||||
try {
|
||||
scroller = wait.until(ElementSearchConditions.visibilityOfElementLocated(
|
||||
By.className("gwt-ScrolledTabLayoutPanel-scrollRight")));
|
||||
} catch (org.openqa.selenium.TimeoutException e) {
|
||||
break; // scroller probably not present; try the other direction
|
||||
}
|
||||
if (!scroller.isDisplayed()) {
|
||||
break; // reached last tab; still not visible; try the other direction
|
||||
}
|
||||
scroller = scroller.findElement(By.tagName("img"));
|
||||
|
||||
scroller.click();
|
||||
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
|
||||
}
|
||||
logger.log(Level.INFO, String.format("Scrolled %d times.", 20 - maxScrollActions));
|
||||
|
||||
logger.log(Level.INFO, String.format("Scrolled %d times right", 20 - maxScrollActions));
|
||||
maxScrollActions = 20;
|
||||
while (!tab.isDisplayed() && maxScrollActions-- > 0) {
|
||||
try {
|
||||
scroller = wait.until(ElementSearchConditions.visibilityOfElementLocated(
|
||||
By.className("gwt-ScrolledTabLayoutPanel-scrollLeft")));
|
||||
} catch (org.openqa.selenium.TimeoutException e) {
|
||||
break; // scroller probably not present; try the other direction
|
||||
}
|
||||
scroller = scroller.findElement(By.tagName("img"));
|
||||
scroller.click();
|
||||
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
|
||||
}
|
||||
logger.log(Level.INFO, String.format("Scrolled %d times left", 20 - maxScrollActions));
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} // wait until tab is really available for clicking
|
||||
tab.click();
|
||||
// Wait for the tab to become visible due to the used animations.
|
||||
FluentWait<WebElement> wait = new FluentWait<>(this.tabPanel);
|
||||
wait.withTimeout(30, TimeUnit.SECONDS);
|
||||
wait.pollingEvery(5, TimeUnit.SECONDS);
|
||||
|
||||
WebElement content = wait.until(ElementSearchConditions.visibilityOfElementLocated(new BySeleniumId(id)));
|
||||
return content;
|
||||
}
|
||||
|
||||
+7
-27
@@ -5,17 +5,13 @@ import org.openqa.selenium.WebElement;
|
||||
|
||||
import com.sap.sailing.selenium.core.BySeleniumId;
|
||||
import com.sap.sailing.selenium.core.FindBy;
|
||||
import com.sap.sailing.selenium.test.PageArea;
|
||||
import com.sap.sailing.selenium.test.gwt.widgets.AbstractDialog;
|
||||
|
||||
public class FlexibleLeaderboardCreationDialog extends PageArea {
|
||||
@FindBy(how = BySeleniumId.class, using = "OkButton")
|
||||
private WebElement okButton;
|
||||
@FindBy(how = BySeleniumId.class, using = "CancelButton")
|
||||
private WebElement cancelButton;
|
||||
public class FlexibleLeaderboardCreationDialog extends AbstractDialog {
|
||||
@FindBy(how = BySeleniumId.class, using = "LeaderboardNameField")
|
||||
private WebElement nameField;
|
||||
@FindBy(how = BySeleniumId.class, using = "StatusLabel")
|
||||
private WebElement statusLabel;
|
||||
@FindBy(how = BySeleniumId.class, using = "LeaderboardDisplayNameField")
|
||||
private WebElement displayNameField;
|
||||
|
||||
public FlexibleLeaderboardCreationDialog(WebDriver driver, WebElement element) {
|
||||
super(driver, element);
|
||||
@@ -24,24 +20,8 @@ public class FlexibleLeaderboardCreationDialog extends PageArea {
|
||||
public void setName(String name) {
|
||||
this.nameField.clear();
|
||||
this.nameField.sendKeys(name);
|
||||
}
|
||||
|
||||
public boolean isOkEnabled() {
|
||||
return this.okButton.isEnabled();
|
||||
}
|
||||
|
||||
public String getErrorMessage() {
|
||||
return this.statusLabel.getText();
|
||||
}
|
||||
|
||||
public void pressOk() {
|
||||
this.okButton.click();
|
||||
|
||||
// Wait, since we create the flexible leader board
|
||||
waitForAjaxRequests();
|
||||
}
|
||||
|
||||
public void pressCancel() {
|
||||
this.cancelButton.click();
|
||||
// now move the focus away from the nameField to ensure the onchange event is fired; see https://code.google.com/p/selenium/wiki/FrequentlyAskedQuestions
|
||||
this.displayNameField.sendKeys(" ");
|
||||
this.displayNameField.clear();
|
||||
}
|
||||
}
|
||||
+57
-13
@@ -22,6 +22,9 @@ public class LeaderboardConfigurationPanel extends PageArea {
|
||||
@FindBy(how = BySeleniumId.class, using = "AvailableLeaderboardsTable")
|
||||
private WebElement availableLeaderboardsTable;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "AddRaceColumnsButton")
|
||||
private WebElement addRaceColumnsButton;
|
||||
|
||||
protected LeaderboardConfigurationPanel(WebDriver driver, WebElement element) {
|
||||
super(driver, element);
|
||||
}
|
||||
@@ -35,31 +38,41 @@ public class LeaderboardConfigurationPanel extends PageArea {
|
||||
|
||||
for(WebElement row : rows) {
|
||||
WebElement name = row.findElement(By.xpath(".//td/div/a"));
|
||||
|
||||
leaderboards.add(name.getText());
|
||||
}
|
||||
|
||||
return leaderboards;
|
||||
}
|
||||
|
||||
public void selectLeaderboard(String leaderboardName) {
|
||||
WebElement row = getLeaderboardRow(leaderboardName);
|
||||
row.click();
|
||||
}
|
||||
|
||||
private WebElement getLeaderboardRow(String leaderboardName) {
|
||||
for (WebElement row : getLeaderboardTable().getRows()) {
|
||||
WebElement name = row.findElement(By.xpath(".//td/div/a"));
|
||||
if (leaderboardName.equals(name.getText())) {
|
||||
return row;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void deleteLeaderboard(String leaderboard) {
|
||||
CellTable table = getLeaderboardTable();
|
||||
List<WebElement> rows = table.getRows();
|
||||
|
||||
for(WebElement row : rows) {
|
||||
for (WebElement row : rows) {
|
||||
WebElement name = row.findElement(By.xpath(".//td/div/a"));
|
||||
|
||||
if(!leaderboard.equals(name.getText()))
|
||||
continue;
|
||||
|
||||
WebElement removeAction = row.findElement(By.xpath(".//td/div/div[@title='Remove']/img"));
|
||||
|
||||
removeAction.click();
|
||||
|
||||
this.driver.switchTo().alert().accept();
|
||||
if (leaderboard.equals(name.getText())) {
|
||||
WebElement removeAction = row.findElement(By.xpath(".//td/div/div[@title='Remove']/img"));
|
||||
removeAction.click();
|
||||
this.driver.switchTo().alert().accept();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public FlexibleLeaderboardCreationDialog startCreatingFlexibleLeaderboard() {
|
||||
this.createFlexibleLeaderboardButton.click();
|
||||
// Wait, since we trigger an AJAX-request to get the available events
|
||||
@@ -77,4 +90,35 @@ public class LeaderboardConfigurationPanel extends PageArea {
|
||||
|
||||
//this.availableLeaderboardsTable = new CellTable(this.driver, findElementBySeleniumId("AvailableLeaderboardsTable"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assuming that the leaderboard is already selected, clicks the "Add Races..." button
|
||||
* @param i
|
||||
*/
|
||||
public void addRacesToFlexibleLeaderboard(int i) {
|
||||
addRaceColumnsButton.click();
|
||||
WebElement dialog = findElementBySeleniumId(this.driver, "RaceColumnsInLeaderboardDialog");
|
||||
RaceColumnsInLeaderboardDialog raceColumnsInLeaderboardDialog = new RaceColumnsInLeaderboardDialog(this.driver, dialog);
|
||||
raceColumnsInLeaderboardDialog.addRaces(2);
|
||||
selectRaceColumn("R1", "Default");
|
||||
}
|
||||
|
||||
public void selectRaceColumn(String raceColumnName, String fleetName) {
|
||||
CellTable table = getRaceColumnsTable();
|
||||
for (WebElement row : table.getRows()) {
|
||||
List<WebElement> fields = row.findElements(By.tagName("td"));
|
||||
if (raceColumnName.equals(fields.get(0).getText()) && fleetName.equals(fields.get(1).getText())) {
|
||||
fields.get(1).click();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TrackedRacesPanel getTrackedRacesPanel() {
|
||||
return new TrackedRacesPanel(driver, findElementBySeleniumId(context, "TrackedRaces"));
|
||||
}
|
||||
|
||||
private CellTable getRaceColumnsTable() {
|
||||
return new CellTable(this.driver, findElementBySeleniumId(this.driver, "RaceColumnTable"));
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.sap.sailing.selenium.test.adminconsole.pages;
|
||||
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
||||
import com.sap.sailing.selenium.core.BySeleniumId;
|
||||
import com.sap.sailing.selenium.core.FindBy;
|
||||
import com.sap.sailing.selenium.test.gwt.widgets.AbstractDialog;
|
||||
|
||||
public class RaceColumnsInLeaderboardDialog extends AbstractDialog {
|
||||
@FindBy(how = BySeleniumId.class, using = "AddRacesListBox")
|
||||
private WebElement addRacesListBox;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "AddRacesButton")
|
||||
private WebElement addRacesButton;
|
||||
|
||||
public RaceColumnsInLeaderboardDialog(WebDriver driver, WebElement element) {
|
||||
super(driver, element);
|
||||
}
|
||||
|
||||
public void addRaces(int i) {
|
||||
addRacesListBox.sendKeys("2");
|
||||
addRacesButton.click();
|
||||
pressOk();
|
||||
}
|
||||
}
|
||||
+43
-54
@@ -1,18 +1,18 @@
|
||||
package com.sap.sailing.selenium.test.adminconsole.pages;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
||||
|
||||
|
||||
|
||||
//import org.openqa.selenium.support.FindBy;
|
||||
//import org.openqa.selenium.support.How;
|
||||
|
||||
import com.sap.sailing.selenium.core.FindBy;
|
||||
import com.sap.sailing.selenium.core.BySeleniumId;
|
||||
|
||||
import com.sap.sailing.selenium.core.FindBy;
|
||||
import com.sap.sailing.selenium.test.PageArea;
|
||||
|
||||
/**
|
||||
@@ -34,9 +34,13 @@ public class TracTracEventManagementPanel extends PageArea {
|
||||
@FindBy(how = BySeleniumId.class, using = "ListRaces")
|
||||
private WebElement listRacesButton;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "FilterRaces")
|
||||
private WebElement filterTrackableRacesField;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "TrackableRacesSection")
|
||||
private WebElement startTrackingPanel;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "TrackedRaces")
|
||||
private WebElement trackedRacesPanel;
|
||||
|
||||
|
||||
// private WebElement trackWindCheckBox;
|
||||
// private WebElement correctWindCheckbox;
|
||||
// private WebElement simulateWithNowCheckbox;
|
||||
@@ -66,10 +70,13 @@ public class TracTracEventManagementPanel extends PageArea {
|
||||
jsonURLField.clear();
|
||||
jsonURLField.sendKeys(url);
|
||||
listRacesButton.click();
|
||||
|
||||
waitForAjaxRequests();
|
||||
}
|
||||
|
||||
public TracTracStartTrackingPanel getStartTrackingPanel() {
|
||||
return new TracTracStartTrackingPanel(driver, startTrackingPanel);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the list of all available trackable races. This list will be empty if no race is available or if no
|
||||
* race was specified before.</p>
|
||||
@@ -77,34 +84,10 @@ public class TracTracEventManagementPanel extends PageArea {
|
||||
* @return
|
||||
* The list of all available trackable races.
|
||||
*/
|
||||
// QUESTION: Should we return something different instead of WebElements since it is not recommended to do so?
|
||||
public List<WebElement> getTrackableRaces() {
|
||||
WebElement availableRacesTabel = findElementBySeleniumId(this.context, "RacesTable"); //$NON-NLS-1$
|
||||
List<WebElement> elements = availableRacesTabel.findElements(By.xpath("./tbody/tr")); //$NON-NLS-1$
|
||||
Iterator<WebElement> iterator = elements.iterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
WebElement element = iterator.next();
|
||||
|
||||
if(!element.isDisplayed())
|
||||
iterator.remove();
|
||||
}
|
||||
|
||||
return elements;
|
||||
return getStartTrackingPanel().getTrackableRaces();
|
||||
}
|
||||
|
||||
// public List<String> getAvailableReggatasForTracking() {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// public String getReggataForTracking() {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// public void setReggataForTracking(String regatta) {
|
||||
//
|
||||
// }
|
||||
|
||||
/**
|
||||
* <p>Sets the filter for the trackable races. After the filter is set you can obtain the new resulting list via
|
||||
* {@link #getTrackableRaces}</p>
|
||||
@@ -113,27 +96,33 @@ public class TracTracEventManagementPanel extends PageArea {
|
||||
* The filter to apply to the trackable races.
|
||||
*/
|
||||
public void setFilterForTrackableRaces(String filter) {
|
||||
this.filterTrackableRacesField.clear();
|
||||
this.filterTrackableRacesField.sendKeys(filter);
|
||||
getStartTrackingPanel().setFilterForTrackableRaces(filter);
|
||||
}
|
||||
|
||||
// public void setTrackSettings(boolean trackWind, boolean correctWind, boolean simulateWithNow) {
|
||||
// setSelection(this.trackWindCheckBox, trackWind);
|
||||
// setSelection(this.correctWindCheckbox, correctWind);
|
||||
// setSelection(this.simulateWithNowCheckbox, simulateWithNow);
|
||||
// }
|
||||
//
|
||||
// public void startTrackingForRace() {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// public void startTrackingForRaces() {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// private void setSelection(WebElement checkbox, boolean selected) {
|
||||
// WebElement input = checkbox.findElement(By.tagName("input"));
|
||||
// if(input.isSelected() != selected)
|
||||
// input.click();
|
||||
// }
|
||||
public void startTracking(String regattaName, String raceName) {
|
||||
getStartTrackingPanel().startTracking(regattaName, raceName);
|
||||
}
|
||||
|
||||
public void waitForTrackedRaceLoadingFinished(String regattaName, String raceName, long timeoutInMillis) throws InterruptedException {
|
||||
waitForAjaxRequests(); // wait for the Start Tracking request to succeed; then check Tracked races table and keep refreshing until we time out
|
||||
TrackedRacesPanel trp = getTrackedRacesPanel();
|
||||
long started = System.currentTimeMillis();
|
||||
WebElement raceRow = trp.getTrackedRace(regattaName, raceName);
|
||||
while ((raceRow == null || !"TRACKING".equals(raceRow.findElements(By.tagName("td")).get(6).getText()))
|
||||
&& System.currentTimeMillis()-started < timeoutInMillis) {
|
||||
Thread.sleep(2000); // wait 2s for the race to appear
|
||||
trp.refresh();
|
||||
raceRow = trp.getTrackedRace(regattaName, raceName);
|
||||
}
|
||||
}
|
||||
|
||||
private TrackedRacesPanel getTrackedRacesPanel() {
|
||||
return new TrackedRacesPanel(driver, trackedRacesPanel);
|
||||
}
|
||||
|
||||
public void stopTracking(String regattaName, String raceName) {
|
||||
final TrackedRacesPanel trp = getTrackedRacesPanel();
|
||||
trp.getTrackedRace(regattaName, raceName).click();
|
||||
trp.stopTracking();
|
||||
}
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
package com.sap.sailing.selenium.test.adminconsole.pages;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.openqa.selenium.Alert;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.NoAlertPresentException;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
||||
import com.sap.sailing.selenium.core.BySeleniumId;
|
||||
import com.sap.sailing.selenium.core.FindBy;
|
||||
import com.sap.sailing.selenium.test.PageArea;
|
||||
|
||||
public class TracTracStartTrackingPanel extends PageArea {
|
||||
private static final Logger logger = Logger.getLogger(TracTracStartTrackingPanel.class.getName());
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "TrackWind")
|
||||
private WebElement trackWindCheckbox;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "FilterRaces")
|
||||
private WebElement filterTrackableRacesField;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "StartTracking")
|
||||
private WebElement startTrackingButton;
|
||||
|
||||
public TracTracStartTrackingPanel(WebDriver driver, WebElement element) {
|
||||
super(driver, element);
|
||||
}
|
||||
|
||||
public void setTrackWind(boolean trackWind) {
|
||||
setSelection(trackWindCheckbox, trackWind);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Returns the list of all available trackable races. This list will be empty if no race is available or if no race
|
||||
* was specified before.
|
||||
* </p>
|
||||
*
|
||||
* @return The list of all available trackable races.
|
||||
*/
|
||||
public List<WebElement> getTrackableRaces() {
|
||||
WebElement availableRacesTabel = findElementBySeleniumId(this.context, "RacesTable"); //$NON-NLS-1$
|
||||
List<WebElement> elements = availableRacesTabel.findElements(By.xpath("./tbody/tr")); //$NON-NLS-1$
|
||||
Iterator<WebElement> iterator = elements.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
WebElement element = iterator.next();
|
||||
if (!element.isDisplayed()) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Sets the filter for the trackable races. After the filter is set you can obtain the new resulting list via
|
||||
* {@link #getTrackableRaces}</p>
|
||||
*
|
||||
* @param filter
|
||||
* The filter to apply to the trackable races.
|
||||
*/
|
||||
public void setFilterForTrackableRaces(String filter) {
|
||||
this.filterTrackableRacesField.clear();
|
||||
this.filterTrackableRacesField.sendKeys(filter);
|
||||
}
|
||||
|
||||
private void setSelection(WebElement checkbox, boolean selected) {
|
||||
WebElement input = checkbox.findElement(By.tagName("input"));
|
||||
if (input.isSelected() != selected) {
|
||||
input.click();
|
||||
}
|
||||
}
|
||||
|
||||
private WebElement getTrackableRace(String regattaName, String raceName) {
|
||||
for (WebElement trackableRace : getTrackableRaces()) {
|
||||
List<WebElement> fields = trackableRace.findElements(By.tagName("td"));
|
||||
if (regattaName.equals(fields.get(0).getText()) && raceName.equals(fields.get(1).getText())) {
|
||||
return trackableRace;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void startTracking(String regattaName, String raceName) {
|
||||
getTrackableRace(regattaName, raceName).findElements(By.tagName("td")).get(0).click();
|
||||
startTrackingButton.click();
|
||||
try {
|
||||
// there may be an alert that there already is some default regatta; ignore it
|
||||
Alert alert = driver.switchTo().alert();
|
||||
if (alert != null) {
|
||||
alert.accept();
|
||||
}
|
||||
} catch (NoAlertPresentException e) {
|
||||
logger.log(Level.WARNING, "No alert found when starting to track race; probably there is no regatta for its class yet", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package com.sap.sailing.selenium.test.adminconsole.pages;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
||||
import com.sap.sailing.selenium.core.BySeleniumId;
|
||||
import com.sap.sailing.selenium.core.FindBy;
|
||||
import com.sap.sailing.selenium.test.PageArea;
|
||||
import com.sap.sailing.selenium.test.gwt.widgets.CellTable;
|
||||
|
||||
public class TrackedRacesPanel extends PageArea {
|
||||
@FindBy(how = BySeleniumId.class, using = "TrackedRacesFilter")
|
||||
private WebElement filterTestBox;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "Refresh")
|
||||
private WebElement refreshButton;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "RemoveRace")
|
||||
private WebElement removeButton;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "UntrackRace")
|
||||
private WebElement stopTrackingButton;
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "TrackedRacesTable")
|
||||
private WebElement trackedRacesTable;
|
||||
|
||||
public TrackedRacesPanel(WebDriver driver, WebElement element) {
|
||||
super(driver, element);
|
||||
}
|
||||
|
||||
public Iterable<WebElement> getTrackedRaces() {
|
||||
return new CellTable(driver, trackedRacesTable).getRows();
|
||||
}
|
||||
|
||||
public WebElement getTrackedRace(String regattaName, String raceName) {
|
||||
for (WebElement raceRow : getTrackedRaces()) {
|
||||
List<WebElement> fields = raceRow.findElements(By.tagName("td"));
|
||||
if (regattaName.equals(fields.get(0).getText()) && raceName.equals(fields.get(2).getText())) {
|
||||
return raceRow;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
refreshButton.click();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
removeButton.click();
|
||||
}
|
||||
|
||||
public void stopTracking() {
|
||||
stopTrackingButton.click();
|
||||
}
|
||||
}
|
||||
java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/gwt/widgets/AbstractDialog.java
Executable
+41
@@ -0,0 +1,41 @@
|
||||
package com.sap.sailing.selenium.test.gwt.widgets;
|
||||
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
||||
import com.sap.sailing.selenium.core.BySeleniumId;
|
||||
import com.sap.sailing.selenium.core.FindBy;
|
||||
import com.sap.sailing.selenium.test.PageArea;
|
||||
|
||||
public class AbstractDialog extends PageArea {
|
||||
@FindBy(how = BySeleniumId.class, using = "OkButton")
|
||||
private WebElement okButton;
|
||||
@FindBy(how = BySeleniumId.class, using = "CancelButton")
|
||||
private WebElement cancelButton;
|
||||
@FindBy(how = BySeleniumId.class, using = "StatusLabel")
|
||||
private WebElement statusLabel;
|
||||
|
||||
public AbstractDialog(WebDriver driver, WebElement element) {
|
||||
super(driver, element);
|
||||
}
|
||||
|
||||
public boolean isOkEnabled() {
|
||||
return this.okButton.isEnabled();
|
||||
}
|
||||
|
||||
public String getErrorMessage() {
|
||||
return this.statusLabel.getText();
|
||||
}
|
||||
|
||||
public void pressOk() {
|
||||
this.okButton.click();
|
||||
|
||||
// Wait, since we create the flexible leader board
|
||||
waitForAjaxRequests();
|
||||
}
|
||||
|
||||
public void pressCancel() {
|
||||
this.cancelButton.click();
|
||||
}
|
||||
|
||||
}
|
||||
+35
-34
@@ -12,87 +12,88 @@ import org.openqa.selenium.WebElement;
|
||||
import com.sap.sailing.selenium.test.PageObject;
|
||||
|
||||
/**
|
||||
* <p></p>
|
||||
* <p>
|
||||
* </p>
|
||||
*
|
||||
* @author
|
||||
* D049941
|
||||
* @author D049941
|
||||
*/
|
||||
public class CellTable extends PageObject {
|
||||
/**
|
||||
* <p></p>
|
||||
* <p>
|
||||
* </p>
|
||||
*
|
||||
* @param driver
|
||||
*
|
||||
*
|
||||
* @param element
|
||||
*
|
||||
*
|
||||
*/
|
||||
public CellTable(WebDriver driver, WebElement element) {
|
||||
super(driver, element);
|
||||
}
|
||||
|
||||
|
||||
public List<String> getHeaders() {
|
||||
List<String> headers = new ArrayList<>();
|
||||
|
||||
for(WebElement header : findHeaders()) {
|
||||
|
||||
for (WebElement header : findHeaders()) {
|
||||
headers.add(header.getText());
|
||||
}
|
||||
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
|
||||
public void clickHeader(String name) {
|
||||
for(WebElement header : findHeaders()) {
|
||||
if(name.equals(header.getText()))
|
||||
for (WebElement header : findHeaders()) {
|
||||
if (name.equals(header.getText())) {
|
||||
header.click();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<WebElement> getRows() {
|
||||
List<WebElement> bodies = this.context.findElements(By.tagName("tbody"));
|
||||
|
||||
for(WebElement body : bodies) {
|
||||
if(!body.isDisplayed())
|
||||
|
||||
for (WebElement body : bodies) {
|
||||
if (!body.isDisplayed()) {
|
||||
continue;
|
||||
|
||||
}
|
||||
List<WebElement> rows = body.findElements(By.tagName("tr"));
|
||||
|
||||
|
||||
Iterator<WebElement> iterator = rows.iterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
WebElement row = iterator.next();
|
||||
|
||||
if(isRowForLoadingAnimation(row))
|
||||
|
||||
if (isRowForLoadingAnimation(row))
|
||||
iterator.remove();
|
||||
}
|
||||
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void verify() {
|
||||
// TODO: Verify that the context represents a GWT CellTable
|
||||
String tagName = ((WebElement) this.context).getTagName();
|
||||
|
||||
if(!tagName.equalsIgnoreCase("table"))
|
||||
if (!tagName.equalsIgnoreCase("table")) {
|
||||
throw new IllegalArgumentException("WebElement does not represent a table");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private List<WebElement> findHeaders() {
|
||||
return this.context.findElements(By.tagName("th"));
|
||||
}
|
||||
|
||||
|
||||
private boolean isRowForLoadingAnimation(WebElement row) {
|
||||
List<WebElement> images = row.findElements(By.xpath(".//td/div/div/div/img"));
|
||||
|
||||
if(images.isEmpty() || images.size() > 1)
|
||||
|
||||
if (images.isEmpty() || images.size() > 1)
|
||||
return false;
|
||||
|
||||
|
||||
WebElement image = images.get(0);
|
||||
System.out.println(image.getCssValue("background-image"));
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
package com.sap.sailing.selenium.test.leaderboard;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.openqa.selenium.Alert;
|
||||
import org.openqa.selenium.NoAlertPresentException;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
||||
import com.sap.sailing.selenium.core.BySeleniumId;
|
||||
import com.sap.sailing.selenium.core.FindBy;
|
||||
import com.sap.sailing.selenium.test.HostPage;
|
||||
|
||||
/**
|
||||
* <p>The page object representing the administration console. The console consists of multiple tabs with its content
|
||||
* between you can switch.</p>
|
||||
*
|
||||
* @author
|
||||
* D049941
|
||||
*/
|
||||
public class LeaderboardEditingPage extends HostPage {
|
||||
private static final String PAGE_TITLE = "SAP Sailing Analytics Leaderboard Editing"; //$NON-NLS-1$
|
||||
|
||||
private static final Logger logger = Logger.getLogger(LeaderboardEditingPage.class.getName());
|
||||
|
||||
@FindBy(how = BySeleniumId.class, using = "EditableLeaderboardPanel")
|
||||
private WebElement editableLeaderboardPanel;
|
||||
|
||||
/**
|
||||
* <p>Goes to the administration console and returns the representing page object.</p>
|
||||
*
|
||||
* @param driver
|
||||
* The web driver to use.
|
||||
* @param root
|
||||
* The context root of the application.
|
||||
* @return
|
||||
* The page object for the administration console.
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
public static LeaderboardEditingPage goToPage(String leaderboardName, WebDriver driver, String root) throws UnsupportedEncodingException {
|
||||
driver.get(root + "gwt/LeaderboardEditing.html?name="+leaderboardName + "&" + System.getProperty("gwt.codesvr", "")); //$NON-NLS-1$
|
||||
try {
|
||||
Alert alert = driver.switchTo().alert();
|
||||
if (alert != null) {
|
||||
alert.accept();
|
||||
}
|
||||
} catch (NoAlertPresentException e) {
|
||||
logger.log(Level.INFO, "No alert message found; probably already logged in: "+e.getMessage());
|
||||
}
|
||||
return new LeaderboardEditingPage(driver);
|
||||
}
|
||||
|
||||
private LeaderboardEditingPage(WebDriver driver) {
|
||||
super(driver);
|
||||
}
|
||||
|
||||
public LeaderboardTable getLeaderboardTable() {
|
||||
return new LeaderboardTable(this.driver, findElementBySeleniumId(context, "LeaderboardTable"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Verifies that the current page is the leaderboard editing page by checking the title of the page.</p>
|
||||
*/
|
||||
@Override
|
||||
protected void verify() {
|
||||
if (!PAGE_TITLE.equals(this.driver.getTitle())) {
|
||||
throw new IllegalStateException("This is not the administration console: " + this.driver.getTitle()); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.sap.sailing.selenium.test.leaderboard;
|
||||
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
||||
import com.sap.sailing.selenium.test.PageArea;
|
||||
import com.sap.sailing.selenium.test.gwt.widgets.CellTable;
|
||||
|
||||
public class LeaderboardTable extends PageArea {
|
||||
|
||||
private final CellTable table;
|
||||
|
||||
public LeaderboardTable(WebDriver driver, WebElement element) {
|
||||
super(driver, element);
|
||||
this.table = new CellTable(driver, (WebElement) context);
|
||||
}
|
||||
|
||||
public Iterable<String> getColumnNames() {
|
||||
return table.getHeaders();
|
||||
}
|
||||
|
||||
public Iterable<WebElement> getRows() {
|
||||
return table.getRows();
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
package com.sap.sailing.selenium.test.leaderboard;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.selenium.test.AbstractSeleniumTest;
|
||||
import com.sap.sailing.selenium.test.adminconsole.pages.AdminConsolePage;
|
||||
import com.sap.sailing.selenium.test.adminconsole.pages.FlexibleLeaderboardCreationDialog;
|
||||
import com.sap.sailing.selenium.test.adminconsole.pages.LeaderboardConfigurationPanel;
|
||||
import com.sap.sailing.selenium.test.adminconsole.pages.TracTracEventManagementPanel;
|
||||
import com.sap.sailing.selenium.test.adminconsole.pages.TracTracStartTrackingPanel;
|
||||
|
||||
public class TestLeaderboardEditing extends AbstractSeleniumTest {
|
||||
private static final String BMW_CUP_JSON_URL = "http://kml.skitrac.traclive.dk/events/event_20120803_BMWCup/jsonservice.php"; //$NON-NLS-1$
|
||||
private static final String BMW_CUP_RACE_8 = "BMW Cup Race 8";
|
||||
private static final String BMW_CUP_REGATTA = "BMW Cup";
|
||||
private static final String BMW_CUP_BOAT_CLASS = "J80";
|
||||
|
||||
@Test
|
||||
public void testSimpleLeaderboardEditing() throws UnsupportedEncodingException, InterruptedException {
|
||||
final String leaderboardName = "Humba Humba";
|
||||
createNewLeaderboardLoadRaceAndLink(leaderboardName);
|
||||
LeaderboardEditingPage page = LeaderboardEditingPage.goToPage(leaderboardName, getWebDriver(), getContextRoot());
|
||||
LeaderboardTable table = page.getLeaderboardTable();
|
||||
assertNotNull(table);
|
||||
Iterable<WebElement> rows = table.getRows();
|
||||
assertEquals("Expected 6 rows for the six competitors but found only "+Util.size(rows), 6, Util.size(rows));
|
||||
}
|
||||
|
||||
private void createNewLeaderboardLoadRaceAndLink(String leaderboardName) throws InterruptedException {
|
||||
AdminConsolePage adminConsole = AdminConsolePage.goToPage(getWebDriver(), getContextRoot());
|
||||
LeaderboardConfigurationPanel leaderboardConfiguration = createLeaderboard(leaderboardName, adminConsole);
|
||||
startTrackingRaceAndWait(adminConsole, BMW_CUP_JSON_URL, BMW_CUP_REGATTA, BMW_CUP_RACE_8, 30000l /* 30s timeout */);
|
||||
// now create two race columns
|
||||
adminConsole.goToLeaderboardConfiguration();
|
||||
leaderboardConfiguration.selectLeaderboard(leaderboardName);
|
||||
leaderboardConfiguration.addRacesToFlexibleLeaderboard(2);
|
||||
leaderboardConfiguration.selectRaceColumn("R1", "Default");
|
||||
WebElement trackedRace = leaderboardConfiguration.getTrackedRacesPanel().getTrackedRace(BMW_CUP_REGATTA+" ("+BMW_CUP_BOAT_CLASS+")", BMW_CUP_RACE_8);
|
||||
trackedRace.findElements(By.tagName("td")).get(1).click(); // associates the race with the column
|
||||
}
|
||||
|
||||
private void startTrackingRaceAndWait(AdminConsolePage adminConsole, String bmwCupJsonUrl, String bmwCupRegatta, String bmwCupRace8, long l) throws InterruptedException {
|
||||
TracTracEventManagementPanel tracTracEvents = adminConsole.goToTracTracEvents();
|
||||
tracTracEvents.listRaces(BMW_CUP_JSON_URL);
|
||||
Thread.sleep(500); // wait for list to appear; it seems that the waitForAjaxCalls isn't really reliable...
|
||||
TracTracStartTrackingPanel startTrackingPanel = tracTracEvents.getStartTrackingPanel();
|
||||
startTrackingPanel.setTrackWind(false);
|
||||
tracTracEvents.startTracking(BMW_CUP_REGATTA, BMW_CUP_RACE_8);
|
||||
final String trackedRegattaName = BMW_CUP_REGATTA+" ("+BMW_CUP_BOAT_CLASS+")";
|
||||
tracTracEvents.waitForTrackedRaceLoadingFinished(trackedRegattaName, BMW_CUP_RACE_8, 30000l /* 30s timeout */);
|
||||
tracTracEvents.stopTracking(trackedRegattaName, BMW_CUP_RACE_8);
|
||||
}
|
||||
|
||||
private LeaderboardConfigurationPanel createLeaderboard(String leaderboardName, AdminConsolePage adminConsole) {
|
||||
LeaderboardConfigurationPanel leaderboardConfiguration = adminConsole.goToLeaderboardConfiguration();
|
||||
leaderboardConfiguration.deleteLeaderboard(leaderboardName);
|
||||
{
|
||||
FlexibleLeaderboardCreationDialog dialog = leaderboardConfiguration.startCreatingFlexibleLeaderboard();
|
||||
dialog.setName(leaderboardName);
|
||||
assertTrue(dialog.isOkEnabled());
|
||||
dialog.pressOk();
|
||||
}
|
||||
return leaderboardConfiguration;
|
||||
}
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
/bin
|
||||
/bin
|
||||
@@ -26,6 +26,6 @@
|
||||
<booleanAttribute key="tracing" value="false"/>
|
||||
<booleanAttribute key="useCustomFeatures" value="false"/>
|
||||
<booleanAttribute key="useDefaultConfigArea" value="false"/>
|
||||
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils.test@default:false,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.datamining.shared@default:default,com.sap.sailing.datamining@default:default,com.sap.sailing.declination.test@default:false,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.igtimiadapter.persistence@default:default,com.sap.sailing.domain.igtimiadapter@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@5:true,com.sap.sailing.domain.swisstimingreplayadapter@5:true,com.sap.sailing.domain.test@default:default,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter.test@default:false,com.sap.sailing.domain.tractracadapter@5:true,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport.test@default:false,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector.test@default:false,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport.test@default:false,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding.test@default:false,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui.test@default:false,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.kiworesultimport.test@default:false,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.mongodb.test@default:false,com.sap.sailing.mongodb@default:default,com.sap.sailing.operationaltransformation.test@default:false,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@default:default,com.sap.sailing.server.gateway.serialization@default:default,com.sap.sailing.server.gateway.test@default:false,com.sap.sailing.server.gateway@default:default,com.sap.sailing.server.replication.test@default:false,com.sap.sailing.server.replication@default:default,com.sap.sailing.server.test@default:false,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xrr.resultimport.test@default:false,com.sap.sailing.xrr.resultimport@default:default,com.sap.sse.gwt@default:default,com.tractrac.clientmodule@default:default,de.csenk.gwt.ws@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
|
||||
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils.test@default:false,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.datamining.shared@default:default,com.sap.sailing.datamining@default:default,com.sap.sailing.declination.test@default:false,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.igtimiadapter.persistence@default:default,com.sap.sailing.domain.igtimiadapter@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@5:true,com.sap.sailing.domain.swisstimingreplayadapter@5:true,com.sap.sailing.domain.test@default:default,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter.test@default:false,com.sap.sailing.domain.tractracadapter@5:true,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport.test@default:false,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector.test@default:false,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport.test@default:false,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding.test@default:false,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui.test@default:false,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.kiworesultimport.test@default:false,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.mongodb.test@default:false,com.sap.sailing.mongodb@default:default,com.sap.sailing.operationaltransformation.test@default:false,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@default:default,com.sap.sailing.server.gateway.serialization@default:default,com.sap.sailing.server.gateway.test@default:false,com.sap.sailing.server.gateway@default:default,com.sap.sailing.server.replication.test@default:false,com.sap.sailing.server.replication@default:default,com.sap.sailing.server.test@default:false,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xmlexport@default:default,com.sap.sailing.xrr.resultimport.test@default:false,com.sap.sailing.xrr.resultimport@default:default,com.sap.sse.gwt@default:default,com.tractrac.clientmodule@default:default,de.csenk.gwt.ws@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
|
||||
<stringAttribute key="yk-options" value=" additional-options2=onexit\=snapshot "/>
|
||||
</launchConfiguration>
|
||||
@@ -469,7 +469,8 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch
|
||||
int authorPriority, int passId, TimePoint logicalTimePoint, TimePoint startTime);
|
||||
|
||||
/**
|
||||
* Gets the start time and pass identifier for the queried race.
|
||||
* Gets the start time and pass identifier for the queried race. Returns <code>null</code> if there
|
||||
* is no attached race log.
|
||||
*/
|
||||
Pair<TimePoint, Integer> getStartTime(String leaderboardName, String raceColumnName, String fleetName);
|
||||
|
||||
|
||||
+97
-49
@@ -152,6 +152,8 @@ import com.sap.sailing.server.operationaltransformation.UpdateTrackedRaceStatus;
|
||||
import com.sap.sailing.server.operationaltransformation.UpdateWindAveragingTime;
|
||||
import com.sap.sailing.server.operationaltransformation.UpdateWindSourcesToExclude;
|
||||
import com.sap.sailing.util.BuildVersion;
|
||||
import com.sap.sailing.util.impl.LockUtil;
|
||||
import com.sap.sailing.util.impl.NamedReentrantReadWriteLock;
|
||||
|
||||
public class RacingEventServiceImpl implements RacingEventService, RegattaListener, LeaderboardRegistry, Replicator {
|
||||
private static final Logger logger = Logger.getLogger(RacingEventServiceImpl.class.getName());
|
||||
@@ -184,6 +186,21 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
|
||||
* Remembers the trackers by paramURL/liveURI/storedURI to avoid duplication
|
||||
*/
|
||||
protected final ConcurrentHashMap<Object, RaceTracker> raceTrackersByID;
|
||||
|
||||
/**
|
||||
* {@link #addRace(RegattaIdentifier, RaceTrackingConnectivityParameters, long)} will check
|
||||
* {@link #raceTrackersByID} for the presence of a tracker and won't create a new tracker if one for the
|
||||
* connectivity parameters' ID already exists. This check and creation and addition to {@link #raceTrackersByID}
|
||||
* requires locking in the face of concurrent calls to
|
||||
* {@link #addRace(RegattaIdentifier, RaceTrackingConnectivityParameters, long)}. Using <code>synchronized</code> is
|
||||
* not ideal due to its coarse-grained locking style which allows for little concurrency. Instead, this map is used
|
||||
* to keep locks for any ID that any invocation of the
|
||||
* {@link #addRace(RegattaIdentifier, RaceTrackingConnectivityParameters, long)} method is currently working on.
|
||||
* Fetching or creating and putting a lock to this map happens in a synchronized method ({@link #getOrCreateRaceTrackersByIdLock}).
|
||||
* When done, the {@link #addRace(RegattaIdentifier, RaceTrackingConnectivityParameters, long)} method cleans up by
|
||||
* removing the lock again from this map, again using a synchronized method ({@link #removeRaceTrackersByIdLock}).
|
||||
*/
|
||||
private final ConcurrentHashMap<Object, NamedReentrantReadWriteLock> raceTrackersByIDLocks;
|
||||
|
||||
/**
|
||||
* Leaderboards managed by this racing event service
|
||||
@@ -285,14 +302,15 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
|
||||
this.mongoObjectFactory = mongoObjectFactory;
|
||||
regattasByName = new ConcurrentHashMap<String, Regatta>();
|
||||
eventsById = new ConcurrentHashMap<Serializable, Event>();
|
||||
regattaTrackingCache = new ConcurrentHashMap<Regatta, DynamicTrackedRegatta>();
|
||||
raceTrackersByRegatta = new ConcurrentHashMap<Regatta, Set<RaceTracker>>();
|
||||
raceTrackersByID = new ConcurrentHashMap<Object, RaceTracker>();
|
||||
leaderboardGroupsByName = new ConcurrentHashMap<String, LeaderboardGroup>();
|
||||
regattaTrackingCache = new ConcurrentHashMap<>();
|
||||
raceTrackersByRegatta = new ConcurrentHashMap<>();
|
||||
raceTrackersByID = new ConcurrentHashMap<>();
|
||||
raceTrackersByIDLocks = new ConcurrentHashMap<>();
|
||||
leaderboardGroupsByName = new ConcurrentHashMap<>();
|
||||
leaderboardsByName = new ConcurrentHashMap<String, Leaderboard>();
|
||||
operationExecutionListeners = new ConcurrentHashMap<OperationExecutionListener, OperationExecutionListener>();
|
||||
courseListeners = new ConcurrentHashMap<RaceDefinition, CourseChangeReplicator>();
|
||||
persistentRegattasForRaceIDs = new ConcurrentHashMap<String, Regatta>();
|
||||
operationExecutionListeners = new ConcurrentHashMap<>();
|
||||
courseListeners = new ConcurrentHashMap<>();
|
||||
persistentRegattasForRaceIDs = new ConcurrentHashMap<>();
|
||||
this.raceLogReplicator = new RaceLogReplicator(this);
|
||||
this.raceLogScoringReplicator = new RaceLogScoringReplicator(this);
|
||||
this.mediaDB = mediaDb;
|
||||
@@ -796,59 +814,89 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
|
||||
public void raceRemoved(Regatta regatta, RaceDefinition raceDefinition) {
|
||||
raceDefinition.getCourse().removeCourseListener(courseListeners.remove(raceDefinition));
|
||||
}
|
||||
|
||||
private NamedReentrantReadWriteLock lockRaceTrackersById(Object trackerId) {
|
||||
NamedReentrantReadWriteLock lock;
|
||||
synchronized (raceTrackersByIDLocks) {
|
||||
lock = raceTrackersByIDLocks.get(trackerId);
|
||||
if (lock == null) {
|
||||
lock = new NamedReentrantReadWriteLock("raceTrackersByIDLock for "+trackerId, /* fair */ false);
|
||||
raceTrackersByIDLocks.put(trackerId, lock);
|
||||
}
|
||||
}
|
||||
LockUtil.lockForWrite(lock);
|
||||
return lock;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param lock
|
||||
* need to pass the lock obtained from {@link #lockRaceTrackersById(Object)} because a competing thread
|
||||
* may already have removed the lock from the {@link #raceTrackersByIDLocks} map
|
||||
*/
|
||||
private synchronized void unlockRaceTrackersById(Object trackerId, NamedReentrantReadWriteLock lock) {
|
||||
LockUtil.unlockAfterWrite(lock);
|
||||
synchronized (raceTrackersByIDLocks) {
|
||||
raceTrackersByIDLocks.remove(trackerId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RacesHandle addRace(RegattaIdentifier regattaToAddTo, RaceTrackingConnectivityParameters params,
|
||||
long timeoutInMilliseconds) throws Exception {
|
||||
RaceTracker tracker = raceTrackersByID.get(params.getTrackerID());
|
||||
if (tracker == null) {
|
||||
Regatta regatta = regattaToAddTo == null ? null : getRegatta(regattaToAddTo);
|
||||
if (regatta == null) {
|
||||
// create tracker and use an existing or create a default regatta
|
||||
tracker = params.createRaceTracker(this, windStore);
|
||||
} else {
|
||||
// use the regatta selected by the RaceIdentifier regattaToAddTo
|
||||
tracker = params.createRaceTracker(regatta, this, windStore);
|
||||
assert tracker.getRegatta() == regatta;
|
||||
}
|
||||
synchronized (raceTrackersByRegatta) {
|
||||
raceTrackersByID.put(params.getTrackerID(), tracker);
|
||||
Set<RaceTracker> trackers = raceTrackersByRegatta.get(tracker.getRegatta());
|
||||
if (trackers == null) {
|
||||
trackers = new HashSet<RaceTracker>();
|
||||
raceTrackersByRegatta.put(tracker.getRegatta(), trackers);
|
||||
final Object trackerID = params.getTrackerID();
|
||||
NamedReentrantReadWriteLock raceTrackersByIdLock = lockRaceTrackersById(trackerID);
|
||||
try {
|
||||
RaceTracker tracker = raceTrackersByID.get(trackerID);
|
||||
if (tracker == null) {
|
||||
Regatta regatta = regattaToAddTo == null ? null : getRegatta(regattaToAddTo);
|
||||
if (regatta == null) {
|
||||
// create tracker and use an existing or create a default regatta
|
||||
tracker = params.createRaceTracker(this, windStore);
|
||||
} else {
|
||||
// use the regatta selected by the RaceIdentifier regattaToAddTo
|
||||
tracker = params.createRaceTracker(regatta, this, windStore);
|
||||
assert tracker.getRegatta() == regatta;
|
||||
}
|
||||
trackers.add(tracker);
|
||||
}
|
||||
// TODO we assume here that the event name is unique which necessitates adding the boat class name to it in
|
||||
// EventImpl constructor
|
||||
String regattaName = tracker.getRegatta().getName();
|
||||
Regatta regattaWithName = regattasByName.get(regattaName);
|
||||
// TODO we assume here that the event name is unique which necessitates adding the boat class name to it in
|
||||
// EventImpl constructor
|
||||
if (regattaWithName != null) {
|
||||
if (regattaWithName != tracker.getRegatta()) {
|
||||
if (Util.isEmpty(regattaWithName.getAllRaces())) {
|
||||
// probably, tracker removed the last races from the old regatta and created a new one
|
||||
cacheAndReplicateDefaultRegatta(tracker.getRegatta());
|
||||
} else {
|
||||
throw new RuntimeException("Internal error. Two Event objects with equal name " + regattaName);
|
||||
synchronized (raceTrackersByRegatta) {
|
||||
raceTrackersByID.put(trackerID, tracker);
|
||||
Set<RaceTracker> trackers = raceTrackersByRegatta.get(tracker.getRegatta());
|
||||
if (trackers == null) {
|
||||
trackers = new HashSet<RaceTracker>();
|
||||
raceTrackersByRegatta.put(tracker.getRegatta(), trackers);
|
||||
}
|
||||
trackers.add(tracker);
|
||||
}
|
||||
// TODO we assume here that the event name is unique which necessitates adding the boat class name to it in EventImpl constructor
|
||||
String regattaName = tracker.getRegatta().getName();
|
||||
Regatta regattaWithName = regattasByName.get(regattaName);
|
||||
// TODO we assume here that the event name is unique which necessitates adding the boat class name to it in EventImpl constructor
|
||||
if (regattaWithName != null) {
|
||||
if (regattaWithName != tracker.getRegatta()) {
|
||||
if (Util.isEmpty(regattaWithName.getAllRaces())) {
|
||||
// probably, tracker removed the last races from the old regatta and created a new one
|
||||
regattasByName.remove(regattaName);
|
||||
cacheAndReplicateDefaultRegatta(tracker.getRegatta());
|
||||
} else {
|
||||
throw new RuntimeException("Internal error. Two Event objects with equal name " + regattaName);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cacheAndReplicateDefaultRegatta(tracker.getRegatta());
|
||||
}
|
||||
} else {
|
||||
cacheAndReplicateDefaultRegatta(tracker.getRegatta());
|
||||
WindStore existingTrackersWindStore = tracker.getWindStore();
|
||||
if (!existingTrackersWindStore.equals(windStore)) {
|
||||
logger.warning("Wind store mismatch. Requested wind store: " + windStore
|
||||
+ ". Wind store in use by existing tracker: " + existingTrackersWindStore);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
WindStore existingTrackersWindStore = tracker.getWindStore();
|
||||
if (!existingTrackersWindStore.equals(windStore)) {
|
||||
logger.warning("Wind store mismatch. Requested wind store: " + windStore
|
||||
+ ". Wind store in use by existing tracker: " + existingTrackersWindStore);
|
||||
if (timeoutInMilliseconds != -1) {
|
||||
scheduleAbortTrackerAfterInitialTimeout(tracker, timeoutInMilliseconds);
|
||||
}
|
||||
return tracker.getRacesHandle();
|
||||
} finally {
|
||||
unlockRaceTrackersById(trackerID, raceTrackersByIdLock);
|
||||
}
|
||||
if (timeoutInMilliseconds != -1) {
|
||||
scheduleAbortTrackerAfterInitialTimeout(tracker, timeoutInMilliseconds);
|
||||
}
|
||||
return tracker.getRacesHandle();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -90,7 +90,6 @@ public class LeaderboardData extends ExportAction {
|
||||
}
|
||||
|
||||
private Element createLeaderboardXML(Leaderboard leaderboard, List<Element> competitors, List<Element> races, Pair<Double, Vector<String>> leaderboardConfidenceAndErrorMessages) {
|
||||
log.info("Creating XML for leaderboard " + leaderboard.getName());
|
||||
Element leaderboardElement = new Element("leaderboard");
|
||||
addNamedElementWithValue(leaderboardElement, "name", leaderboard.getName());
|
||||
addNamedElementWithValue(leaderboardElement, "display_name", leaderboard.getDisplayName());
|
||||
@@ -101,7 +100,6 @@ public class LeaderboardData extends ExportAction {
|
||||
leaderboardElement.addContent(createDataConfidenceXML(leaderboardConfidenceAndErrorMessages));
|
||||
leaderboardElement.addContent(competitors);
|
||||
leaderboardElement.addContent(races);
|
||||
log.info("Done with XML for leaderboard " + leaderboard.getName());
|
||||
return leaderboardElement;
|
||||
}
|
||||
|
||||
@@ -135,7 +133,6 @@ public class LeaderboardData extends ExportAction {
|
||||
}
|
||||
|
||||
public List<Element> createWindXML(String prefix, SpeedWithConfidence<TimePoint> speedWithConfidence) {
|
||||
log.info("Creating XML for wind " + prefix);
|
||||
List<Element> windElements = new ArrayList<Element>();
|
||||
if (speedWithConfidence == null) {
|
||||
speedWithConfidence = new SpeedWithConfidenceImpl<TimePoint>(new KnotSpeedImpl(0.0), 0, MillisecondsTimePoint.now());
|
||||
@@ -169,18 +166,16 @@ public class LeaderboardData extends ExportAction {
|
||||
}
|
||||
windElements.add(createNamedElementWithValue(prefix+"human_readable", windSpeedAsHumanReadableString));
|
||||
windElements.add(createNamedElementWithValue(prefix+"knots_interval", windSpeedAsInterval));
|
||||
log.info("Done with XML for wind " + prefix);
|
||||
return windElements;
|
||||
}
|
||||
|
||||
private Element createRaceXML(final TrackedRace race, final Fleet fleet, final List<Element> legs, final RaceColumn column, final Leaderboard leaderboard, int sameDayGroupIndex, int raceCounter, Pair<Double, Vector<String>> raceConfidenceAndErrorMessages) throws NoWindException, IOException, ServletException {
|
||||
log.info("Creating XML for race " + race.getRace().getName());
|
||||
Element raceElement = new Element("race");
|
||||
addNamedElementWithValue(raceElement, "name", cleanRaceName(race.getRace().getName()));
|
||||
addNamedElementWithValue(raceElement, "race_index_in_leaderboard", raceCounter);
|
||||
addNamedElementWithValue(raceElement, "fleet_name", fleet.getName());
|
||||
addNamedElementWithValue(raceElement, "same_day_index", sameDayGroupIndex);
|
||||
raceElement.addContent(createDataConfidenceXML(raceConfidenceAndErrorMessages));
|
||||
addNamedElementWithValue(raceElement, "is_live", race.isLive(MillisecondsTimePoint.now()) ? "true" : "false");
|
||||
|
||||
addNamedElementWithValue(raceElement, "start_type", race.getTrackedLeg(race.getRace().getCourse().getFirstLeg()).getLegType(race.getStartOfRace()).name());
|
||||
addNamedElementWithValue(raceElement, "delay_to_live_in_millis", race.getDelayToLiveInMillis());
|
||||
@@ -189,6 +184,13 @@ public class LeaderboardData extends ExportAction {
|
||||
addNamedElementWithValue(raceElement, "timepoint_of_newest_event_as_millis", handleValue(race.getTimePointOfNewestEvent()));
|
||||
addNamedElementWithValue(raceElement, "timepoint_of_oldest_event_as_millis", handleValue(race.getTimePointOfOldestEvent()));
|
||||
|
||||
if (race.isLive(MillisecondsTimePoint.now())) {
|
||||
// we can't tell meaningful values about live races
|
||||
raceElement.addContent(createDataConfidenceXML(raceConfidenceAndErrorMessages));
|
||||
raceElement.addContent(legs);
|
||||
return raceElement;
|
||||
}
|
||||
|
||||
raceElement.addContent(createTimedXML("start_time_", race.getStartOfRace()));
|
||||
raceElement.addContent(createTimedXML("end_time_", race.getEndOfRace()));
|
||||
addNamedElementWithValue(raceElement, "start_of_tracking_time_as_millis", handleValue(race.getStartOfTracking()));
|
||||
@@ -244,6 +246,7 @@ public class LeaderboardData extends ExportAction {
|
||||
// we do not want to include competitors that did not start the race
|
||||
competitorElement.addContent(competitorRaceDataElement);
|
||||
raceElement.addContent(competitorElement);
|
||||
raceConfidenceAndErrorMessages.getB().add("Competitor " + competitor.getName() + " has no valid data for this race!");
|
||||
continue;
|
||||
}
|
||||
int[] timePointsInSecondsBeforeStart = new int[]{5, 10, 20, 30};
|
||||
@@ -260,6 +263,9 @@ public class LeaderboardData extends ExportAction {
|
||||
addNamedElementWithValue(competitorRaceDataElement, "start_advantage_in_meters", start.getAdvantage().getMeters());
|
||||
addNamedElementWithValue(competitorRaceDataElement, "advantageous_side_while_approaching_start_line", start.getAdvantageousSideWhileApproachingLine().name());
|
||||
Distance distanceTraveledInThisRace = race.getDistanceTraveled(competitor, race.getEndOfRace());
|
||||
if (distanceTraveledInThisRace == null) {
|
||||
raceConfidenceAndErrorMessages.getB().add("Competitor " + competitor.getName() + " has no valid distance traveled for this race!");
|
||||
}
|
||||
addNamedElementWithValue(competitorRaceDataElement, "distance_traveled_in_meters", distanceTraveledInThisRace == null ? 0.0 : distanceTraveledInThisRace.getMeters());
|
||||
addNamedElementWithValue(competitorRaceDataElement, "distance_traveled_including_non_finished_legs_in_meters", getDistanceTraveled(race, competitor, race.getEndOfRace(), /*alsoReturnDistanceIfCompetitorHasNotFinishedRace*/ true).getMeters());
|
||||
Speed averageSpeedOverGround = getAverageSpeedOverGround(race, competitor, race.getEndOfRace(), true);
|
||||
@@ -269,6 +275,7 @@ public class LeaderboardData extends ExportAction {
|
||||
if (trackedLegOfCompetitor != null && trackedLegOfCompetitor.getFinishTime() != null) {
|
||||
addNamedElementWithValue(competitorRaceDataElement, "rank_at_end_of_first_leg", trackedLegOfCompetitor.getRank(trackedLegOfCompetitor.getFinishTime()));
|
||||
} else {
|
||||
raceConfidenceAndErrorMessages.getB().add("It seems that competitor " + competitor.getName() + " has not finished first leg!");
|
||||
addNamedElementWithValue(competitorRaceDataElement, "rank_at_end_of_first_leg", 0);
|
||||
}
|
||||
Double finalRaceScore = leaderboard.getTotalPoints(competitor, column, race.getEndOfRace());
|
||||
@@ -280,12 +287,13 @@ public class LeaderboardData extends ExportAction {
|
||||
raceElement.addContent(competitorElement);
|
||||
}
|
||||
|
||||
raceElement.addContent(createDataConfidenceXML(raceConfidenceAndErrorMessages));
|
||||
raceElement.addContent(legs);
|
||||
log.info("Done with XML for race " + race.getRace().getName());
|
||||
return raceElement;
|
||||
}
|
||||
|
||||
private Element createCompetitorXML(Competitor competitor, Leaderboard leaderboard, boolean shortVersion, Pair<Double, Vector<String>> competitorConfidenceAndErrorMessages) throws NoWindException, IOException, ServletException {
|
||||
TimePoint timeSpent = MillisecondsTimePoint.now();
|
||||
Element competitorElement = new Element("competitor");
|
||||
addNamedElementWithValue(competitorElement, "uuid", competitor.getId().toString());
|
||||
addNamedElementWithValue(competitorElement, "name", competitor.getName());
|
||||
@@ -293,9 +301,6 @@ public class LeaderboardData extends ExportAction {
|
||||
if (shortVersion)
|
||||
return competitorElement;
|
||||
|
||||
log.info("Creating XML for competitor " + competitor.getName());
|
||||
createDataConfidenceXML(competitorConfidenceAndErrorMessages);
|
||||
|
||||
if (competitor.getBoat() != null) {
|
||||
addNamedElementWithValue(competitorElement, "sail_id", cleanSailId(competitor.getBoat().getSailID(), competitor));
|
||||
addNamedElementWithValue(competitorElement, "boat_class", competitor.getBoat().getBoatClass().getName());
|
||||
@@ -322,10 +327,17 @@ public class LeaderboardData extends ExportAction {
|
||||
Distance totalDistanceSailed = leaderboard.getTotalDistanceTraveled(competitor, timePointOfLatestModification);
|
||||
addNamedElementWithValue(competitorElement, "total_distance_sailed_in_meters", totalDistanceSailed != null ? totalDistanceSailed.getMeters() : 0);
|
||||
addNamedElementWithValue(competitorElement, "total_distance_sailed_including_non_finished_races_in_meters", getTotalDistanceTraveled(leaderboard, competitor, timePointOfLatestModification).getMeters());
|
||||
if (totalDistanceSailed == null) {
|
||||
competitorConfidenceAndErrorMessages.getB().add("Competitor has not finished all races in this leaderboard! His distance sailed is not comparable to others!");
|
||||
}
|
||||
addNamedElementWithValue(competitorElement, "maximum_speed_over_ground_in_knots", leaderboard.getMaximumSpeedOverGround(competitor, timePointOfLatestModification).getB().getKnots());
|
||||
Speed averageSpeed = leaderboard.getAverageSpeedOverGround(competitor, timePointOfLatestModification);
|
||||
addNamedElementWithValue(competitorElement, "average_speed_over_ground_from_start_mark_passing_in_knots", averageSpeed != null ? averageSpeed.getKnots() : 0);
|
||||
addNamedElementWithValue(competitorElement, "average_speed_over_ground_including_non_finished_races_in_knots", getAverageSpeedOverGround(leaderboard, competitor, timePointOfLatestModification, true).getKnots());
|
||||
if (averageSpeed == null) {
|
||||
competitorConfidenceAndErrorMessages.getB().add("Competitor has not finished all races in this leaderboard! His average speed over ground is not comparable to others!");
|
||||
}
|
||||
Speed averageSpeedOverGroundIncludingNonCompletedRaces = getAverageSpeedOverGround(leaderboard, competitor, timePointOfLatestModification, true);
|
||||
addNamedElementWithValue(competitorElement, "average_speed_over_ground_including_non_finished_races_in_knots", averageSpeedOverGroundIncludingNonCompletedRaces == null ? 0 : averageSpeedOverGroundIncludingNonCompletedRaces.getKnots());
|
||||
|
||||
addNamedElementWithValue(competitorElement, "overall_rank", leaderboard.getTotalRankOfCompetitor(competitor, timePointOfLatestModification));
|
||||
addNamedElementWithValue(competitorElement, "overall_score", leaderboard.getTotalPoints(competitor, timePointOfLatestModification));
|
||||
@@ -333,25 +345,38 @@ public class LeaderboardData extends ExportAction {
|
||||
TimePoint now = MillisecondsTimePoint.now();
|
||||
addNamedElementWithValue(competitorElement, "total_time_sailed_in_milliseconds", leaderboard.getTotalTimeSailedInMilliseconds(competitor, now));
|
||||
addNamedElementWithValue(competitorElement, "total_time_sailed_including_non_finished_races_in_milliseconds", getTotalTimeSailedInMilliseconds(competitor, now, true));
|
||||
addNamedElementWithValue(competitorElement, "total_distance_sailed_in_meters", leaderboard.getTotalDistanceTraveled(competitor, now).getMeters());
|
||||
Distance totalDistanceSailed = leaderboard.getTotalDistanceTraveled(competitor, now);
|
||||
addNamedElementWithValue(competitorElement, "total_distance_sailed_in_meters", totalDistanceSailed != null ? totalDistanceSailed.getMeters() : 0);
|
||||
if (totalDistanceSailed == null) {
|
||||
competitorConfidenceAndErrorMessages.getB().add("Competitor has not finished all races in this leaderboard! His distance sailed is not comparable to others!");
|
||||
}
|
||||
addNamedElementWithValue(competitorElement, "total_distance_sailed_including_non_finished_races_in_meters", getTotalDistanceTraveled(leaderboard, competitor, now).getMeters());
|
||||
addNamedElementWithValue(competitorElement, "maximum_speed_over_ground_in_knots", leaderboard.getMaximumSpeedOverGround(competitor, now).getB().getKnots());
|
||||
Speed averageSpeed = leaderboard.getAverageSpeedOverGround(competitor, now);
|
||||
addNamedElementWithValue(competitorElement, "average_speed_over_ground_from_start_mark_passing_in_knots", averageSpeed != null ? averageSpeed.getKnots() : 0);
|
||||
addNamedElementWithValue(competitorElement, "average_speed_over_ground_including_non_finished_races_in_knots", getAverageSpeedOverGround(leaderboard, competitor, now, true).getKnots());
|
||||
if (averageSpeed == null) {
|
||||
competitorConfidenceAndErrorMessages.getB().add("Competitor has not finished all races in this leaderboard! His average speed over ground is not comparable to others!");
|
||||
}
|
||||
Speed averageSpeedOverGroundIncludingNonCompletedRaces = getAverageSpeedOverGround(leaderboard, competitor, now, true);
|
||||
addNamedElementWithValue(competitorElement, "average_speed_over_ground_including_non_finished_races_in_knots", averageSpeedOverGroundIncludingNonCompletedRaces == null ? 0 : averageSpeedOverGroundIncludingNonCompletedRaces.getKnots());
|
||||
|
||||
addNamedElementWithValue(competitorElement, "overall_rank", leaderboard.getTotalRankOfCompetitor(competitor, now));
|
||||
addNamedElementWithValue(competitorElement, "overall_score", leaderboard.getTotalPoints(competitor, now));
|
||||
}
|
||||
log.info("Done with XML for competitor " + competitor.getName());
|
||||
competitorElement.addContent(createDataConfidenceXML(competitorConfidenceAndErrorMessages));
|
||||
TimePoint elapsedTime = MillisecondsTimePoint.now().minus(timeSpent.asMillis());
|
||||
addNamedElementWithValue(competitorElement, "generation_time_in_milliseconds", elapsedTime.asMillis());
|
||||
return competitorElement;
|
||||
}
|
||||
|
||||
private Element createLegXML(TrackedLeg trackedLeg, Leaderboard leaderboard, int legCounter, Pair<Double, Vector<String>> raceConfidenceAndErrorMessages, Pair<Double, Vector<String>> legConfidenceAndErrorMessages) throws NoWindException, IOException, ServletException {
|
||||
log.info("Creating XML for leg " + trackedLeg.getTrackedRace().getRace().getName() + ":" + legCounter);
|
||||
TimePoint timeSpent = MillisecondsTimePoint.now();
|
||||
Leg leg = trackedLeg.getLeg();
|
||||
Element legElement = new Element("leg");
|
||||
legElement.addContent(createDataConfidenceXML(legConfidenceAndErrorMessages));
|
||||
if (trackedLeg.getTrackedRace().isLive(MillisecondsTimePoint.now())) {
|
||||
return legElement;
|
||||
}
|
||||
addNamedElementWithValue(legElement, "position", legCounter);
|
||||
addNamedElementWithValue(legElement, "mark_from", leg.getFrom().getName());
|
||||
addNamedElementWithValue(legElement, "mark_to", leg.getTo().getName());
|
||||
@@ -373,6 +398,9 @@ public class LeaderboardData extends ExportAction {
|
||||
competitorLegDataElement.addContent(createTimedXML("leg_started_time_", competitorLeg.getStartTime()));
|
||||
Pair<GPSFixMoving, Speed> maximumSpeed = competitorLeg.getMaximumSpeedOverGround(legFinishTime);
|
||||
addNamedElementWithValue(competitorLegDataElement, "maximum_speed_over_ground_in_knots", maximumSpeed != null ? maximumSpeed.getB().getKnots() : -1);
|
||||
if (maximumSpeed == null) {
|
||||
legConfidenceAndErrorMessages.getB().add("Competitor "+ competitor.getName() +" has not finished this leg! His maximum speed for this leg is not comparable to others!");
|
||||
}
|
||||
addNamedElementWithValue(competitorLegDataElement, "average_velocity_made_good_in_knots", competitorLeg.getAverageVelocityMadeGood(legFinishTime).getKnots());
|
||||
addNamedElementWithValue(competitorLegDataElement, "leg_finished_time_as_millis", handleValue(legFinishTime));
|
||||
addNamedElementWithValue(competitorLegDataElement, "total_race_time_elapsed_as_millis", handleValue(legFinishTime)-handleValue(trackedLeg.getTrackedRace().getStartOfRace()));
|
||||
@@ -414,7 +442,8 @@ public class LeaderboardData extends ExportAction {
|
||||
competitorElement.addContent(competitorLegDataElement);
|
||||
legElement.addContent(competitorElement);
|
||||
}
|
||||
log.info("Done with XML for leg " + trackedLeg.getTrackedRace().getRace().getName() + ":" + legCounter);
|
||||
TimePoint elapsedTime = MillisecondsTimePoint.now().minus(timeSpent.asMillis());
|
||||
addNamedElementWithValue(legElement, "generation_time_in_milliseconds", elapsedTime.asMillis());
|
||||
return legElement;
|
||||
}
|
||||
|
||||
@@ -490,6 +519,9 @@ public class LeaderboardData extends ExportAction {
|
||||
messages.add("End tracking time of race " + race.getRaceIdentifier().getRaceName() + " is either null or not valid!");
|
||||
simpleConfidence -= 0.2;
|
||||
}
|
||||
if (race.isLive(MillisecondsTimePoint.now())) {
|
||||
messages.add("This race is live - data for this race will not be available until the race has been finished!");
|
||||
}
|
||||
return new Pair<Double, Vector<String>>(simpleConfidence, messages);
|
||||
}
|
||||
|
||||
@@ -537,7 +569,7 @@ public class LeaderboardData extends ExportAction {
|
||||
simpleConfidence -= 1.0;
|
||||
}
|
||||
TimePoint dateAtYear2000 = new MillisecondsTimePoint(946681200000l);
|
||||
if (leaderboard.getTimePointOfLatestModification().before(dateAtYear2000)) {
|
||||
if (leaderboard.getTimePointOfLatestModification() != null && leaderboard.getTimePointOfLatestModification().before(dateAtYear2000)) {
|
||||
messages.add("The time point of the last modification for this leaderboard is very old.");
|
||||
simpleConfidence -= 0.4;
|
||||
}
|
||||
@@ -567,6 +599,8 @@ public class LeaderboardData extends ExportAction {
|
||||
|
||||
public void perform() throws Exception {
|
||||
final Leaderboard leaderboard = getLeaderboard();
|
||||
TimePoint timeSpent = MillisecondsTimePoint.now();
|
||||
log.info("Starting XML export of " + leaderboard.getName());
|
||||
Pair<Double, Vector<String>> leaderboardConfidenceAndErrorMessages = checkData(leaderboard);
|
||||
|
||||
final List<Element> racesElements = new ArrayList<Element>();
|
||||
@@ -577,14 +611,13 @@ public class LeaderboardData extends ExportAction {
|
||||
competitorElements.add(createCompetitorXML(competitor, leaderboard, /*shortVersion*/ false, competitorConfidenceAndErrorMessages));
|
||||
}
|
||||
|
||||
TrackedRace raceBefore = null; int sameDayGroupIndex = 0;
|
||||
TrackedRace raceBefore = null; int sameDayGroupIndex = 0; int raceCounter = 0;
|
||||
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
||||
for (Fleet fleet : raceColumn.getFleets()) {
|
||||
sameDayGroupIndex += getSameDayGroupIndex(raceColumn.getTrackedRace(fleet), raceBefore);
|
||||
int raceCounter = 0;
|
||||
TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
|
||||
if (trackedRace != null && trackedRace.hasGPSData()) {
|
||||
raceCounter++;
|
||||
TimePoint timeSpentForRace = MillisecondsTimePoint.now();
|
||||
Pair<Double, Vector<String>> raceConfidenceAndErrorMessages = checkData(trackedRace);
|
||||
final List<Element> legs = new ArrayList<Element>();
|
||||
int legCounter = 0;
|
||||
@@ -592,12 +625,17 @@ public class LeaderboardData extends ExportAction {
|
||||
Pair<Double, Vector<String>> legConfidenceAndErrorMessages = checkData(leg);
|
||||
legs.add(createLegXML(leg, leaderboard, ++legCounter, raceConfidenceAndErrorMessages, legConfidenceAndErrorMessages));
|
||||
}
|
||||
racesElements.add(createRaceXML(trackedRace, fleet, legs, raceColumn, leaderboard, sameDayGroupIndex, raceCounter, raceConfidenceAndErrorMessages));
|
||||
Element raceElement = createRaceXML(trackedRace, fleet, legs, raceColumn, leaderboard, sameDayGroupIndex, ++raceCounter, raceConfidenceAndErrorMessages);
|
||||
TimePoint elapsedTimeForRace = MillisecondsTimePoint.now().minus(timeSpentForRace.asMillis());
|
||||
addNamedElementWithValue(raceElement, "generation_time_in_milliseconds", elapsedTimeForRace.asMillis());
|
||||
racesElements.add(raceElement);
|
||||
log.info("Exported complete race " + trackedRace.getRace().getName() + " in " + elapsedTimeForRace.asMillis() + " milliseconds!");
|
||||
raceBefore = trackedRace;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.info("Finished XML export of leaderboard " + leaderboard.getName() + " in " + MillisecondsTimePoint.now().minus(timeSpent.asMillis()).asMillis() + " milliseconds");
|
||||
sendDocument(createLeaderboardXML(leaderboard, competitorElements, racesElements, leaderboardConfidenceAndErrorMessages), leaderboard.getName() + ".xml");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry exported="true" kind="lib" path="selenium-java-2.39.0.jar"/>
|
||||
<classpathentry exported="true" kind="lib" path="lib/apache-mime4j-0.6.jar"/>
|
||||
<classpathentry exported="true" kind="lib" path="lib/bsh-1.3.0.jar"/>
|
||||
<classpathentry exported="true" kind="lib" path="lib/cglib-nodep-2.1_3.jar"/>
|
||||
@@ -37,7 +38,6 @@
|
||||
<classpathentry exported="true" kind="lib" path="lib/xalan-2.7.1.jar"/>
|
||||
<classpathentry exported="true" kind="lib" path="lib/xercesImpl-2.10.0.jar"/>
|
||||
<classpathentry exported="true" kind="lib" path="lib/xml-apis-1.4.01.jar"/>
|
||||
<classpathentry exported="true" kind="lib" path="selenium-java-2.34.0.jar"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
|
||||
@@ -2,8 +2,8 @@ Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Selenium
|
||||
Bundle-SymbolicName: org.openqa.selenium.osgi
|
||||
Bundle-Version: 2.34.0
|
||||
Bundle-ClassPath: selenium-java-2.34.0.jar,
|
||||
Bundle-Version: 2.39.0
|
||||
Bundle-ClassPath: selenium-java-2.39.0.jar,
|
||||
lib/apache-mime4j-0.6.jar,
|
||||
lib/bsh-1.3.0.jar,
|
||||
lib/cglib-nodep-2.1_3.jar,
|
||||
|
||||
@@ -20,7 +20,6 @@ bin.includes = META-INF/,\
|
||||
lib/testng-6.8.5.jar,\
|
||||
lib/xercesImpl-2.10.0.jar,\
|
||||
lib/xml-apis-1.4.01.jar,\
|
||||
selenium-java-2.34.0.jar,\
|
||||
lib/apache-mime4j-0.6.jar,\
|
||||
lib/bsh-1.3.0.jar,\
|
||||
lib/cglib-nodep-2.1_3.jar,\
|
||||
@@ -36,4 +35,5 @@ bin.includes = META-INF/,\
|
||||
lib/protobuf-java-2.4.1.jar,\
|
||||
lib/sac-1.3.jar,\
|
||||
lib/serializer-2.7.1.jar,\
|
||||
lib/xalan-2.7.1.jar
|
||||
lib/xalan-2.7.1.jar,\
|
||||
selenium-java-2.39.0.jar
|
||||
@@ -8,6 +8,6 @@
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>org.openqa.selenium.osgi</artifactId>
|
||||
<version>2.34.0</version>
|
||||
<version>2.39.0</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
</project>
|
||||
Binary file not shown.
BIN
Binary file not shown.
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>com.sap.sailing.racecommittee.app.test</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
+1
-1
@@ -73,7 +73,7 @@ public class PreferencesDeviceConfigurationLoader implements ConfigurationLoader
|
||||
}
|
||||
|
||||
private static void logApply(String configurationName, Object value) {
|
||||
ExLog.i(TAG, String.format("Applied '%s' configuration: %s.", configurationName, value.toString()));
|
||||
ExLog.i(TAG, String.format("Applied '%s' configuration: %s.", configurationName, value==null?"null":value.toString()));
|
||||
}
|
||||
|
||||
}
|
||||
+2
-1
@@ -76,7 +76,8 @@ public class FlagPoleStateRenderer {
|
||||
}
|
||||
|
||||
private int getFleetColorId() {
|
||||
Triple<Integer, Integer, Integer> rgb = race.getFleet().getColor().getAsRGB();
|
||||
Triple<Integer, Integer, Integer> rgb = race.getFleet().getColor() == null ?
|
||||
new Triple<Integer, Integer, Integer>(0, 0, 0) : race.getFleet().getColor().getAsRGB();
|
||||
return Color.rgb(rgb.getA(), rgb.getB(), rgb.getC());
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
Our current server deployment uses a 64bit Java7 Hotspot virtual machine and runs on a 64bit Linux CentOS distribution. We have a single host (sapsailing.com) which runs a number of Java VMs, some to offer the application in different development stages (dev, test, prod, ...), some to perform specific tasks such as replicating UDP wind data to the various server processes, or a process to store data received from the SwissTiming connector durably while forwarding that data to a server VM requesting it.
|
||||
|
||||
The various processes run in "tmux" sessions to which, once connected to sapsailing.com with an ssh client, users can gain access using the `tmux -2 attach-session -t sailing` command. The tmux environment including is started automagically upon system boot by invoking the script _/home/trac/servers/tmuxManagementConsole.sh_.
|
||||
The various processes run in "tmux" sessions to which, once connected to the desired EC2 instance with an ssh client and becoming the sailing user 'su - sailing', users can gain access using the `tmux attach` command. The tmux environment including is started automagically upon system boot by invoking the script _/home/trac/servers/tmuxManagementConsole.sh_.
|
||||
|
||||
For the OSGi containers by convention we have one directory under _/home/trac/servers/_ per deployable branch (dev, test, prod1, prod2). In those directories we have copies of the "install" script from the git's java/target folder. Running it after a successful product build on the branch corresponding to the current directory will copy the compiled product to the server directory. Running the start script will then launch the respective server instance. A safety check in the install script avoids accidentally overwriting a server directory with a non-matching product version by comparing the directory name with the branch name checked out under _/home/trac/git_.
|
||||
|
||||
@@ -254,4 +254,4 @@ MongoDB configuration can be found in /opt/mongodb/etc. This service is automati
|
||||
|
||||
### MySQL
|
||||
|
||||
MySQL serves as database backend for Piwik and Bugzilla. Configuration can be found in /etc/my.cnf and database files in /var/lib/mysql.
|
||||
MySQL serves as database backend for Piwik and Bugzilla. Configuration can be found in /etc/my.cnf and database files in /var/lib/mysql.
|
||||
Reference in new issue
Block a user