3-table course designer

This commit is contained in:
Fredrik Teschke committed 2014-04-24 06:59:25 +02:00
1 parent 7fa3e066b6
commit 70ae0e9543
15 files changed
+577 -466

No files matched your search

@@ -0,0 +1,41 @@
package com.sap.sailing.gwt.ui.adminconsole;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.view.client.SelectionModel;
import com.sap.sailing.gwt.ui.client.ErrorReporter;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.ControlPointDTO;
import com.sap.sailing.gwt.ui.shared.GateDTO;
import com.sap.sailing.gwt.ui.shared.MarkDTO;
public class ControlPointTableWrapper<S extends SelectionModel<ControlPointDTO>> extends TableWrapper<ControlPointDTO, S> {
public ControlPointTableWrapper(S selectionModel, SailingServiceAsync sailingService, final StringMessages stringMessages,
ErrorReporter errorReporter) {
super(sailingService, stringMessages, errorReporter, selectionModel);
mainPanel.add(table);
TextColumn<ControlPointDTO> nameColumn = new TextColumn<ControlPointDTO>() {
@Override
public String getValue(ControlPointDTO d) {
return d.getName();
}
};
table.addColumn(nameColumn, stringMessages.name());
TextColumn<ControlPointDTO> typeColumn = new TextColumn<ControlPointDTO>() {
@Override
public String getValue(ControlPointDTO d) {
if (d instanceof GateDTO) {
return "2x " + stringMessages.mark();
} else if (d instanceof MarkDTO) {
return stringMessages.mark();
} else {
return stringMessages.unknown();
}
}
};
table.addColumn(typeColumn, stringMessages.type());
}
}
@@ -1,34 +1,28 @@
package com.sap.sailing.gwt.ui.adminconsole;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.Map;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.FontWeight;
import com.google.gwt.core.shared.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CaptionPanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.MultiSelectionModel;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SelectionChangeEvent.Handler;
import com.google.gwt.view.client.SetSelectionModel;
import com.google.gwt.view.client.SingleSelectionModel;
import com.sap.sailing.domain.common.PassingInstruction;
import com.sap.sailing.domain.common.impl.Util.Pair;
import com.sap.sailing.domain.common.impl.Util;
import com.sap.sailing.gwt.ui.client.ErrorReporter;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
@@ -40,180 +34,25 @@ import com.sap.sailing.gwt.ui.shared.WaypointDTO;
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
public abstract class CourseManagementWidget implements IsWidget {
/**
* Represents one mark assignment for a control point. Gates have multiple such records, one for each of their marks.
*
* @author Axel Uhl (D043530)
*/
public static class ControlPointAndOldAndNewMark {
protected final ControlPointDTO controlPoint;
protected final MarkDTO oldMark;
protected MarkDTO newMark;
protected PassingInstruction passingInstructions;
public ControlPointAndOldAndNewMark(ControlPointDTO controlPoint, PassingInstruction passingInstructions, MarkDTO oldMark) {
super();
this.controlPoint = controlPoint;
this.passingInstructions = passingInstructions;
this.oldMark = oldMark;
this.newMark = oldMark;
}
public PassingInstruction getPassingInstructions() {
return passingInstructions;
}
public MarkDTO getNewMark() {
return newMark;
}
public void setNewMark(MarkDTO newMark) {
this.newMark = newMark;
}
public ControlPointDTO getControlPoint() {
return controlPoint;
}
public MarkDTO getOldMark() {
return oldMark;
}
}
protected final MarkTableWrapper<MultiSelectionModel<MarkDTO>> marks;
protected final ControlPointTableWrapper<MultiSelectionModel<ControlPointDTO>> multiMarkControlPoints;
protected final WaypointTableWrapper<SingleSelectionModel<WaypointDTO>> waypoints;
private class ControlPointCreationDialog extends DataEntryDialog<Pair<ControlPointDTO, PassingInstruction>> {
private final MarkTableWrapper<MultiSelectionModel<MarkDTO>> marksTable;
private final MultiSelectionModel<MarkDTO> selectionModel;
private final ListBox passingInstructions;
private final StringMessages stringMessages;
public ControlPointCreationDialog(final StringMessages stringMessages, AdminConsoleTableResources tableRes,
List<MarkDTO> marks, DialogCallback<Pair<ControlPointDTO, PassingInstruction>> callback) {
super(stringMessages.controlPoint(), stringMessages.selectOneMarkOrTwoMarksForGate(),
stringMessages.ok(), stringMessages.cancel(), new DataEntryDialog.Validator<Pair<ControlPointDTO, PassingInstruction>>() {
@Override
public String getErrorMessage(Pair<ControlPointDTO, PassingInstruction> valueToValidate) {
if (valueToValidate.getA() == null) {
return stringMessages.selectOneMarkOrTwoMarksForGate();
} else {
return null;
}
}
}, /* animationEnabled */ false, callback);
this.stringMessages = stringMessages;
selectionModel = new MultiSelectionModel<MarkDTO>();
selectionModel.addSelectionChangeHandler(new Handler() {
@Override
public void onSelectionChange(SelectionChangeEvent event) {
updatePassingInstructions();
validate();
}
});
marksTable = new MarkTableWrapper<MultiSelectionModel<MarkDTO>>(
selectionModel, CourseManagementWidget.this.sailingService, stringMessages, errorReporter);
marksTable.getDataProvider().getList().addAll(marks);
passingInstructions = createListBox(false);
updatePassingInstructions();
}
private void updatePassingInstructions() {
passingInstructions.clear();
int numSelectedMarks = selectionModel.getSelectedSet().size();
int i = 0;
passingInstructions.insertItem(PassingInstruction.None.name(), i++);
for (PassingInstruction pi : PassingInstruction.relevantValues()) {
for (int numApplicableMarks : pi.applicability) {
if (numApplicableMarks == numSelectedMarks) {
passingInstructions.insertItem(pi.name(), i++);
}
}
}
}
@Override
protected Pair<ControlPointDTO, PassingInstruction> getResult() {
ControlPointDTO controlPoint = null;
Set<MarkDTO> selection = selectionModel.getSelectedSet();
if (selection.size() == 1) {
controlPoint = selectionModel.getSelectedSet().iterator().next();
} else if (selection.size() == 2) {
Iterator<MarkDTO> i = selectionModel.getSelectedSet().iterator();
MarkDTO first = i.next();
MarkDTO second = i.next();
MarkDTO left;
MarkDTO right;
String gateName;
if (first.getName().matches("^.*"+REGEX_FOR_LEFT+".*$")) {
left = first;
right = second;
} else {
left = second;
right = first;
}
gateName = left.getName().replaceFirst(REGEX_FOR_LEFT, "");
controlPoint = new GateDTO(/* generate UUID on the server */ null, gateName, left, right);
}
PassingInstruction passingInstruction =
passingInstructions.getSelectedIndex() == -1 ? PassingInstruction.None :
PassingInstruction.valueOf(passingInstructions.getValue(passingInstructions.getSelectedIndex()));
return new Pair<ControlPointDTO, PassingInstruction>(controlPoint, passingInstruction);
}
@Override
protected Widget getAdditionalWidget() {
Grid grid = new Grid(2,1);
grid.setWidget(0, 0, marksTable);
HorizontalPanel passingInstructionsRow = new HorizontalPanel();
grid.setWidget(1, 0, passingInstructionsRow);
passingInstructionsRow.add(new Label(stringMessages.passingInstructions() + ":"));
passingInstructionsRow.add(passingInstructions);
return grid;
}
}
protected final Grid mainPanel;
protected static final String REGEX_FOR_LEFT = "( \\()?(([lL][eE][fF][tT])|(1))\\)?";
/**
* A table that lists the marks for which events have been received for the race selected. Note that this list may
* be longer than the list of marks actually used by the control points backing the course's waypoints because of
* the possibility of spare marks.
*/
protected final SingleSelectionModel<MarkDTO> markSelectionModel;
/**
* A table that lists the product of Waypoint x ControlPoint x Mark plus a hint as to the number of mark passings.
* The (multi-)selection on this table can be used as either a selection of waypoints or a selection of control points
* or a selection of marks.
*/
protected final CellTable<ControlPointAndOldAndNewMark> controlPointsTable;
protected final MultiSelectionModel<ControlPointAndOldAndNewMark> controlPointsSelectionModel;
protected final ListDataProvider<ControlPointAndOldAndNewMark> controlPointDataProvider;
/**
* When for a control point's mark a replacement mark is defined (see {@link #updateNewMark(Set, MarkDTO)}),
* the control point needs to be replaced before {@link #saveCourse(SailingServiceAsync, StringMessages) saving}.
* Those control points are added to this set. When the mark is reset to the original mark for all the control
* point's marks, the control point is removed from this set again. {@link #saveCourse(SailingServiceAsync, StringMessages)}
* then is responsible for creating replacement {@link ControlPointDTO}s before sending the new control point list to the
* server.
*/
protected final Set<ControlPointDTO> controlPointsNeedingReplacement;
protected final HorizontalPanel courseActionsPanel;
protected final VerticalPanel mainPanel;
protected MarkTableWrapper<SingleSelectionModel<MarkDTO>> marksTable;
protected final Handler markSelectionChangeHandler;
protected final Button insertWaypointBefore;
protected final Button insertWaypointAfter;
protected final Button saveButton;
protected boolean ignoreWaypointAndOldAndNewMarkSelectionChange;
protected final SailingServiceAsync sailingService;
protected final ErrorReporter errorReporter;
protected final StringMessages stringMessages;
protected final HorizontalPanel waypointsBtnsPanel;
protected final HorizontalPanel controlPointsBtnsPanel;
protected final HorizontalPanel marksBtnsPanel;
protected final HorizontalPanel buttonsPanel;
protected final Button insertWaypointBefore;
protected final Button insertWaypointAfter;
protected final AdminConsoleTableResources tableRes = GWT.create(AdminConsoleTableResources.class);
@Override
public Widget asWidget() {
@@ -224,119 +63,101 @@ public abstract class CourseManagementWidget implements IsWidget {
final StringMessages stringMessages) {
this.sailingService = sailingService;
this.errorReporter = errorReporter;
mainPanel = new VerticalPanel();
this.stringMessages = stringMessages;
controlPointsNeedingReplacement = new HashSet<ControlPointDTO>();
Grid grid = new Grid(2, 2);
grid.setCellPadding(5);
mainPanel.add(grid);
mainPanel = new Grid(3, 3);
mainPanel.setCellPadding(5);
mainPanel.getRowFormatter().setVerticalAlign(0, HasVerticalAlignment.ALIGN_TOP);
Label currentRaceCourseLabel = new Label("Current race course");
currentRaceCourseLabel.getElement().getStyle().setFontWeight(FontWeight.BOLD);
grid.setWidget(0, 0, currentRaceCourseLabel);
Label availableMarksLabel = new Label("Available marks");
availableMarksLabel.getElement().getStyle().setFontWeight(FontWeight.BOLD);
grid.setWidget(0, 1, availableMarksLabel);
grid.getRowFormatter().setVerticalAlign(1, HasVerticalAlignment.ALIGN_TOP);
waypoints = new WaypointTableWrapper<SingleSelectionModel<WaypointDTO>>(
new SingleSelectionModel<WaypointDTO>(), sailingService, stringMessages, errorReporter);
multiMarkControlPoints = new ControlPointTableWrapper<MultiSelectionModel<ControlPointDTO>>(
new MultiSelectionModel<ControlPointDTO>(), sailingService, stringMessages, errorReporter);
marks = new MarkTableWrapper<MultiSelectionModel<MarkDTO>>(
new MultiSelectionModel<MarkDTO>(), sailingService, stringMessages, errorReporter);
final AdminConsoleTableResources tableRes = GWT.create(AdminConsoleTableResources.class);
controlPointsTable = new CellTable<ControlPointAndOldAndNewMark>(/* pageSize */10000, tableRes);
grid.setWidget(1, 0, controlPointsTable);
controlPointsSelectionModel = new MultiSelectionModel<ControlPointAndOldAndNewMark>();
controlPointsTable.setSelectionModel(controlPointsSelectionModel);
controlPointsSelectionModel.addSelectionChangeHandler(new Handler() {
@Override
public void onSelectionChange(SelectionChangeEvent event) {
handleControlPointSelectionChange();
}
});
TextColumn<ControlPointAndOldAndNewMark> nameColumn = new TextColumn<ControlPointAndOldAndNewMark>() {
@Override
public String getValue(ControlPointAndOldAndNewMark cpaoanm) {
return cpaoanm.getControlPoint().getName();
}
};
controlPointsTable.addColumn(nameColumn, stringMessages.controlPoint());
TextColumn<ControlPointAndOldAndNewMark> passingInstructionsColumn = new TextColumn<ControlPointAndOldAndNewMark>() {
@Override
public String getValue(ControlPointAndOldAndNewMark cpaoanm) {
String result = "";
if(cpaoanm.getPassingInstructions() != null) {
result = cpaoanm.getPassingInstructions().name();
}
return result;
}
};
controlPointsTable.addColumn(passingInstructionsColumn, "Passing instructions");
TextColumn<ControlPointAndOldAndNewMark> oldMarkColumn = new TextColumn<ControlPointAndOldAndNewMark>() {
@Override
public String getValue(ControlPointAndOldAndNewMark cpaoanm) {
return "" + cpaoanm.getOldMark().getName();
}
};
controlPointsTable.addColumn(oldMarkColumn, stringMessages.mark());
TextColumn<ControlPointAndOldAndNewMark> newMarkColumn = new TextColumn<ControlPointAndOldAndNewMark>(){
@Override
public String getValue(ControlPointAndOldAndNewMark cpaoanm) {
return "" + cpaoanm.getNewMark().getName();
}
};
controlPointsTable.addColumn(newMarkColumn, stringMessages.newMark());
ImagesBarColumn<ControlPointAndOldAndNewMark, CourseManagementWidgetWaypointsImagesBarCell> actionColumn =
new ImagesBarColumn<ControlPointAndOldAndNewMark, CourseManagementWidgetWaypointsImagesBarCell>(
CaptionPanel waypointsPanel = new CaptionPanel(stringMessages.waypoints());
CaptionPanel controlPointsPanel = new CaptionPanel(stringMessages.twoMarkControlPoint());
CaptionPanel marksPanel = new CaptionPanel(stringMessages.mark());
waypointsPanel.add(waypoints);
controlPointsPanel.add(multiMarkControlPoints);
marksPanel.add(marks);
mainPanel.setWidget(0, 0, waypointsPanel);
mainPanel.setWidget(0, 1, controlPointsPanel);
mainPanel.setWidget(0, 2, marksPanel);
waypointsBtnsPanel = new HorizontalPanel();
controlPointsBtnsPanel = new HorizontalPanel();
marksBtnsPanel = new HorizontalPanel();
mainPanel.setWidget(1, 0, waypointsBtnsPanel);
mainPanel.setWidget(1, 1, controlPointsBtnsPanel);
mainPanel.setWidget(1, 2, marksBtnsPanel);
ImagesBarColumn<WaypointDTO, CourseManagementWidgetWaypointsImagesBarCell> waypointsActionColumn =
new ImagesBarColumn<WaypointDTO, CourseManagementWidgetWaypointsImagesBarCell>(
new CourseManagementWidgetWaypointsImagesBarCell(stringMessages));
actionColumn.setFieldUpdater(new FieldUpdater<ControlPointAndOldAndNewMark, String>() {
waypointsActionColumn.setFieldUpdater(new FieldUpdater<WaypointDTO, String>() {
@Override
public void update(int index, ControlPointAndOldAndNewMark controlPoint, String value) {
public void update(int index, WaypointDTO waypoint, String value) {
if (CourseManagementWidgetWaypointsImagesBarCell.ACTION_DELETE.equals(value)) {
removeSelectedWaypoints(sailingService);
removeWaypoint(waypoint);
}
}
});
controlPointsTable.addColumn(actionColumn, stringMessages.actions());
controlPointDataProvider = new ListDataProvider<ControlPointAndOldAndNewMark>();
controlPointDataProvider.addDataDisplay(controlPointsTable);
// race course marks table
markSelectionModel = new SingleSelectionModel<MarkDTO>();
marksTable = new MarkTableWrapper<SingleSelectionModel<MarkDTO>>(markSelectionModel, sailingService, stringMessages, errorReporter);
markSelectionChangeHandler = new Handler() {
waypoints.getTable().addColumn(waypointsActionColumn);
waypoints.getSelectionModel().addSelectionChangeHandler(new Handler() {
@Override
public void onSelectionChange(SelectionChangeEvent event) {
if (!ignoreWaypointAndOldAndNewMarkSelectionChange) {
updateNewMark(controlPointsSelectionModel.getSelectedSet(), markSelectionModel.getSelectedObject());
WaypointDTO waypoint = waypoints.getSelectionModel().getSelectedObject();
if (waypoint != null) {
selectControlPoints(waypoint);
selectMarks(waypoint.marks);
}
updateWaypointButtons();
}
});
multiMarkControlPoints.getSelectionModel().addSelectionChangeHandler(new Handler() {
@Override
public void onSelectionChange(SelectionChangeEvent event) {
if (multiMarkControlPoints.getSelectionModel().getSelectedSet().size() > 0) {
ControlPointDTO first = multiMarkControlPoints.getSelectionModel().getSelectedSet().iterator().next();
selectMarks(first.getMarks());
}
}
};
markSelectionModel.addSelectionChangeHandler(markSelectionChangeHandler);
grid.setWidget(1, 1, marksTable);
courseActionsPanel = new HorizontalPanel();
courseActionsPanel.setSpacing(10);
});
insertWaypointBefore = new Button(stringMessages.insertWaypointBeforeSelected());
insertWaypointBefore.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
insertWaypoint(sailingService, stringMessages, tableRes, /* before */ true);
insertWaypoint(/* before */ true);
}
});
insertWaypointBefore.setEnabled(false);
courseActionsPanel.add(insertWaypointBefore);
waypointsBtnsPanel.add(insertWaypointBefore);
insertWaypointAfter = new Button(stringMessages.insertWaypointAfterSelected());
insertWaypointAfter.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
insertWaypoint(sailingService, stringMessages, tableRes, /* before */ false);
insertWaypoint(/* before */ false);
}
});
insertWaypointAfter.setEnabled(false);
courseActionsPanel.add(insertWaypointAfter);
waypointsBtnsPanel.add(insertWaypointAfter);
final Button addControlPoint = new Button(stringMessages.addGate());
addControlPoint.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
addMultiMarkControlPoint();
}
});
controlPointsBtnsPanel.add(addControlPoint);
buttonsPanel = new HorizontalPanel();
mainPanel.setWidget(2, 2, buttonsPanel);
Button refreshBtn = new Button(stringMessages.refresh());
refreshBtn.addClickHandler(new ClickHandler() {
@Override
@@ -344,178 +165,120 @@ public abstract class CourseManagementWidget implements IsWidget {
refresh();
}
});
courseActionsPanel.add(refreshBtn);
saveButton = new Button(stringMessages.save());
saveButton.addClickHandler(new ClickHandler() {
buttonsPanel.add(refreshBtn);
Button saveBtn = new Button(stringMessages.save());
saveBtn.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
Set<ControlPointDTO> oldControlPointsFromTableAlreadyHandled = new HashSet<ControlPointDTO>();
List<Pair<ControlPointDTO, PassingInstruction>> controlPoints = new ArrayList<Pair<ControlPointDTO, PassingInstruction>>();
for (ControlPointAndOldAndNewMark cpaoanb : controlPointDataProvider.getList()) {
if (!oldControlPointsFromTableAlreadyHandled.contains(cpaoanb.getControlPoint())) {
oldControlPointsFromTableAlreadyHandled.add(cpaoanb.getControlPoint());
ControlPointDTO controlPointToAdd;
if (controlPointsNeedingReplacement.contains(cpaoanb.getControlPoint())) {
if (cpaoanb.getControlPoint() instanceof GateDTO) {
controlPointToAdd = createGate((GateDTO) cpaoanb.getControlPoint());
} else {
controlPointToAdd = cpaoanb.getNewMark();
}
} else {
controlPointToAdd = cpaoanb.getControlPoint();
}
controlPoints.add(new Pair<ControlPointDTO, PassingInstruction>(controlPointToAdd, cpaoanb.passingInstructions));
}
}
saveCourse(controlPoints);
save();
}
});␍ courseActionsPanel.add(saveButton);
// courseActionsPanel.setVisible(false);
mainPanel.add(courseActionsPanel);
});
buttonsPanel.add(saveBtn);
}
private void handleControlPointSelectionChange() {
ignoreWaypointAndOldAndNewMarkSelectionChange = true;
try {
markSelectionModel.setSelected(markSelectionModel.getSelectedObject(), false);
final int selectionSize = controlPointsSelectionModel.getSelectedSet().size();
insertWaypointAfter.setEnabled(selectionSize==1);
insertWaypointBefore.setEnabled(selectionSize==1 || controlPointDataProvider.getList().isEmpty());
if (selectionSize == 1) {
MarkDTO newMark = controlPointsSelectionModel.getSelectedSet().iterator().next().getNewMark();
if (newMark != null) {
for (MarkDTO markDTO : marksTable.getDataProvider().getList()) {
if (markDTO.getName().equals(newMark.getName())) {
markSelectionModel.setSelected(markDTO, true);
}
}
}
}
} finally {
ignoreWaypointAndOldAndNewMarkSelectionChange = false;
private void removeWaypoint(WaypointDTO waypoint) {
waypoints.getDataProvider().getList().remove(waypoint);
}
private void selectControlPoints(WaypointDTO waypoint) {
for (ControlPointDTO controlPoint : multiMarkControlPoints.getDataProvider().getList()) {
multiMarkControlPoints.getSelectionModel().setSelected(
controlPoint, waypoint.controlPoint == controlPoint);
}
}
private void selectMarks(Iterable<MarkDTO> newMarks) {
marks.getSelectionModel().clear();
for (MarkDTO toSelect : newMarks) {
marks.getSelectionModel().setSelected(toSelect, true);
}
}
protected abstract void saveCourse(List<Pair<ControlPointDTO, PassingInstruction>> controlPoints);
/**
* When a gate needs replacement, its entries in {@link #controlPointDataProvider} are looked up, and a new
* {@link GateDTO} is created having the same name as the old gate, but using the new marks as the gate's marks.
*/
protected ControlPointDTO createGate(GateDTO oldGate) {
MarkDTO newLeft = null;
MarkDTO newRight = null;
for (ControlPointAndOldAndNewMark cpaoanb : controlPointDataProvider.getList()) {
if (cpaoanb.getControlPoint() == oldGate) {
MarkDTO newMark = cpaoanb.getNewMark();
if (newRight != null || newMark.getName().matches("^.*"+REGEX_FOR_LEFT+".*$")) {
newLeft = newMark;
} else {
newRight = newMark;
}
}
protected abstract void save();
private <T> T getFirstSelected(SetSelectionModel<T> selectionModel) {
if (selectionModel.getSelectedSet().isEmpty()) {
return null;
}
assert newLeft != null && newRight != null;
// if old gate had null ID, the new gate will have a null ID too, causing the server to generate one
return new GateDTO(oldGate.getIdAsString(), oldGate.getName(), newLeft, newRight);
return selectionModel.getSelectedSet().iterator().next();
}
private void updateNewMark(Set<ControlPointAndOldAndNewMark> selectedWaypointsAndOldAndNewMarks, MarkDTO selectedNewMark) {
if (selectedWaypointsAndOldAndNewMarks != null) {
for (ControlPointAndOldAndNewMark w : selectedWaypointsAndOldAndNewMarks) {
if (selectedNewMark == null) {
w.setNewMark(w.getOldMark());
} else {
w.setNewMark(selectedNewMark);
}
if (w.getOldMark().getName().equals(w.getNewMark().getName())) {
checkIfAllMarksOfControlPointAreUnchangedAndIfSoRememberThis(w.getControlPoint());
} else {
controlPointsNeedingReplacement.add(w.getControlPoint());
}
final int indexOf = controlPointDataProvider.getList().indexOf(w);
if (indexOf != -1) {
controlPointDataProvider.getList().set(indexOf, w);
}
}
private <T> void insert(TableWrapper<T, ? extends SetSelectionModel<T>> tableWrapper, T toInsert, boolean beforeSelection) {
T selected = getFirstSelected(tableWrapper.getSelectionModel());
int index = -1;
if (tableWrapper.getDataProvider().getList().isEmpty()) {
index = 0;
} else if (selected != null) {
index = tableWrapper.getDataProvider().getList().indexOf(selected) + (beforeSelection?0:1);
}
if (index != -1) {
tableWrapper.getDataProvider().getList().add(index, toInsert);
}
}
private void checkIfAllMarksOfControlPointAreUnchangedAndIfSoRememberThis(ControlPointDTO controlPoint) {
boolean allMarksUnchanged = true;
for (ControlPointAndOldAndNewMark cpaoanb : controlPointDataProvider.getList()) {
if (cpaoanb.getControlPoint() == controlPoint) {
if (!cpaoanb.getOldMark().getName().equals(cpaoanb.getNewMark().getName())) {
allMarksUnchanged = false;
break;
}
}
}
if (allMarksUnchanged) {
controlPointsNeedingReplacement.remove(controlPoint);
}
}
private void insertWaypoint(final SailingServiceAsync sailingService, StringMessages stringMessages,
AdminConsoleTableResources tableRes, final boolean beforeSelection) {
new ControlPointCreationDialog(stringMessages, tableRes, marksTable.getDataProvider().getList(), new DataEntryDialog.DialogCallback<Pair<ControlPointDTO, PassingInstruction>>() {
private void addMultiMarkControlPoint() {
new GateCreationDialog(sailingService, errorReporter, stringMessages, tableRes,
marks.getDataProvider().getList(), new DataEntryDialog.DialogCallback<GateDTO>() {
@Override
public void cancel() {
// dialog cancelled, do nothing
}
public void cancel() {}
@Override
public void ok(Pair<ControlPointDTO, PassingInstruction> result) {
Set<ControlPointAndOldAndNewMark> selectedElements = controlPointsSelectionModel.getSelectedSet();
int index = -1;
if (controlPointDataProvider.getList().isEmpty()) {
index = 0;
} else if (!selectedElements.isEmpty()) {
ControlPointAndOldAndNewMark selectedElement = selectedElements.iterator().next();
index = controlPointDataProvider.getList().indexOf(selectedElement) + (beforeSelection?0:1);
}
if (index != -1) {
for (MarkDTO markDTO : result.getA().getMarks()) {
controlPointDataProvider.getList().add(index++, new ControlPointAndOldAndNewMark(result.getA(), result.getB(), markDTO));
}
}
handleControlPointSelectionChange();
public void ok(GateDTO result) {
multiMarkControlPoints.dataProvider.getList().add(result);
}
}).show();
}
private void insertWaypoint(final boolean beforeSelection) {
List<ControlPointDTO> allControlPoints = new ArrayList<>();
allControlPoints.addAll(multiMarkControlPoints.getDataProvider().getList());
allControlPoints.addAll(marks.getDataProvider().getList());
new WaypointCreationDialog(sailingService, errorReporter, stringMessages, tableRes,
allControlPoints, new DataEntryDialog.DialogCallback<WaypointDTO>() {
@Override
public void cancel() {}
@Override
public void ok(WaypointDTO result) {
insert(waypoints, result, beforeSelection);
}
}).show();
}
public abstract void refresh();
protected void updateWaypointTable(RaceCourseDTO raceCourseDTO) {
List<ControlPointAndOldAndNewMark> waypointsAndOldAndNewMarks = new ArrayList<ControlPointAndOldAndNewMark>();
for (WaypointDTO waypointDTO : raceCourseDTO.waypoints) {
ControlPointDTO controlPointDTO = waypointDTO.controlPoint;
for (MarkDTO mark : controlPointDTO.getMarks()) {
ControlPointAndOldAndNewMark waypointAndOldAndNewMark = new ControlPointAndOldAndNewMark(controlPointDTO, waypointDTO.passingInstructions, mark);
waypointsAndOldAndNewMarks.add(waypointAndOldAndNewMark);
protected void updateWaypointsAndControlPoints(RaceCourseDTO raceCourseDTO) {
waypoints.getDataProvider().getList().clear();
multiMarkControlPoints.getDataProvider().getList().clear();
waypoints.getDataProvider().getList().addAll(raceCourseDTO.waypoints);
Map<String, ControlPointDTO> noDuplicateCPs = new HashMap<>();
for (ControlPointDTO controlPoint : raceCourseDTO.getControlPoints()) {
if (controlPoint instanceof GateDTO) {
noDuplicateCPs.put(controlPoint.getIdAsString(), controlPoint);
}
}
controlPointDataProvider.getList().clear();
controlPointDataProvider.getList().addAll(waypointsAndOldAndNewMarks);
controlPointsNeedingReplacement.clear();
for (ControlPointAndOldAndNewMark w : controlPointsSelectionModel.getSelectedSet()) {
controlPointsSelectionModel.setSelected(w, false);
}
multiMarkControlPoints.getDataProvider().getList().addAll(noDuplicateCPs.values());
updateWaypointButtons();
}
private void removeSelectedWaypoints(final SailingServiceAsync sailingService) {
final Set<ControlPointDTO> selectedControlPoints = new HashSet<ControlPointDTO>();
for (ControlPointAndOldAndNewMark cpaoanb : controlPointsSelectionModel.getSelectedSet()) {
selectedControlPoints.add(cpaoanb.getControlPoint());
protected List<Util.Pair<ControlPointDTO, PassingInstruction>> createWaypointPairs() {
List<Util.Pair<ControlPointDTO, PassingInstruction>> result = new ArrayList<>();
for (WaypointDTO waypoint : waypoints.getDataProvider().getList()) {
result.add(new Util.Pair<>(waypoint.controlPoint, waypoint.passingInstructions));
}
for (Iterator<ControlPointAndOldAndNewMark> i=controlPointDataProvider.getList().iterator(); i.hasNext(); ) {
ControlPointAndOldAndNewMark next = i.next();
if (selectedControlPoints.contains(next.getControlPoint())) {
i.remove();
controlPointsSelectionModel.setSelected(next, false);
}
return result;
}
protected void updateWaypointButtons() {
if (waypoints.getDataProvider().getList().isEmpty() ||
waypoints.getSelectionModel().getSelectedObject() != null) {
insertWaypointAfter.setEnabled(true);
insertWaypointBefore.setEnabled(true);
} else {
insertWaypointBefore.setEnabled(false);
insertWaypointAfter.setEnabled(false);
}
handleControlPointSelectionChange();
}
}
@@ -0,0 +1,88 @@
package com.sap.sailing.gwt.ui.adminconsole;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.MultiSelectionModel;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SelectionChangeEvent.Handler;
import com.sap.sailing.gwt.ui.client.ErrorReporter;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.GateDTO;
import com.sap.sailing.gwt.ui.shared.MarkDTO;
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
public class GateCreationDialog extends DataEntryDialog<GateDTO> {
private final MarkTableWrapper<MultiSelectionModel<MarkDTO>> marksWrapper;
private final TextBox name;
private final StringMessages stringMessages;
public GateCreationDialog(SailingServiceAsync sailingService, ErrorReporter errorReporter,
final StringMessages stringMessages, AdminConsoleTableResources tableRes,
List<MarkDTO> marks, DialogCallback<GateDTO> callback) {
super(stringMessages.gate(), stringMessages.gate(),
stringMessages.ok(), stringMessages.cancel(), new DataEntryDialog.Validator<GateDTO>() {
@Override
public String getErrorMessage(GateDTO valueToValidate) {
if (valueToValidate == null) {
return stringMessages.selectTwoMarksForGate();
} else if (valueToValidate.getName() == null || valueToValidate.getName().isEmpty()) {
return stringMessages.pleaseEnterAName();
}
return null;
}
}, /* animationEnabled */ false, callback);
this.stringMessages = stringMessages;
name = createTextBox("");
marksWrapper = new MarkTableWrapper<MultiSelectionModel<MarkDTO>>(
new MultiSelectionModel<MarkDTO>(), sailingService, stringMessages, errorReporter);
marksWrapper.getDataProvider().getList().addAll(marks);
marksWrapper.getSelectionModel().addSelectionChangeHandler(new Handler() {
@Override
public void onSelectionChange(SelectionChangeEvent event) {
validate();
}
});
}
@Override
protected GateDTO getResult() {
GateDTO controlPoint = null;
Set<MarkDTO> selection = marksWrapper.getSelectionModel().getSelectedSet();
if (selection.size() == 2) {
name.setEnabled(true);
Iterator<MarkDTO> i = marksWrapper.getSelectionModel().getSelectedSet().iterator();
MarkDTO first = i.next();
MarkDTO second = i.next();
controlPoint = new GateDTO(/* generate UUID on the server */ null, name.getText(), first, second);
}
return controlPoint;
}
@Override
protected Widget getAdditionalWidget() {
Grid grid = new Grid(2,1);
HorizontalPanel nameRow = new HorizontalPanel();
nameRow.add(new Label(stringMessages.name()));
nameRow.add(name);
grid.setWidget(0, 0, nameRow);
grid.setWidget(1, 0, marksWrapper);
return grid;
}
}
@@ -1,17 +1,13 @@
package com.sap.sailing.gwt.ui.adminconsole;
import java.util.Date;
import java.util.List;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.domain.common.PassingInstruction;
import com.sap.sailing.domain.common.impl.Util.Pair;
import com.sap.sailing.gwt.ui.client.ErrorReporter;
import com.sap.sailing.gwt.ui.client.RegattaRefresher;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.ControlPointDTO;
import com.sap.sailing.gwt.ui.shared.RaceCourseDTO;
/**
@@ -30,10 +26,9 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
super(sailingService, errorReporter, regattaRefresher, stringMessages);
courseManagementWidget = new CourseManagementWidget(sailingService, errorReporter, stringMessages) {
@Override
protected void saveCourse(List<Pair<ControlPointDTO, PassingInstruction>> controlPoints) {
sailingService.updateRaceCourse(singleSelectedRace, controlPoints, new AsyncCallback<Void>() {
protected void save() {
sailingService.updateRaceCourse(singleSelectedRace, createWaypointPairs(), new AsyncCallback<Void>() {
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError(stringMessages.errorUpdatingRaceCourse(caught.getMessage()));
@@ -50,13 +45,13 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
@Override
public void refresh() {
if (singleSelectedRace != null && selectedRaceDTO != null) {
// courseActionsPanel.setVisible(true);
mainPanel.setVisible(true);
// TODO bug 1351: never use System.currentTimeMillis() on the client when trying to compare anything with "server time"; this one is not so urgent as it is reached only in the AdminConsole and we expect administrators to have proper client-side time settings
sailingService.getRaceCourse(singleSelectedRace, new Date(), new AsyncCallback<RaceCourseDTO>() {
@Override
public void onSuccess(RaceCourseDTO raceCourseDTO) {
updateWaypointTable(raceCourseDTO);
marksTable.refresh(raceCourseDTO.getMarks());
updateWaypointsAndControlPoints(raceCourseDTO);
marks.refresh(raceCourseDTO.getMarks());
}
@Override
@@ -67,7 +62,7 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
}
});
} else {
courseActionsPanel.setVisible(false);
mainPanel.setVisible(false);
}
}
};
@@ -1,7 +1,6 @@
package com.sap.sailing.gwt.ui.adminconsole;
import java.util.Collection;
import java.util.List;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.event.dom.client.ClickEvent;
@@ -9,13 +8,10 @@ import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Panel;
import com.sap.sailing.domain.common.PassingInstruction;
import com.sap.sailing.domain.common.dto.PositionDTO;
import com.sap.sailing.domain.common.impl.Util.Pair;
import com.sap.sailing.gwt.ui.client.ErrorReporter;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.ControlPointDTO;
import com.sap.sailing.gwt.ui.shared.MarkDTO;
import com.sap.sailing.gwt.ui.shared.RaceCourseDTO;
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
@@ -51,7 +47,7 @@ public class RaceLogTrackingCourseDefinitionDialog extends RaceLogTrackingDialog
}).show();
}
});
courseActionsPanel.insert(addMark, courseActionsPanel.getWidgetIndex(RaceLogCourseManagementWidget.this.saveButton));
marksBtnsPanel.add(addMark);
Button cancel = new Button(stringMessages.cancel());
@@ -61,7 +57,7 @@ public class RaceLogTrackingCourseDefinitionDialog extends RaceLogTrackingDialog
hide();
}
});
courseActionsPanel.insert(cancel, courseActionsPanel.getWidgetIndex(RaceLogCourseManagementWidget.this.saveButton));
buttonsPanel.add(cancel);
ImagesBarColumn<MarkDTO, RaceLogTrackingCourseDefinitionDialogMarksImagesBarCell> actionColumn =
new ImagesBarColumn<MarkDTO, RaceLogTrackingCourseDefinitionDialogMarksImagesBarCell>(
@@ -96,12 +92,13 @@ public class RaceLogTrackingCourseDefinitionDialog extends RaceLogTrackingDialog
}
}
});
marksTable.getTable().addColumn(actionColumn);
marks.getTable().addColumn(actionColumn);
}
@Override
protected void saveCourse(List<Pair<ControlPointDTO, PassingInstruction>> controlPoints) {
sailingService.addCourseDefinitionToRaceLog(leaderboardName, raceColumnName, fleetName, controlPoints, new AsyncCallback<Void>() {
protected void save() {
sailingService.addCourseDefinitionToRaceLog(leaderboardName, raceColumnName, fleetName,
createWaypointPairs(), new AsyncCallback<Void>() {
@Override
public void onSuccess(Void result) {
hide();
@@ -119,10 +116,7 @@ public class RaceLogTrackingCourseDefinitionDialog extends RaceLogTrackingDialog
sailingService.getLastCourseDefinitionInRaceLog(leaderboardName, raceColumnName, fleetName, new AsyncCallback<RaceCourseDTO>() {
@Override
public void onSuccess(RaceCourseDTO result) {
updateWaypointTable(result);
if (result.waypoints.isEmpty()) {
insertWaypointBefore.setEnabled(true);
}
updateWaypointsAndControlPoints(result);
}
@Override
@@ -134,7 +128,7 @@ public class RaceLogTrackingCourseDefinitionDialog extends RaceLogTrackingDialog
sailingService.getMarksInRaceLog(leaderboardName, raceColumnName, fleetName, new AsyncCallback<Collection<MarkDTO>>() {
@Override
public void onSuccess(Collection<MarkDTO> result) {
marksTable.refresh(result);
marks.refresh(result);
}
@Override
@@ -1,5 +1,7 @@
package com.sap.sailing.gwt.ui.adminconsole;
import java.util.Collection;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.client.ui.IsWidget;
@@ -55,4 +57,10 @@ public abstract class TableWrapper<T, S extends SelectionModel<T>> implements Is
public ListDataProvider<T> getDataProvider() {
return dataProvider;
}
}
public void refresh(Collection<T> newItems) {
dataProvider.getList().clear();
dataProvider.getList().addAll(newItems);
dataProvider.flush();
}
}
@@ -0,0 +1,108 @@
package com.sap.sailing.gwt.ui.adminconsole;
import java.util.ArrayList;
import java.util.List;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SingleSelectionModel;
import com.google.gwt.view.client.SelectionChangeEvent.Handler;
import com.sap.sailing.domain.common.PassingInstruction;
import com.sap.sailing.domain.common.impl.Util;
import com.sap.sailing.gwt.ui.client.ErrorReporter;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.ControlPointDTO;
import com.sap.sailing.gwt.ui.shared.MarkDTO;
import com.sap.sailing.gwt.ui.shared.WaypointDTO;
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
public class WaypointCreationDialog extends DataEntryDialog<WaypointDTO> {
private final ControlPointTableWrapper<SingleSelectionModel<ControlPointDTO>> controlPointsWrapper;
private final ListBox passingInstructions;
private final StringMessages stringMessages;
public WaypointCreationDialog(SailingServiceAsync sailingService, ErrorReporter errorReporter,
final StringMessages stringMessages, AdminConsoleTableResources tableRes,
List<ControlPointDTO> controlPoints, DialogCallback<WaypointDTO> callback) {
super(stringMessages.waypoint(), stringMessages.waypoint(),
stringMessages.ok(), stringMessages.cancel(), new DataEntryDialog.Validator<WaypointDTO>() {
@Override
public String getErrorMessage(WaypointDTO valueToValidate) {
if (valueToValidate.controlPoint == null) {
return stringMessages.pleaseSelectAControlPoint();
}
return null;
}
}, /* animationEnabled */ false, callback);
this.stringMessages = stringMessages;
controlPointsWrapper = new ControlPointTableWrapper<SingleSelectionModel<ControlPointDTO>>(
new SingleSelectionModel<ControlPointDTO>(), sailingService, stringMessages, errorReporter);
controlPointsWrapper.getDataProvider().getList().addAll(controlPoints);
passingInstructions = createListBox(false);
updatePassingInstructions();
controlPointsWrapper.getSelectionModel().addSelectionChangeHandler(new Handler() {
@Override
public void onSelectionChange(SelectionChangeEvent event) {
updatePassingInstructions();
validate();
}
});
}
private void updatePassingInstructions() {
passingInstructions.clear();
int numMarks = controlPointsWrapper.getSelectionModel().getSelectedObject() != null ?
Util.size(controlPointsWrapper.getSelectionModel().getSelectedObject().getMarks()) : 0;
int i = 0;
passingInstructions.insertItem(PassingInstruction.None.name(), i++);
for (PassingInstruction pi : PassingInstruction.relevantValues()) {
for (int numApplicableMarks : pi.applicability) {
if (numApplicableMarks == numMarks) {
passingInstructions.insertItem(pi.name(), i++);
}
}
}
}
@Override
protected WaypointDTO getResult() {
PassingInstruction pi = passingInstructions.getSelectedIndex() > 0 ?
PassingInstruction.valueOf(passingInstructions.getItemText(passingInstructions.getSelectedIndex()))
: PassingInstruction.None;
ControlPointDTO controlPoint = controlPointsWrapper.getSelectionModel().getSelectedObject();
List<MarkDTO> marks = new ArrayList<MarkDTO>();
String name = null;
if (controlPoint != null) {
Util.addAll(controlPoint.getMarks(), marks);
name = controlPoint.getName();
}
return new WaypointDTO(name, controlPoint, marks, pi);
}
@Override
protected Widget getAdditionalWidget() {
Grid grid = new Grid(2,1);
grid.setWidget(0, 0, controlPointsWrapper);
HorizontalPanel passingInstructionsRow = new HorizontalPanel();
grid.setWidget(1, 0, passingInstructionsRow);
passingInstructionsRow.add(new Label(stringMessages.passingInstructions() + ":"));
passingInstructionsRow.add(passingInstructions);
return grid;
}
}
@@ -0,0 +1,51 @@
package com.sap.sailing.gwt.ui.adminconsole;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.view.client.SelectionModel;
import com.sap.sailing.gwt.ui.client.ErrorReporter;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.ControlPointDTO;
import com.sap.sailing.gwt.ui.shared.GateDTO;
import com.sap.sailing.gwt.ui.shared.MarkDTO;
import com.sap.sailing.gwt.ui.shared.WaypointDTO;
public class WaypointTableWrapper<S extends SelectionModel<WaypointDTO>> extends TableWrapper<WaypointDTO, S> {
public WaypointTableWrapper(S selectionModel, SailingServiceAsync sailingService, final StringMessages stringMessages,
ErrorReporter errorReporter) {
super(sailingService, stringMessages, errorReporter, selectionModel);
mainPanel.add(table);
TextColumn<WaypointDTO> nameColumn = new TextColumn<WaypointDTO>() {
@Override
public String getValue(WaypointDTO d) {
return d.controlPoint.getName();
}
};
table.addColumn(nameColumn, stringMessages.controlPoint() + " " + stringMessages.name());
TextColumn<WaypointDTO> typeColumn = new TextColumn<WaypointDTO>() {
@Override
public String getValue(WaypointDTO w) {
ControlPointDTO d = w.controlPoint;
if (d instanceof GateDTO) {
return "2x " + stringMessages.mark();
} else if (d instanceof MarkDTO) {
return stringMessages.mark();
} else {
return stringMessages.unknown();
}
}
};
table.addColumn(typeColumn, stringMessages.type());
TextColumn<WaypointDTO> passingInstructionsColumn = new TextColumn<WaypointDTO>() {
@Override
public String getValue(WaypointDTO waypoint) {
return waypoint.passingInstructions != null ? waypoint.passingInstructions.name() : "";
}
};
table.addColumn(passingInstructionsColumn, stringMessages.passingInstructions());
}
}
@@ -364,11 +364,12 @@ public interface StringMessages extends Messages {
String controlPoint();
String errorUpdatingRaceCourse(String message);
String successfullyUpdatedCourse();
String selectOneMarkOrTwoMarksForGate();
String selectTwoMarksForGate();
String errorTryingToObtainTheMarksOfTheRace(String message);
String errorTryingToObtainRaceCourse(String message);
String insertWaypointBeforeSelected();
String insertWaypointAfterSelected();
String addGate();
String scoringSchemeLowPointSystem();
String scoringSchemeHighPointSystem();
String scoringSchemeLowPointWinnerGetsZero();
@@ -1007,4 +1008,6 @@ public interface StringMessages extends Messages {
String authorPriority();
String removeDenotation();
String competitorRegistrationsMissingProceed(String namesOfRaces);
String pleaseSelectAControlPoint();
String twoMarkControlPoint();
}
@@ -389,11 +389,12 @@ newMark=New Mark
controlPoint=Mark/Gate
errorUpdatingRaceCourse=Error updating race course: {0}
successfullyUpdatedCourse=Successfully updated race course
selectOneMarkOrTwoMarksForGate=Select a single mark or two marks to create a gate
selectTwoMarksForGate=Select two marks to create a gate
errorTryingToObtainTheMarksOfTheRace=Error trying to obtain the marks of the race course: {0}
errorTryingToObtainRaceCourse=Error trying to obtain the race course: {0}
insertWaypointBeforeSelected=Insert waypoint before selected
insertWaypointAfterSelected=Insert waypoint after selected
addGate=Add Gate
scoringSchemeLowPointSystem=Low Point System
scoringSchemeHighPointSystem=High Point System
scoringSchemeHighPointEssOverall=High Point System ESS Overall
@@ -992,4 +993,6 @@ importWindTooltip=Unchecking this option will drastically lower the amount of da
authorName=Author name
authorPriority=Author priority
removeDenotation=Remove Denotation
competitorRegistrationsMissingProceed=At least one of the selected races ({0}) is missing competitor registrations. Proceed anyway?
competitorRegistrationsMissingProceed=At least one of the selected races ({0}) is missing competitor registrations. Proceed anyway?
pleaseSelectAControlPoint=Please select a control point
twoMarkControlPoint=2-mark-controlpoint
@@ -390,11 +390,12 @@ newMark=Neue Marke
controlPoint=Einzelmarke/Gate
errorUpdatingRaceCourse=Fehler beim Aktualisieren des neuen Kurses: {0}
successfullyUpdatedCourse=Kurs erfolgreich aktualisiert
selectOneMarkOrTwoMarksForGate=Eine einzelne Marke auswählen oder zwei Marken, um ein Gate zu erstellen
selectTwoMarksForGate=Zwei Marken auswählen, um ein Gate zu erstellen
errorTryingToObtainTheMarksOfTheRace=Fehler beim Ermitteln der Marken des Regattakurses: {0}
errorTryingToObtainRaceCourse=Fehler beim Ermitteln des Rennkurses: {0}
insertWaypointBeforeSelected=Wegpunkt nach dem selektierten einfügen
insertWaypointAfterSelected=Wegpunkt vor dem selektierten einfügen
addGate=Gate hinzufügen
scoringSchemeLowPointSystem=Low Point System
scoringSchemeHighPointSystem=High Point System
scoringSchemeHighPointEssOverall=High Point System ESS Gesamtwertung
@@ -988,4 +989,6 @@ importWindTooltip=Diese Option zu deselektieren führt zu einer wesentlich klein
authorName=Benutzername
authorPriority=Benutzer-Priorität
removeDenotation=Markierung entfernen
competitorRegistrationsMissingProceed=Für mindestens eins der Rennen ({0}) sind keine Teams registriert. Trotzdem fortfahren?
competitorRegistrationsMissingProceed=Für mindestens eins der Rennen ({0}) sind keine Teams registriert. Trotzdem fortfahren?
pleaseSelectAControlPoint=Bitte eine Einzelmark/ein Gate auswählen
twoMarkControlPoint=2-Marken-Kontrollpunkt
@@ -160,6 +160,7 @@ import com.sap.sailing.domain.common.impl.WindSourceImpl;
import com.sap.sailing.domain.common.racelog.FlagPole;
import com.sap.sailing.domain.common.racelog.Flags;
import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus;
import com.sap.sailing.domain.common.racelog.RacingProcedureType;
import com.sap.sailing.domain.common.racelog.tracking.NoCorrespondingServiceRegisteredException;
import com.sap.sailing.domain.common.racelog.tracking.NotDenotedForRaceLogTrackingException;
import com.sap.sailing.domain.common.racelog.tracking.NotRevokableException;
@@ -167,7 +168,6 @@ import com.sap.sailing.domain.common.racelog.tracking.RaceLogTrackingState;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.common.racelog.tracking.TypeBasedServiceFinder;
import com.sap.sailing.domain.common.racelog.tracking.TypeBasedServiceFinderFactory;
import com.sap.sailing.domain.common.racelog.RacingProcedureType;
import com.sap.sailing.domain.igtimiadapter.Account;
import com.sap.sailing.domain.igtimiadapter.IgtimiConnection;
import com.sap.sailing.domain.igtimiadapter.IgtimiConnectionFactory;
@@ -1633,6 +1633,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
@Override
public RaceCourseDTO getRaceCourse(RegattaAndRaceIdentifier raceIdentifier, Date date) {
List<WaypointDTO> waypointDTOs = new ArrayList<WaypointDTO>();
Map<Serializable, ControlPointDTO> controlPointCache = new HashMap<>();
RaceCourseDTO result = new RaceCourseDTO(waypointDTOs);
if (date != null) {
TimePoint dateAsTimePoint = new MillisecondsTimePoint(date);
@@ -1640,14 +1641,18 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
if (trackedRace != null) {
Course course = trackedRace.getRace().getCourse();
for (Waypoint waypoint : course.getWaypoints()) {
List<MarkDTO> markDTOs = new ArrayList<MarkDTO>();
for (Mark mark : trackedRace.getMarks()) {
List<MarkDTO> marks = new ArrayList<>();
for (Mark mark : waypoint.getMarks()) {
GPSFixTrack<Mark, GPSFix> track = trackedRace.getOrCreateTrack(mark);
Position positionAtDate = track.getEstimatedPosition(dateAsTimePoint, /* extrapolate */false);
markDTOs.add(convertToMarkDTO(mark, positionAtDate));
marks.add(convertToMarkDTO(mark, positionAtDate));
}
ControlPointDTO controlPointDTO = convertToControlPointDTO(waypoint.getControlPoint(), trackedRace, dateAsTimePoint);
WaypointDTO waypointDTO = new WaypointDTO(waypoint.getName(), controlPointDTO, markDTOs, waypoint.getPassingInstructions());
ControlPointDTO controlPointDTO = controlPointCache.get(waypoint.getControlPoint().getId());
if (controlPointDTO == null) {
controlPointDTO = convertToControlPointDTO(waypoint.getControlPoint(), trackedRace, dateAsTimePoint);
controlPointCache.put(waypoint.getControlPoint().getId(), controlPointDTO);
}
WaypointDTO waypointDTO = new WaypointDTO(waypoint.getName(), controlPointDTO, marks, waypoint.getPassingInstructions());
waypointDTOs.add(waypointDTO);
}
}
@@ -1685,29 +1690,34 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
/**
* For each {@link ControlPointDTO} in <code>controlPoints</code> tries to find the best-matching waypoint
* from the {@code old} {@code CourseBase}.
* from the {@code old} {@code CourseBase}, and also from the newly created additional waypoints.
* If such a waypoint is found, its control point is added to the control point list for the new course.
* Otherwise, a new control point is created using the default {@link com.sap.sailing.domain.base.DomainFactory}
* instance.
*/
private List<Pair<ControlPoint, PassingInstruction>> resolveControlPoints(
CourseBase old, List<Pair<ControlPointDTO, PassingInstruction>> controlPoints) {
Map<ControlPointDTO, ControlPoint> newlyCreatedCache = new HashMap<ControlPointDTO, ControlPoint>();
Iterable<Waypoint> waypoints = old.getWaypoints();
List<Pair<ControlPoint, PassingInstruction>> newControlPoints = new ArrayList<Pair<ControlPoint, PassingInstruction>>();
int lastMatchPosition = -1;
for (Pair<ControlPointDTO, PassingInstruction> controlPointAndPassingInstruction : controlPoints) {
ControlPointDTO controlPointDTO = controlPointAndPassingInstruction.getA();
ControlPoint matchFromOldCourse = null;
for (int i=lastMatchPosition+1; matchFromOldCourse == null && i<Util.size(waypoints); i++) {
Waypoint waypointAtI = Util.get(waypoints, i);
ControlPoint controlPointAtI = waypointAtI.getControlPoint();
if (controlPointAtI.getId().toString().equals(controlPointDTO.getIdAsString()) && markIDsMatch(controlPointAtI.getMarks(), controlPointDTO.getMarks())) {
matchFromOldCourse = controlPointAtI;
newControlPoints.add(new Pair<ControlPoint, PassingInstruction>(matchFromOldCourse, null));
lastMatchPosition = i;
ControlPoint match = null;
if (newlyCreatedCache.containsKey(controlPointDTO)) {
match = newlyCreatedCache.get(controlPointDTO);
} else {
for (Waypoint oldWP : waypoints) {
ControlPoint oldControlPoint = oldWP.getControlPoint();
if (oldControlPoint.getId().toString().equals(controlPointDTO.getIdAsString())
&& markIDsMatch(oldControlPoint.getMarks(), controlPointDTO.getMarks())) {
match = oldControlPoint;
break;
}
}
}
if (matchFromOldCourse == null) {
if (match != null) {
newControlPoints.add(new Pair<ControlPoint, PassingInstruction>(match, controlPointAndPassingInstruction.getB()));
} else {
// no match found; create new control point:
ControlPoint newControlPoint;
if (controlPointDTO instanceof GateDTO) {
@@ -1727,6 +1737,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
PassingInstruction passingInstructions = controlPointAndPassingInstruction.getB();
newControlPoints.add(new Pair<ControlPoint, PassingInstruction>(newControlPoint, passingInstructions));
}
newlyCreatedCache.put(controlPointDTO, newControlPoint);
}
}
return newControlPoints;
@@ -4170,8 +4181,12 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
raceLog.add(event);
}
private WaypointDTO convertToWaypointDTO(Waypoint waypoint) {
ControlPointDTO cp = convertToControlPointDTO(waypoint.getControlPoint());
private WaypointDTO convertToWaypointDTO(Waypoint waypoint, Map<Serializable, ControlPointDTO> controlPointCache) {
ControlPointDTO cp = controlPointCache.get(waypoint.getControlPoint().getId());
if (cp == null) {
cp = convertToControlPointDTO(waypoint.getControlPoint());
controlPointCache.put(waypoint.getControlPoint().getId(), cp);
}
List<MarkDTO> marks = new ArrayList<MarkDTO>();
Util.addAll(cp.getMarks(), marks);
return new WaypointDTO(waypoint.getName(), cp, marks, waypoint.getPassingInstructions());
@@ -4179,9 +4194,10 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
private RaceCourseDTO convertToRaceCourseDTO(CourseBase course) {
List<WaypointDTO> waypointDTOs = new ArrayList<WaypointDTO>();
Map<Serializable, ControlPointDTO> controlPointCache = new HashMap<>();
RaceCourseDTO result = new RaceCourseDTO(waypointDTOs);
for (Waypoint waypoint : course.getWaypoints()) {
waypointDTOs.add(convertToWaypointDTO(waypoint));
waypointDTOs.add(convertToWaypointDTO(waypoint, controlPointCache));
}
return result;
}
@@ -28,4 +28,18 @@ public class MarkDTO extends ControlPointDTO {
public Iterable<MarkDTO> getMarks() {
return Collections.singleton(this);
}
@Override
public boolean equals(Object o) {
if (o instanceof MarkDTO) {
MarkDTO other = (MarkDTO) o;
return getIdAsString() != null && getIdAsString().equals(other.getIdAsString());
}
return false;
}
@Override
public int hashCode() {
return getIdAsString().hashCode();
}
}
@@ -10,11 +10,17 @@ import com.google.gwt.user.client.rpc.IsSerializable;
public class RaceCourseDTO implements IsSerializable {
public List<WaypointDTO> waypoints;
public List<MarkDTO> marks;
RaceCourseDTO() {}
public RaceCourseDTO(List<WaypointDTO> waypoints) {
this(waypoints, null);
}
public RaceCourseDTO(List<WaypointDTO> waypoints, List<MarkDTO> marks) {
this.waypoints = waypoints;
this.marks = marks;
}
public List<ControlPointDTO> getControlPoints() {
@@ -26,6 +32,10 @@ public class RaceCourseDTO implements IsSerializable {
}
public Collection<MarkDTO> getMarks() {
if (marks != null) {
return marks;
}
Map<String, MarkDTO> marks = new HashMap<String, MarkDTO>();
for(WaypointDTO waypoint: waypoints) {
for(MarkDTO mark: waypoint.marks) {
@@ -5,6 +5,10 @@ import java.util.List;
import com.sap.sailing.domain.common.PassingInstruction;
import com.sap.sailing.domain.common.dto.NamedDTO;
/**
* Equality and hashcode based on object identity
*
*/
public class WaypointDTO extends NamedDTO {
private static final long serialVersionUID = 7439553659782967746L;
@@ -23,4 +27,14 @@ public class WaypointDTO extends NamedDTO {
this.controlPoint = controlPoint;
this.passingInstructions = passingInstructions;
}
@Override
public boolean equals(Object obj) {
return this == obj;
}
@Override
public int hashCode() {
return System.identityHashCode(this);
}
}