mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-04 11:23:50 +00:00
Merge branch 'gwt' into mak-raceboard
Conflicts: java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardPanel.java
This commit is contained in:
commit
8e3656b369
34 files changed
+1353
-340
No files matched your search
+2
-2
@@ -73,12 +73,12 @@ public class PlacemarkImpl implements Placemark {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder b = new StringBuilder();
|
||||
StringBuilder b = new StringBuilder("[");
|
||||
|
||||
b.append(name + ", ");
|
||||
b.append(countryCode + ", ");
|
||||
b.append(position.toString() + ", ");
|
||||
b.append(population);
|
||||
b.append(population + "]");
|
||||
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
+14
-14
@@ -23,20 +23,20 @@ public class RacePlaceOrderImpl implements RacePlaceOrder, Serializable {
|
||||
return Collections.unmodifiableCollection(places);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public String toString() {
|
||||
// StringBuilder b = new StringBuilder();
|
||||
// boolean first = true;
|
||||
// for (Placemark place : places) {
|
||||
// if (first) {
|
||||
// b.append(place.getCountryCode() + ", " + place.getName());
|
||||
// first = false;
|
||||
// } else {
|
||||
// b.append(" -> " + place.getCountryCode() + ", " + place.getName());
|
||||
// }
|
||||
// }
|
||||
// return b.toString();
|
||||
// }
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder b = new StringBuilder();
|
||||
boolean first = true;
|
||||
for (Placemark place : places) {
|
||||
if (place != null && first) {
|
||||
b.append(place.getCountryCode() + ", " + place.getName());
|
||||
first = false;
|
||||
} else if (place != null) {
|
||||
b.append(" -> " + place.getCountryCode() + ", " + place.getName());
|
||||
}
|
||||
}
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package com.sap.sailing.domain.test;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.base.Buoy;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.RacePlaceOrder;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.impl.GPSFixImpl;
|
||||
import com.sap.sailing.domain.tractracadapter.ReceiverType;
|
||||
|
||||
public class LongRangeRegattaGeocoderTest extends AbstractManeuverDetectionTestCase {
|
||||
|
||||
public LongRangeRegattaGeocoderTest() throws MalformedURLException, URISyntaxException {
|
||||
super();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws URISyntaxException, IOException, InterruptedException {
|
||||
super.setUp();
|
||||
super.setUp("event_20110609_KielerWoch",
|
||||
/* raceId */"357c700a-9d9a-11e0-85be-406186cbf87c", new ReceiverType[] { ReceiverType.MARKPASSINGS,
|
||||
ReceiverType.RACESTARTFINISH, ReceiverType.RACECOURSE });
|
||||
fixApproximateMarkPositionsForGeocoder(getTrackedRace());
|
||||
dateFormat = new SimpleDateFormat("MM/dd/yyyy-HH:mm:ss");
|
||||
}
|
||||
|
||||
private void fixApproximateMarkPositionsForGeocoder(DynamicTrackedRace race) {
|
||||
TimePoint epoch = new MillisecondsTimePoint(0l);
|
||||
TimePoint now = MillisecondsTimePoint.now();
|
||||
Map<String, Position> buoyPositions = new HashMap<String, Position>();
|
||||
buoyPositions.put("K Start (left)", new DegreePosition(5.90906782829855, -55.16166687011719));
|
||||
buoyPositions.put("K Start (right)", new DegreePosition(5.939801840526332, -55.17402648925781));
|
||||
buoyPositions.put("K Mark1", new DegreePosition(8.233237111274565, -31.640625));
|
||||
buoyPositions.put("K Mark4 (right)", new DegreePosition(13.63083009512624, -21.8243408203125));
|
||||
buoyPositions.put("K Mark4 (left)", new DegreePosition(13.870080100685891, -21.9122314453125));
|
||||
buoyPositions.put("K Finish (left)", new DegreePosition(14.694198629294522, -17.39307403564453));
|
||||
buoyPositions.put("K Finish (right)", new DegreePosition(14.693866535193942, -17.371788024902344));
|
||||
for (Waypoint w : race.getRace().getCourse().getWaypoints()) {
|
||||
for (Buoy buoy : w.getBuoys()) {
|
||||
race.getOrCreateTrack(buoy).addGPSFix(new GPSFixImpl(buoyPositions.get(buoy.getName()), epoch));
|
||||
race.getOrCreateTrack(buoy).addGPSFix(new GPSFixImpl(buoyPositions.get(buoy.getName()), now));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetupOK() throws ParseException, NoWindException {
|
||||
assertNotNull(getTrackedRace());
|
||||
RacePlaceOrder order = getTrackedRace().getPlaceOrder();
|
||||
assertNotNull(order);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -69,7 +69,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
|
||||
* Used in {@link #getPlaceOrder()} to calculate the radius for the
|
||||
* {@link ReverseGeocoder#getPlacemarksNear(Position, double) GetPlacemarksNear-Service}.
|
||||
*/
|
||||
private static final double GEONAMES_RADIUS_CACLCULATION_FACTOR = 2.5;
|
||||
private static final double GEONAMES_RADIUS_CACLCULATION_FACTOR = 10.0;
|
||||
|
||||
// TODO observe the race course; if it changes, update leg structures; consider fine-grained update events that tell what changed
|
||||
private final RaceDefinition race;
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ public class ExpeditionWindTrackerFactory implements WindTrackerFactory, BundleA
|
||||
logger.info("Created "+getClass().getName()+" with default UDP port "+defaultPort);
|
||||
}
|
||||
|
||||
public static WindTrackerFactory getInstance() {
|
||||
public synchronized static WindTrackerFactory getInstance() {
|
||||
if (defaultInstance == null) {
|
||||
defaultInstance = new ExpeditionWindTrackerFactory();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#Mon Jan 16 18:21:00 CET 2012
|
||||
#Wed Jan 18 15:31:10 CET 2012
|
||||
eclipse.preferences.version=1
|
||||
entryPointModules=
|
||||
filesCopiedToWebInfLib=gwt-servlet.jar
|
||||
|
||||
+2
-2
@@ -129,8 +129,8 @@ public class RaceMapResources {
|
||||
Icon unknownManeuverIcon = Icon
|
||||
.newInstance("http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=?|FFFFFF|000000");
|
||||
unknownManeuverIcon.setIconAnchor(Point.newInstance(10, 33));
|
||||
maneuverIconsForTypeAndTargetTack.put(new Pair<ManeuverType, Tack>(ManeuverType.UNKNOWN, Tack.STARBOARD), tackToStarboardIcon);
|
||||
maneuverIconsForTypeAndTargetTack.put(new Pair<ManeuverType, Tack>(ManeuverType.UNKNOWN, Tack.PORT), tackToStarboardIcon);
|
||||
maneuverIconsForTypeAndTargetTack.put(new Pair<ManeuverType, Tack>(ManeuverType.UNKNOWN, Tack.STARBOARD), unknownManeuverIcon);
|
||||
maneuverIconsForTypeAndTargetTack.put(new Pair<ManeuverType, Tack>(ManeuverType.UNKNOWN, Tack.PORT), unknownManeuverIcon);
|
||||
Icon penaltyCircleToStarboardIcon = Icon
|
||||
.newInstance("http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=P|00FF00|000000");
|
||||
penaltyCircleToStarboardIcon.setIconAnchor(Point.newInstance(10, 33));
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ public class RacesListBoxPanel extends FormPanel implements RaceSelectionProvide
|
||||
Triple<EventDAO, RegattaDAO, RaceDAO> selectedRace = getSelectedRace();
|
||||
List<Triple<EventDAO, RegattaDAO, RaceDAO>> selectedRacesCollection = Collections.emptyList();
|
||||
if (selectedRace != null) {
|
||||
Collections.singletonList(selectedRace);
|
||||
selectedRacesCollection = Collections.singletonList(selectedRace);
|
||||
}
|
||||
fireRaceSelectionChanged(selectedRacesCollection);
|
||||
}
|
||||
|
||||
Executable
+240
@@ -0,0 +1,240 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import ca.nanometrics.gflot.client.Axis;
|
||||
import ca.nanometrics.gflot.client.DataPoint;
|
||||
import ca.nanometrics.gflot.client.PlotItem;
|
||||
import ca.nanometrics.gflot.client.PlotModelStrategy;
|
||||
import ca.nanometrics.gflot.client.PlotPosition;
|
||||
import ca.nanometrics.gflot.client.PlotWithOverview;
|
||||
import ca.nanometrics.gflot.client.PlotWithOverviewModel;
|
||||
import ca.nanometrics.gflot.client.SeriesHandler;
|
||||
import ca.nanometrics.gflot.client.SeriesType;
|
||||
import ca.nanometrics.gflot.client.event.PlotHoverListener;
|
||||
import ca.nanometrics.gflot.client.event.SelectionListener;
|
||||
import ca.nanometrics.gflot.client.jsni.Plot;
|
||||
import ca.nanometrics.gflot.client.options.AxisOptions;
|
||||
import ca.nanometrics.gflot.client.options.GridOptions;
|
||||
import ca.nanometrics.gflot.client.options.LegendOptions;
|
||||
import ca.nanometrics.gflot.client.options.LineSeriesOptions;
|
||||
import ca.nanometrics.gflot.client.options.PlotOptions;
|
||||
import ca.nanometrics.gflot.client.options.PointsSeriesOptions;
|
||||
import ca.nanometrics.gflot.client.options.SelectionOptions;
|
||||
import ca.nanometrics.gflot.client.options.SeriesOptions;
|
||||
import ca.nanometrics.gflot.client.options.TickFormatter;
|
||||
|
||||
import com.google.gwt.i18n.client.DateTimeFormat;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.gwt.ui.client.ColorMap;
|
||||
import com.sap.sailing.gwt.ui.client.ErrorReporter;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.shared.WindDAO;
|
||||
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDAO;
|
||||
import com.sap.sailing.gwt.ui.shared.WindTrackInfoDAO;
|
||||
import com.sap.sailing.gwt.ui.shared.components.Component;
|
||||
import com.sap.sailing.gwt.ui.shared.components.SettingsDialogComponent;
|
||||
|
||||
public class WindChart implements Component<WindChartSettings> {
|
||||
private final StringMessages stringMessages;
|
||||
private final DateTimeFormat dateFormat;
|
||||
private PlotWithOverviewModel model;
|
||||
private final Set<WindSource> windSourcesToDisplay;
|
||||
private final ColorMap<WindSource> colorMap;
|
||||
private final Map<WindSource, SeriesHandler> stripChartSeries;
|
||||
private final List<SeriesHandler> seriesHandlersInOrder;
|
||||
private final Label selectedPointLabel;
|
||||
private final ErrorReporter errorReporter;
|
||||
private PlotWithOverview plot;
|
||||
|
||||
public WindChart(WindChartSettings settings, StringMessages stringMessages, ErrorReporter errorReporter) {
|
||||
super();
|
||||
this.stringMessages = stringMessages;
|
||||
this.errorReporter = errorReporter;
|
||||
this.windSourcesToDisplay = new HashSet<WindSource>(settings.getWindSourcesToDisplay());
|
||||
dateFormat = DateTimeFormat.getFormat("HH:mm:ss");
|
||||
this.colorMap = new ColorMap<WindSource>();
|
||||
this.stripChartSeries = new HashMap<WindSource, SeriesHandler>();
|
||||
this.seriesHandlersInOrder = new ArrayList<SeriesHandler>();
|
||||
this.selectedPointLabel = new Label();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocalizedShortName() {
|
||||
return stringMessages.wind();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Widget getEntryWidget() {
|
||||
VerticalPanel vp = new VerticalPanel();
|
||||
HorizontalPanel hp = new HorizontalPanel();
|
||||
hp.add(selectedPointLabel);
|
||||
hp.setHeight("2em");
|
||||
vp.add(hp);
|
||||
model = new PlotWithOverviewModel(PlotModelStrategy.defaultStrategy());
|
||||
PlotOptions plotOptions = new PlotOptions();
|
||||
plotOptions.setDefaultLineSeriesOptions(new LineSeriesOptions().setLineWidth(1).setShow(true));
|
||||
plotOptions.setDefaultPointsOptions(new PointsSeriesOptions().setShow(false));
|
||||
plotOptions.setDefaultShadowSize(2);
|
||||
AxisOptions hAxisOptions = new AxisOptions();
|
||||
hAxisOptions.setTickFormatter(new TickFormatter() {
|
||||
@Override
|
||||
public String formatTickValue(double tickValue, Axis axis) {
|
||||
return dateFormat.format(new Date((long) tickValue));
|
||||
}
|
||||
});
|
||||
plotOptions.setXAxisOptions(hAxisOptions);
|
||||
plotOptions.setLegendOptions(new LegendOptions().setShow(false));
|
||||
plotOptions.setGridOptions(new GridOptions().setHoverable(true).setMouseActiveRadius(5).setAutoHighlight(true));
|
||||
plotOptions.setSelectionOptions(new SelectionOptions().setDragging(true).setMode("x")); // select along x-axis only
|
||||
for (WindSource windSource : windSourcesToDisplay) {
|
||||
SeriesHandler series = addSeries(windSource);
|
||||
series.setOptions(SeriesType.LINES, getLinesOptions(/* visible */ windSourcesToDisplay.contains(windSource)));
|
||||
series.setOptions(SeriesType.POINTS, getPointsOptions(/* visible */ false));
|
||||
series.setVisible(false);
|
||||
}
|
||||
this.plot = new PlotWithOverview(model, plotOptions) {
|
||||
@Override
|
||||
protected void onLoad() {
|
||||
super.onLoad();
|
||||
// onLoad is called immediately after a widget becomes attached to the browser's document.
|
||||
// Use this time point to ask the chart to redraw
|
||||
redraw();
|
||||
}
|
||||
};
|
||||
// add hover listener
|
||||
plot.addHoverListener(new PlotHoverListener() {
|
||||
public void onPlotHover(Plot plot, PlotPosition position, PlotItem item) {
|
||||
if (item != null) {
|
||||
SeriesHandler seriesHandler = seriesHandlersInOrder.get(item.getSeriesIndex());
|
||||
WindSource windSource = getWindSource(seriesHandler);
|
||||
selectedPointLabel.setText(windSource.name()+": "+position.getY().intValue());
|
||||
selectedPointLabel.setVisible(true);
|
||||
} else {
|
||||
selectedPointLabel.setVisible(false);
|
||||
}
|
||||
}
|
||||
}, /* only on data point */ false);
|
||||
plot.addSelectionListener(new SelectionListener() {
|
||||
public void selected(double x1, double y1, double x2, double y2) {
|
||||
/* TODO Remove not visible buoys from the series when user is zooming in or add them if he is zooming out.
|
||||
for (CompetitorDAO competitor : competitorsAndTimePointsDAO.getCompetitor()){
|
||||
long[] markPassingTimes = competitorsAndTimePointsDAO.getMarkPassings(competitor);
|
||||
Double[] markPassingValues = chartData.getMarkPassings(competitor);
|
||||
SeriesHandler markSeries = getCompetitorMarkPassingSeries(competitor);
|
||||
markSeries.clear();
|
||||
int visibleMarkPassings = 0;
|
||||
for (int j = 0; j < markPassingTimes.length; j++){
|
||||
if (markPassingValues[j] != null && markPassingTimes[j] > x1 && markPassingTimes[j] < x2) {
|
||||
markSeries.add(new DataPoint(markPassingTimes[j],markPassingValues[j]));
|
||||
visibleMarkPassings++;
|
||||
}
|
||||
}
|
||||
if (visibleMarkPassings == 0){
|
||||
markSeries.setVisible(false);
|
||||
}
|
||||
}*/
|
||||
plot.setLinearSelection(x1, x2);
|
||||
}
|
||||
});
|
||||
plot.setOverviewHeight(60);
|
||||
vp.add(plot);
|
||||
return vp;
|
||||
}
|
||||
|
||||
private WindSource getWindSource(SeriesHandler seriesHandler) {
|
||||
for (Map.Entry<WindSource, SeriesHandler> e : stripChartSeries.entrySet()) {
|
||||
if (e.getValue() == seriesHandler) {
|
||||
return e.getKey();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private SeriesHandler addSeries(WindSource windSource) {
|
||||
SeriesHandler series = model.addSeries(windSource.name(), colorMap.getColorByID(windSource));
|
||||
seriesHandlersInOrder.add(series);
|
||||
stripChartSeries.put(windSource, series);
|
||||
return series;
|
||||
}
|
||||
|
||||
public void updateStripChartSeries(WindInfoForRaceDAO result) {
|
||||
long min = Long.MAX_VALUE;
|
||||
long max = Long.MIN_VALUE;
|
||||
for (Map.Entry<WindSource, WindTrackInfoDAO> e : result.windTrackInfoByWindSource.entrySet()) {
|
||||
WindSource windSource = e.getKey();
|
||||
SeriesHandler seriesHandler = stripChartSeries.get(windSource);
|
||||
if (e.getValue().windFixes.isEmpty()) {
|
||||
if (seriesHandler != null) {
|
||||
model.removeSeries(seriesHandler);
|
||||
stripChartSeries.remove(windSource);
|
||||
}
|
||||
} else {
|
||||
if (seriesHandler == null) {
|
||||
seriesHandler = addSeries(windSource);
|
||||
seriesHandler.setOptions(SeriesType.LINES, getLinesOptions(/* visible */ windSourcesToDisplay.contains(windSource)));
|
||||
seriesHandler.setOptions(SeriesType.POINTS, getPointsOptions(/* visible */ false));
|
||||
} else {
|
||||
seriesHandler.clear();
|
||||
}
|
||||
for (WindDAO windFix : e.getValue().windFixes) {
|
||||
seriesHandler.add(new DataPoint(windFix.timepoint, windFix.dampenedTrueWindFromDeg));
|
||||
min = Math.min(min, windFix.timepoint);
|
||||
max = Math.max(max, windFix.timepoint);
|
||||
}
|
||||
seriesHandler.setVisible(true);
|
||||
}
|
||||
}
|
||||
if (plot != null && plot.isAttached()) {
|
||||
try {
|
||||
plot.setLinearSelection(min, max); // TODO maintain previous selection
|
||||
plot.redraw();
|
||||
} catch (Exception ex) {
|
||||
errorReporter.reportError("Error trying to update strip chart: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private SeriesOptions getPointsOptions(boolean visible) {
|
||||
return new PointsSeriesOptions().setLineWidth(0).setShow(visible);
|
||||
}
|
||||
|
||||
private SeriesOptions getLinesOptions(boolean visible) {
|
||||
return new LineSeriesOptions().setLineWidth(2.5).setShow(visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSettings() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SettingsDialogComponent<WindChartSettings> getSettingsDialogComponent() {
|
||||
return new WindChartSettingsDialogComponent(new WindChartSettings(windSourcesToDisplay));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the visibilities of the wind source series based on the new settings. Note that this does not
|
||||
* re-load any wind data. This has to happen by calling {@link #updateStripChartSeries(WindInfoForRaceDAO)}.
|
||||
*/
|
||||
@Override
|
||||
public void updateSettings(WindChartSettings newSettings) {
|
||||
windSourcesToDisplay.clear();
|
||||
windSourcesToDisplay.addAll(newSettings.getWindSourcesToDisplay());
|
||||
for (Map.Entry<WindSource, SeriesHandler> e : stripChartSeries.entrySet()) {
|
||||
e.getValue().setVisible(windSourcesToDisplay.contains(e.getKey()));
|
||||
}
|
||||
plot.redraw();
|
||||
}
|
||||
|
||||
}
|
||||
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/WindChartSettings.java
Executable
+24
@@ -0,0 +1,24 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
|
||||
public class WindChartSettings {
|
||||
private final Set<WindSource> windSourcesToDisplay;
|
||||
|
||||
public WindChartSettings(Set<WindSource> windSourcesToDisplay) {
|
||||
this.windSourcesToDisplay = windSourcesToDisplay;
|
||||
}
|
||||
|
||||
public WindChartSettings(WindSource... windSourcesToDisplay) {
|
||||
this(new HashSet<WindSource>(windSourcesToDisplay==null?new ArrayList<WindSource>():Arrays.asList(windSourcesToDisplay)));
|
||||
}
|
||||
|
||||
public Set<WindSource> getWindSourcesToDisplay() {
|
||||
return windSourcesToDisplay;
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.gwt.user.client.ui.CheckBox;
|
||||
import com.google.gwt.user.client.ui.FocusWidget;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.gwt.ui.client.DataEntryDialog;
|
||||
import com.sap.sailing.gwt.ui.client.DataEntryDialog.Validator;
|
||||
import com.sap.sailing.gwt.ui.shared.components.SettingsDialogComponent;
|
||||
|
||||
public class WindChartSettingsDialogComponent implements SettingsDialogComponent<WindChartSettings> {
|
||||
private final WindChartSettings initialSettings;
|
||||
private final Map<WindSource, CheckBox> checkboxes;
|
||||
|
||||
public WindChartSettingsDialogComponent(WindChartSettings initialSettings) {
|
||||
super();
|
||||
this.initialSettings = initialSettings;
|
||||
checkboxes = new LinkedHashMap<WindSource, CheckBox>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Widget getAdditionalWidget(DataEntryDialog<WindChartSettings> dialog) {
|
||||
VerticalPanel vp = new VerticalPanel();
|
||||
for (WindSource windSource : WindSource.values()) {
|
||||
CheckBox checkbox = dialog.createCheckbox(windSource.name());
|
||||
checkboxes.put(windSource, checkbox);
|
||||
checkbox.setValue(initialSettings.getWindSourcesToDisplay().contains(windSource));
|
||||
vp.add(checkbox);
|
||||
}
|
||||
return vp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindChartSettings getResult() {
|
||||
Set<WindSource> windSourcesToDisplay = new HashSet<WindSource>();
|
||||
for (Map.Entry<WindSource, CheckBox> e : checkboxes.entrySet()) {
|
||||
if (e.getValue().getValue()) {
|
||||
windSourcesToDisplay.add(e.getKey());
|
||||
}
|
||||
}
|
||||
return new WindChartSettings(windSourcesToDisplay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Validator<WindChartSettings> getValidator() {
|
||||
// with checkboxes only, nothing can go wrong :-)
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FocusWidget getFocusWidget() {
|
||||
return checkboxes.values().iterator().next();
|
||||
}
|
||||
|
||||
}
|
||||
+37
-192
@@ -7,34 +7,16 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import ca.nanometrics.gflot.client.Axis;
|
||||
import ca.nanometrics.gflot.client.DataPoint;
|
||||
import ca.nanometrics.gflot.client.PlotItem;
|
||||
import ca.nanometrics.gflot.client.PlotModelStrategy;
|
||||
import ca.nanometrics.gflot.client.PlotPosition;
|
||||
import ca.nanometrics.gflot.client.PlotWithOverview;
|
||||
import ca.nanometrics.gflot.client.PlotWithOverviewModel;
|
||||
import ca.nanometrics.gflot.client.SeriesHandler;
|
||||
import ca.nanometrics.gflot.client.SeriesType;
|
||||
import ca.nanometrics.gflot.client.event.PlotHoverListener;
|
||||
import ca.nanometrics.gflot.client.event.SelectionListener;
|
||||
import ca.nanometrics.gflot.client.jsni.Plot;
|
||||
import ca.nanometrics.gflot.client.options.AxisOptions;
|
||||
import ca.nanometrics.gflot.client.options.GridOptions;
|
||||
import ca.nanometrics.gflot.client.options.LegendOptions;
|
||||
import ca.nanometrics.gflot.client.options.LineSeriesOptions;
|
||||
import ca.nanometrics.gflot.client.options.PlotOptions;
|
||||
import ca.nanometrics.gflot.client.options.PointsSeriesOptions;
|
||||
import ca.nanometrics.gflot.client.options.SelectionOptions;
|
||||
import ca.nanometrics.gflot.client.options.TickFormatter;
|
||||
|
||||
import com.google.gwt.cell.client.ActionCell;
|
||||
import com.google.gwt.cell.client.ActionCell.Delegate;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.event.dom.client.ChangeEvent;
|
||||
import com.google.gwt.event.dom.client.ChangeHandler;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.event.logical.shared.ValueChangeEvent;
|
||||
import com.google.gwt.event.logical.shared.ValueChangeHandler;
|
||||
import com.google.gwt.i18n.client.DateTimeFormat;
|
||||
import com.google.gwt.resources.client.ImageResource;
|
||||
import com.google.gwt.user.cellview.client.CellTable;
|
||||
import com.google.gwt.user.cellview.client.ColumnSortEvent;
|
||||
import com.google.gwt.user.cellview.client.ColumnSortEvent.Handler;
|
||||
@@ -44,6 +26,8 @@ import com.google.gwt.user.cellview.client.ColumnSortList.ColumnSortInfo;
|
||||
import com.google.gwt.user.cellview.client.IdentityColumn;
|
||||
import com.google.gwt.user.cellview.client.TextColumn;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.AbstractImagePrototype;
|
||||
import com.google.gwt.user.client.ui.Anchor;
|
||||
import com.google.gwt.user.client.ui.CheckBox;
|
||||
import com.google.gwt.user.client.ui.FormPanel;
|
||||
import com.google.gwt.user.client.ui.Grid;
|
||||
@@ -53,9 +37,8 @@ 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.view.client.ListDataProvider;
|
||||
import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.gwt.ui.client.ColorMap;
|
||||
import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||
import com.sap.sailing.gwt.ui.client.ErrorReporter;
|
||||
import com.sap.sailing.gwt.ui.client.EventDisplayer;
|
||||
import com.sap.sailing.gwt.ui.client.EventRefresher;
|
||||
@@ -68,13 +51,14 @@ import com.sap.sailing.gwt.ui.shared.RegattaDAO;
|
||||
import com.sap.sailing.gwt.ui.shared.WindDAO;
|
||||
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDAO;
|
||||
import com.sap.sailing.gwt.ui.shared.WindTrackInfoDAO;
|
||||
import com.sap.sailing.gwt.ui.shared.components.SettingsDialog;
|
||||
import com.sap.sailing.server.api.EventNameAndRaceName;
|
||||
|
||||
public class WindPanel extends FormPanel implements EventDisplayer, WindShower, RaceSelectionChangeListener {
|
||||
private final SailingServiceAsync sailingService;
|
||||
private final ErrorReporter errorReporter;
|
||||
private final Grid grid;
|
||||
private final StringMessages stringConstants;
|
||||
private final StringMessages stringMessages;
|
||||
private final WindSettingPanel windSettingPanel;
|
||||
private ColumnSortList columnSortList;
|
||||
private final IdentityColumn<WindDAO> removeColumn;
|
||||
@@ -87,19 +71,14 @@ public class WindPanel extends FormPanel implements EventDisplayer, WindShower,
|
||||
private final ListBox windSourceSelection;
|
||||
private final Map<WindSource, ListDataProvider<WindDAO>> windLists;
|
||||
private final CheckBox raceIsKnownToStartUpwindBox;
|
||||
private final PlotWithOverview stripChart;
|
||||
private final DateTimeFormat dateFormat;
|
||||
private final ColorMap<WindSource> colorMap;
|
||||
private final Map<WindSource, SeriesHandler> stripChartSeries;
|
||||
private final WindChart windChart;
|
||||
private static AdminConsoleResources resources = GWT.create(AdminConsoleResources.class);
|
||||
|
||||
public WindPanel(final SailingServiceAsync sailingService, ErrorReporter errorReporter,
|
||||
EventRefresher eventRefresher, StringMessages stringConstants) {
|
||||
EventRefresher eventRefresher, final StringMessages stringMessages) {
|
||||
this.sailingService = sailingService;
|
||||
this.errorReporter = errorReporter;
|
||||
this.stringConstants = stringConstants;
|
||||
this.colorMap = new ColorMap<WindSource>();
|
||||
this.stripChartSeries = new HashMap<WindSource, SeriesHandler>();
|
||||
dateFormat = DateTimeFormat.getFormat("HH:mm:ss");
|
||||
this.stringMessages = stringMessages;
|
||||
windLists = new HashMap<WindSource, ListDataProvider<WindDAO>>();
|
||||
windSourceSelection = new ListBox();
|
||||
windSourceSelection.addChangeHandler(new ChangeHandler() {
|
||||
@@ -108,7 +87,7 @@ public class WindPanel extends FormPanel implements EventDisplayer, WindShower,
|
||||
setWindSource(/* runOnSuccess */ null);
|
||||
}
|
||||
});
|
||||
removeColumn = new IdentityColumn<WindDAO>(new ActionCell<WindDAO>(stringConstants.remove(), new Delegate<WindDAO>() {
|
||||
removeColumn = new IdentityColumn<WindDAO>(new ActionCell<WindDAO>(stringMessages.remove(), new Delegate<WindDAO>() {
|
||||
@Override
|
||||
public void execute(final WindDAO wind) {
|
||||
List<Triple<EventDAO, RegattaDAO, RaceDAO>> eventAndRaces = trackedEventsComposite.getSelectedEventAndRace();
|
||||
@@ -122,7 +101,7 @@ public class WindPanel extends FormPanel implements EventDisplayer, WindShower,
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
WindPanel.this.errorReporter.reportError(
|
||||
WindPanel.this.stringConstants.errorSettingWindForRace()+ " "+eventAndRace.getC().name
|
||||
WindPanel.this.stringMessages.errorSettingWindForRace()+ " "+eventAndRace.getC().name
|
||||
+ ": "+ caught.getMessage());
|
||||
}
|
||||
});
|
||||
@@ -159,16 +138,16 @@ public class WindPanel extends FormPanel implements EventDisplayer, WindShower,
|
||||
}
|
||||
};
|
||||
grid = new Grid(4, 2); // first row: event/race selection; second row: wind source selection; third row: wind display
|
||||
trackedEventsComposite = new TrackedEventsComposite(sailingService, errorReporter, eventRefresher, stringConstants, false);
|
||||
trackedEventsComposite = new TrackedEventsComposite(sailingService, errorReporter, eventRefresher, stringMessages, false);
|
||||
trackedEventsComposite.addRaceSelectionChangeListener(this);
|
||||
grid.setWidget(0, 0, trackedEventsComposite);
|
||||
windSettingPanel = new WindSettingPanel(sailingService, errorReporter, trackedEventsComposite, this);
|
||||
grid.setWidget(0, 1, windSettingPanel);
|
||||
HorizontalPanel windSourceSelectionPanel = new HorizontalPanel();
|
||||
windSourceSelectionPanel.setSpacing(10);
|
||||
windSourceSelectionPanel.add(new Label(stringConstants.windSource()));
|
||||
windSourceSelectionPanel.add(new Label(stringMessages.windSource()));
|
||||
windSourceSelectionPanel.add(windSourceSelection);
|
||||
raceIsKnownToStartUpwindBox = new CheckBox(stringConstants.raceIsKnownToStartUpwind());
|
||||
raceIsKnownToStartUpwindBox = new CheckBox(stringMessages.raceIsKnownToStartUpwind());
|
||||
windSourceSelectionPanel.add(raceIsKnownToStartUpwindBox);
|
||||
raceIsKnownToStartUpwindBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
|
||||
@Override
|
||||
@@ -180,118 +159,23 @@ public class WindPanel extends FormPanel implements EventDisplayer, WindShower,
|
||||
});
|
||||
}
|
||||
});
|
||||
ImageResource settingsImage = resources.settingsIcon();
|
||||
Anchor showConfigAnchor = new Anchor(AbstractImagePrototype.create(settingsImage).getSafeHtml());
|
||||
showConfigAnchor.setTitle(stringMessages.configuration());
|
||||
showConfigAnchor.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
new SettingsDialog<WindChartSettings>(windChart, stringMessages).show();
|
||||
}
|
||||
});
|
||||
windSourceSelectionPanel.add(showConfigAnchor);
|
||||
grid.setWidget(1, 0, windSourceSelectionPanel);
|
||||
stripChart = createStripChart();
|
||||
grid.setWidget(2, 0, stripChart);
|
||||
windChart = new WindChart(new WindChartSettings(WindSource.values()), stringMessages, errorReporter);
|
||||
grid.setWidget(2, 0, windChart.getEntryWidget());
|
||||
grid.getCellFormatter().setVerticalAlignment(1, 1, HasVerticalAlignment.ALIGN_TOP);
|
||||
this.setWidget(grid);
|
||||
}
|
||||
|
||||
private PlotWithOverview createStripChart() {
|
||||
PlotWithOverviewModel model = new PlotWithOverviewModel(PlotModelStrategy.defaultStrategy());
|
||||
PlotOptions plotOptions = new PlotOptions();
|
||||
plotOptions.setDefaultLineSeriesOptions(new LineSeriesOptions().setLineWidth(1).setShow(true));
|
||||
plotOptions.setDefaultPointsOptions(new PointsSeriesOptions().setShow(false));
|
||||
plotOptions.setDefaultShadowSize(2);
|
||||
AxisOptions hAxisOptions = new AxisOptions();
|
||||
hAxisOptions.setTickFormatter(new TickFormatter() {
|
||||
@Override
|
||||
public String formatTickValue(double tickValue, Axis axis) {
|
||||
return dateFormat.format(new Date((long) tickValue));
|
||||
}
|
||||
});
|
||||
plotOptions.setXAxisOptions(hAxisOptions);
|
||||
plotOptions.setLegendOptions(new LegendOptions().setShow(false));
|
||||
plotOptions.setGridOptions(new GridOptions().setHoverable(true).setMouseActiveRadius(5).setAutoHighlight(true));
|
||||
plotOptions.setSelectionOptions(new SelectionOptions().setDragging(true).setMode("x")); // select along x-axis only
|
||||
for (WindSource windSource : WindSource.values()) {
|
||||
SeriesHandler series = model.addSeries(""+windSource.name(), colorMap.getColorByID(windSource));
|
||||
series.setOptions(SeriesType.LINES, new LineSeriesOptions().setLineWidth(2.5).setShow(true));
|
||||
series.setOptions(SeriesType.POINTS, new PointsSeriesOptions().setLineWidth(0).setShow(false));
|
||||
series.setVisible(false);
|
||||
stripChartSeries.put(windSource, series);
|
||||
}
|
||||
final PlotWithOverview plot = new PlotWithOverview(model, plotOptions) {
|
||||
@Override
|
||||
protected void onLoad() {
|
||||
super.onLoad();
|
||||
// onLoad is called immediately after a widget becomes attached to the browser's document.
|
||||
// Use this time point to ask the chart to redraw
|
||||
redraw();
|
||||
}
|
||||
};
|
||||
// add hover listener
|
||||
plot.addHoverListener(new PlotHoverListener() {
|
||||
public void onPlotHover(Plot plot, PlotPosition position, PlotItem item) {
|
||||
/* TODO show some reasonable hover tooltip in wind strip chart
|
||||
CompetitorDAO competitor = competitorID.get(seriesID.indexOf(item.getSeries()));
|
||||
if (item != null && competitor != null) {
|
||||
if (item.getSeries().getLabel().toLowerCase().contains("mark")){
|
||||
selectedPointLabel.setText(competitor.name + " passed " + markPassingBuoyName.get(competitor.id + (long) item.getDataPoint().getX()) +" at " + dateFormat.format(new Date((long) item.getDataPoint().getX())));
|
||||
}
|
||||
else {
|
||||
String unit = "";
|
||||
switch (dataToShow){
|
||||
case CURRENT_SPEED_OVER_GROUND_IN_KNOTS:
|
||||
unit = stringConstants.currentSpeedOverGroundInKnotsUnit();
|
||||
break;
|
||||
case DISTANCE_TRAVELED:
|
||||
unit = stringConstants.distanceInMetersUnit();
|
||||
break;
|
||||
case GAP_TO_LEADER_IN_SECONDS:
|
||||
unit = stringConstants.gapToLeaderInSecondsUnit();
|
||||
break;
|
||||
case VELOCITY_MADE_GOOD_IN_KNOTS:
|
||||
unit = stringConstants.velocityMadeGoodInKnotsUnit();
|
||||
break;
|
||||
case WINDWARD_DISTANCE_TO_OVERALL_LEADER:
|
||||
unit = stringConstants.windwardDistanceToGoInMetersUnit();
|
||||
}
|
||||
String decimalPlaces = "";
|
||||
for (int i = 0; i < dataToShow.getPrecision(); i++){
|
||||
if (i == 0){
|
||||
decimalPlaces += ".";
|
||||
}
|
||||
decimalPlaces += "0";
|
||||
}
|
||||
NumberFormat numberFormat = NumberFormat.getFormat("0" +decimalPlaces);
|
||||
selectedPointLabel.setText(competitor.name + " at " + dateFormat.format(new Date((long) item.getDataPoint().getX()))
|
||||
+ ": " + numberFormat.format(item.getDataPoint().getY()) + unit);
|
||||
}
|
||||
} else {
|
||||
selectedPointLabel.setText(stringConstants.noSelection());
|
||||
}
|
||||
*/
|
||||
}
|
||||
}, true);
|
||||
plot.addSelectionListener(new SelectionListener() {
|
||||
public void selected(double x1, double y1, double x2, double y2) {
|
||||
/* TODO Remove not visible buoys from the series when user is zooming in or add them if he is zooming out.
|
||||
for (CompetitorDAO competitor : competitorsAndTimePointsDAO.getCompetitor()){
|
||||
long[] markPassingTimes = competitorsAndTimePointsDAO.getMarkPassings(competitor);
|
||||
Double[] markPassingValues = chartData.getMarkPassings(competitor);
|
||||
SeriesHandler markSeries = getCompetitorMarkPassingSeries(competitor);
|
||||
markSeries.clear();
|
||||
int visibleMarkPassings = 0;
|
||||
for (int j = 0; j < markPassingTimes.length; j++){
|
||||
if (markPassingValues[j] != null && markPassingTimes[j] > x1 && markPassingTimes[j] < x2) {
|
||||
markSeries.add(new DataPoint(markPassingTimes[j],markPassingValues[j]));
|
||||
visibleMarkPassings++;
|
||||
}
|
||||
}
|
||||
if (visibleMarkPassings == 0){
|
||||
markSeries.setVisible(false);
|
||||
}
|
||||
}*/
|
||||
plot.setLinearSelection(x1, x2);
|
||||
}
|
||||
});
|
||||
// plot.setHeight(height);
|
||||
// plot.setWidth(width);
|
||||
plot.setOverviewHeight(60);
|
||||
return plot;
|
||||
}
|
||||
|
||||
private void clearOrShowWindBasedOnRaceSelection(List<Triple<EventDAO, RegattaDAO, RaceDAO>> selectedRaces) {
|
||||
if (selectedRaces.isEmpty()) {
|
||||
clearWindDisplay(); // no wind known for untracked race
|
||||
@@ -325,7 +209,7 @@ public class WindPanel extends FormPanel implements EventDisplayer, WindShower,
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError(WindPanel.this.stringConstants.errorFetchingWindInformationForRace()+" " + race.name + ": "
|
||||
errorReporter.reportError(WindPanel.this.stringMessages.errorFetchingWindInformationForRace()+" " + race.name + ": "
|
||||
+ caught.getMessage());
|
||||
}
|
||||
});
|
||||
@@ -364,10 +248,10 @@ public class WindPanel extends FormPanel implements EventDisplayer, WindShower,
|
||||
grid.setWidget(3, 0, null);
|
||||
VerticalPanel windDisplay = new VerticalPanel();
|
||||
grid.setWidget(3, 0, windDisplay);
|
||||
updateStripChartSeries(result);
|
||||
windChart.updateStripChartSeries(result);
|
||||
for (Map.Entry<WindSource, WindTrackInfoDAO> e : result.windTrackInfoByWindSource.entrySet()) {
|
||||
Label windSourceLabel = new Label(stringConstants.windSource()+": "+e.getKey()+
|
||||
", "+stringConstants.dampeningInterval()+" "+e.getValue().dampeningIntervalInMilliseconds+"ms");
|
||||
Label windSourceLabel = new Label(stringMessages.windSource()+": "+e.getKey()+
|
||||
", "+stringMessages.dampeningInterval()+" "+e.getValue().dampeningIntervalInMilliseconds+"ms");
|
||||
windDisplay.add(windSourceLabel);
|
||||
timeColumn.setSortable(true);
|
||||
speedInKnotsColumn.setSortable(true);
|
||||
@@ -409,45 +293,6 @@ public class WindPanel extends FormPanel implements EventDisplayer, WindShower,
|
||||
}
|
||||
}
|
||||
|
||||
private void updateStripChartSeries(WindInfoForRaceDAO result) {
|
||||
long min = Long.MAX_VALUE;
|
||||
long max = Long.MIN_VALUE;
|
||||
for (Map.Entry<WindSource, WindTrackInfoDAO> e : result.windTrackInfoByWindSource.entrySet()) {
|
||||
WindSource windSource = e.getKey();
|
||||
SeriesHandler seriesHandler = stripChartSeries.get(windSource);
|
||||
if (e.getValue().windFixes.isEmpty()) {
|
||||
if (seriesHandler != null) {
|
||||
stripChart.getModel().removeSeries(seriesHandler);
|
||||
stripChartSeries.remove(windSource);
|
||||
}
|
||||
} else {
|
||||
if (seriesHandler == null) {
|
||||
seriesHandler = stripChart.getModel().addSeries("" + windSource.name(),
|
||||
colorMap.getColorByID(windSource));
|
||||
seriesHandler.setOptions(SeriesType.LINES, new LineSeriesOptions().setLineWidth(2.5).setShow(true));
|
||||
seriesHandler.setOptions(SeriesType.POINTS, new PointsSeriesOptions().setLineWidth(0).setShow(false));
|
||||
stripChartSeries.put(windSource, seriesHandler);
|
||||
} else {
|
||||
seriesHandler.clear();
|
||||
}
|
||||
for (WindDAO windFix : e.getValue().windFixes) {
|
||||
seriesHandler.add(new DataPoint(windFix.timepoint, windFix.dampenedTrueWindFromDeg));
|
||||
min = Math.min(min, windFix.timepoint);
|
||||
max = Math.max(max, windFix.timepoint);
|
||||
}
|
||||
seriesHandler.setVisible(true);
|
||||
}
|
||||
}
|
||||
if (stripChart != null && stripChart.isAttached()) {
|
||||
try {
|
||||
stripChart.setLinearSelection(min, max); // TODO maintain previous selection
|
||||
stripChart.redraw();
|
||||
} catch (Exception ex) {
|
||||
errorReporter.reportError("Error trying to update strip chart: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Handler getWindTableColumnSortHandler(List<WindDAO> list, TextColumn<WindDAO> timeColumn,
|
||||
TextColumn<WindDAO> speedInKnotsColumn, TextColumn<WindDAO> windDirectionInDegColumn,
|
||||
TextColumn<WindDAO> dampenedSpeedInKnotsColumn, TextColumn<WindDAO> dampenedWindDirectionInDegColumn) {
|
||||
@@ -498,9 +343,9 @@ public class WindPanel extends FormPanel implements EventDisplayer, WindShower,
|
||||
windSourceName, raceIsKnownToStartUpwindBox.getValue(), new AsyncCallback<Void>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError(WindPanel.this.stringConstants.errorWhileTryingToSetWindSourceForRace()+
|
||||
" "+selectedRace.getC().name+" "+WindPanel.this.stringConstants.inEvent()+" "+selectedRace.getA().name+
|
||||
" "+WindPanel.this.stringConstants.to()+" "+
|
||||
errorReporter.reportError(WindPanel.this.stringMessages.errorWhileTryingToSetWindSourceForRace()+
|
||||
" "+selectedRace.getC().name+" "+WindPanel.this.stringMessages.inEvent()+" "+selectedRace.getA().name+
|
||||
" "+WindPanel.this.stringMessages.to()+" "+
|
||||
windSourceName+": "+caught.getMessage());
|
||||
}
|
||||
@Override
|
||||
|
||||
-4
@@ -8,7 +8,6 @@ import java.util.Map;
|
||||
import com.google.gwt.user.client.rpc.RemoteService;
|
||||
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.Placemark;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.gwt.ui.shared.CompetitorDAO;
|
||||
@@ -37,9 +36,6 @@ import com.sap.sailing.server.api.RaceIdentifier;
|
||||
*/
|
||||
@RemoteServiceRelativePath("sailing")
|
||||
public interface SailingService extends RemoteService {
|
||||
//
|
||||
Placemark testPlacemarkSerialization();
|
||||
//
|
||||
List<TracTracConfigurationDAO> getPreviousTracTracConfigurations() throws Exception;
|
||||
|
||||
List<EventDAO> listEvents(boolean withRacePlaces);
|
||||
|
||||
-4
@@ -7,7 +7,6 @@ import java.util.Map;
|
||||
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.sap.sailing.domain.base.Course;
|
||||
import com.sap.sailing.domain.common.Placemark;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.domain.leaderboard.RaceInLeaderboard;
|
||||
@@ -37,9 +36,6 @@ import com.sap.sailing.server.api.RaceIdentifier;
|
||||
* The async counterpart of {@link SailingService}
|
||||
*/
|
||||
public interface SailingServiceAsync {
|
||||
//
|
||||
void testPlacemarkSerialization(AsyncCallback<Placemark> callback);
|
||||
//
|
||||
|
||||
void listEvents(boolean withRacePlaces, AsyncCallback<List<EventDAO>> callback);
|
||||
|
||||
|
||||
+13
-13
@@ -3,7 +3,7 @@ kielWeel2011=Kiel Week 2011
|
||||
stgAccount=STG Account
|
||||
tracTracEvents=TracTrac Events
|
||||
swissTimingEvents=SwissTiming Events
|
||||
trackedBefore=History of tracked events
|
||||
trackedBefore=Historie verfolgter Events
|
||||
listRaces=Rennen anzeigen
|
||||
wind=Wind
|
||||
windPanelLabel=This is the Wind Panel which so far is completely empty.
|
||||
@@ -14,14 +14,14 @@ dampeningInterval=Mittelungsintervall
|
||||
map=Karte
|
||||
race=Wettfahrt
|
||||
races=Wettfahrten
|
||||
tracked=getracked
|
||||
tracked=verfolgt
|
||||
time=Zeit
|
||||
acceleration=Acceleration
|
||||
accelerationHelp=Use "1" for regular play-back speed, "2" for double-speed playback and so on
|
||||
delay=Delay (s)
|
||||
delayHelp=Leave empty to replay at arbitrary times; enter seconds (e.g., "60" for one minute or "0" for none) of delay before live data feed
|
||||
speedInKnots=Speed (kn)
|
||||
fromDeg=From (deg)
|
||||
acceleration=Abspielgeschwindigkeit
|
||||
accelerationHelp="1" für normale Abspielgeschwindigkeit, "2" für doppelte Geschwindigkeit usw.
|
||||
delay=Verzögerung (s)
|
||||
delayHelp=Leer für Wiedergabe zu beliebigen Zeitpunkten; Verzögerung des Datenstroms in Sekunden eingeben (z.B. "60" für eine Minute oder "0" für keine)
|
||||
speedInKnots=Geschwindigkeit (sm/h)
|
||||
fromDeg=aus (Grad)
|
||||
noRacesYet=Bisher keine Wettfahrten
|
||||
total=Gesamt
|
||||
carry=übertr.
|
||||
@@ -107,12 +107,12 @@ livePort=Port Live Data
|
||||
storedPort=Port Stored Data
|
||||
liveUri=Live URI
|
||||
storedUri=Stored URI
|
||||
eventsConnectedTo=Events Currently Tracked
|
||||
eventsConnectedTo=Momentan verfolgte Events
|
||||
hostname=Hostname
|
||||
declinationCheckbox=Correct Wind Bearing by Declination
|
||||
declinationCheckbox=Windrichtung mit Missweisung korrigieren
|
||||
raceStartTrackingColumn=Tracking Started
|
||||
pauseAutomaticRefresh=Pause automatic refresh
|
||||
autoRefresh=Refresh automatically
|
||||
pauseAutomaticRefresh=Keine automatische Aktualisierung
|
||||
autoRefresh=Automatisch aktualisieren
|
||||
delayInSeconds=Verzögerung in Sekunden:
|
||||
delayBetweenAutoAdvances=Intervall zwischen Auto-Updates in Sekunden:
|
||||
chooseUpdateIntervalOfAtLeastOneSecond=Update-Intervall mindestens eine Sekunde
|
||||
@@ -154,7 +154,7 @@ in=in
|
||||
secondsUnit=[s]
|
||||
metersUnit=[m]
|
||||
failedToLoadRaceData=Renndaten konnten nicht geladen werden.
|
||||
close=Close
|
||||
close=Schließen
|
||||
compareCompetitors=Kompetitoren vergleichen
|
||||
description=Beschreibung
|
||||
sailNumber=Segelnummer
|
||||
|
||||
+2
-1
@@ -73,7 +73,7 @@ import com.sap.sailing.server.api.RaceIdentifier;
|
||||
* data. So {@code seriesID, competitorID and markSeriesID} are linked with the index. So if u know for example the
|
||||
* seriesID-index, you can get the competitor by calling competitorID.get(index).
|
||||
*
|
||||
* @author Benjamin Ebling (D056866)
|
||||
* @author Benjamin Ebling (D056866), Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractChartPanel<SettingsType extends ChartSettings> extends SimplePanel implements CompetitorSelectionChangeListener {
|
||||
@@ -409,6 +409,7 @@ public abstract class AbstractChartPanel<SettingsType extends ChartSettings> ext
|
||||
// add hover listener
|
||||
plot.addHoverListener(new PlotHoverListener() {
|
||||
public void onPlotHover(Plot plot, PlotPosition position, PlotItem item) {
|
||||
// FIXME can the indexOf ever find anything? seriesID is a List<SeriesHandler>; item.getSeries() returns a Series object
|
||||
CompetitorDAO competitor = competitorID.get(seriesID.indexOf(item.getSeries()));
|
||||
if (item != null && competitor != null) {
|
||||
if (item.getSeries().getLabel().toLowerCase().contains("mark")) {
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
package com.sap.sailing.gwt.ui.raceboard;
|
||||
|
||||
import com.google.gwt.user.client.ui.AbsolutePanel;
|
||||
import com.google.gwt.user.client.ui.Panel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.shared.components.CollapsablePanel;
|
||||
import com.sap.sailing.gwt.ui.shared.components.Component;
|
||||
import com.sap.sailing.gwt.ui.shared.components.ComponentGroup;
|
||||
import com.sap.sailing.gwt.ui.shared.components.ComponentToolbar;
|
||||
|
||||
/**
|
||||
* A GWT component that visualizes a {@link Component} or a {@link Component} including menus to scroll quickly to the embedded view
|
||||
* of the respective component, collapse/expand buttons for the views embedded and homogeneous settings buttons for
|
||||
* those components that have settings.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class CollapsableComponentViewer<SettingsType> {
|
||||
private final CollapsablePanel disclosurePanel;
|
||||
|
||||
private final Component<SettingsType> component;
|
||||
|
||||
private final StringMessages stringMessages;
|
||||
|
||||
public CollapsableComponentViewer(Component<SettingsType> component, StringMessages stringMessages) {
|
||||
this.component = component;
|
||||
this.stringMessages = stringMessages;
|
||||
|
||||
AbsolutePanel contentPanel = new AbsolutePanel();
|
||||
disclosurePanel = createDisclosePanel(contentPanel, component.getLocalizedShortName(), 150);
|
||||
}
|
||||
|
||||
public Widget getViewerWidget() {
|
||||
return disclosurePanel;
|
||||
}
|
||||
|
||||
public Component<?> getComponent() {
|
||||
return component;
|
||||
}
|
||||
|
||||
private CollapsablePanel createDisclosePanel(Panel contentPanel, String panelTitle, int heightInPx)
|
||||
{
|
||||
CollapsablePanel disclosurePanel = new CollapsablePanel (panelTitle);
|
||||
disclosurePanel.setSize("100%", "100%");
|
||||
disclosurePanel.setOpen(true);
|
||||
|
||||
ComponentToolbar<SettingsType> toolbar = new ComponentToolbar<SettingsType>(component, stringMessages);
|
||||
toolbar.addSettingsButton();
|
||||
disclosurePanel.setHeaderToolbar(toolbar);
|
||||
|
||||
contentPanel.setSize("100%", heightInPx + "px");
|
||||
disclosurePanel.setContent(contentPanel);
|
||||
if(component.getEntryWidget() != null) {
|
||||
contentPanel.add(component.getEntryWidget());
|
||||
} else {
|
||||
if(component instanceof ComponentGroup) {
|
||||
Iterable<Component<?>> components = ((ComponentGroup<?>) component).getComponents();
|
||||
for(Component<?> c: components) {
|
||||
if(c.getEntryWidget() != null)
|
||||
contentPanel.add(c.getEntryWidget());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return disclosurePanel;
|
||||
}
|
||||
|
||||
}
|
||||
+27
-54
@@ -1,26 +1,20 @@
|
||||
package com.sap.sailing.gwt.ui.raceboard;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.event.logical.shared.CloseEvent;
|
||||
import com.google.gwt.event.logical.shared.CloseHandler;
|
||||
import com.google.gwt.event.logical.shared.OpenEvent;
|
||||
import com.google.gwt.event.logical.shared.OpenHandler;
|
||||
import com.google.gwt.user.client.ui.AbsolutePanel;
|
||||
import com.google.gwt.user.client.ui.DisclosurePanel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.user.client.ui.FormPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.Panel;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.ui.adminconsole.RaceMap;
|
||||
import com.sap.sailing.gwt.ui.client.CompetitorSelectionModel;
|
||||
import com.sap.sailing.gwt.ui.client.CompetitorSelectionProvider;
|
||||
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.client.Timer;
|
||||
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardPanel;
|
||||
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardSettings;
|
||||
import com.sap.sailing.gwt.ui.shared.components.Component;
|
||||
import com.sap.sailing.gwt.ui.shared.components.SettingsDialogComponent;
|
||||
import com.sap.sailing.server.api.DefaultLeaderboardName;
|
||||
|
||||
public class RaceBoardPanel extends FormPanel implements Component<RaceBoardSettings> {
|
||||
|
||||
@@ -28,68 +22,46 @@ public class RaceBoardPanel extends FormPanel implements Component<RaceBoardSett
|
||||
|
||||
private final ErrorReporter errorReporter;
|
||||
|
||||
// TODO Frank to use these later
|
||||
// private final StringMessages stringMessages;
|
||||
|
||||
private String raceBoardName;
|
||||
|
||||
private static RaceBoardResources resources = GWT.create(RaceBoardResources.class);
|
||||
|
||||
// TODO Frank to use these later
|
||||
// private List<DisclosurePanel> collapsablePanels;
|
||||
|
||||
private final CompetitorSelectionProvider competitorSelectionProvider;
|
||||
private final List<CollapsableComponentViewer<?>> collapsableViewers;
|
||||
|
||||
public RaceBoardPanel(SailingServiceAsync sailingService, String raceBoardName, ErrorReporter errorReporter,
|
||||
final StringMessages stringMessages) {
|
||||
this.sailingService = sailingService;
|
||||
this.setRaceBoardName(raceBoardName);
|
||||
this.errorReporter = errorReporter;
|
||||
// TODO Frank to use these later
|
||||
// this.stringMessages = stringMessages;
|
||||
|
||||
VerticalPanel mainPanel = new VerticalPanel();
|
||||
// TODO marcus: add styles in css
|
||||
mainPanel.addStyleName("mainPanel");
|
||||
setWidget(mainPanel);
|
||||
competitorSelectionProvider = new CompetitorSelectionModel(/* hasMultiSelection */ true);
|
||||
RaceMap raceMap = new RaceMap(sailingService, errorReporter, new Timer(
|
||||
/* delayBetweenAutoAdvancesInMilliseconds */500), competitorSelectionProvider, stringMessages);
|
||||
collapsableViewers = new ArrayList<CollapsableComponentViewer<?>>();
|
||||
for(int i = 0; i < 4; i++) {
|
||||
if(i == 0) {
|
||||
AbsolutePanel contentPanel = new AbsolutePanel();
|
||||
DisclosurePanel panel = createDisclosePanel(contentPanel, "Panel " + i, 300);
|
||||
CompetitorSelectionModel competitorSelectionModel = new CompetitorSelectionModel(/* hasMultiSelection */ true);
|
||||
//final RaceMapPanel raceMapPanel = new RaceMapPanel(sailingService, competitorSelectionModel, this, this, stringMessages);
|
||||
LeaderboardPanel defaultLeaderboardPanel = new LeaderboardPanel(sailingService, competitorSelectionModel,
|
||||
DefaultLeaderboardName.DEFAULT_LEADERBOARD_NAME, errorReporter, stringMessages);
|
||||
|
||||
raceMap.loadMapsAPI(contentPanel);
|
||||
mainPanel.add(panel);
|
||||
CollapsableComponentViewer<LeaderboardSettings> viewer = new CollapsableComponentViewer<LeaderboardSettings>(
|
||||
defaultLeaderboardPanel, stringMessages);
|
||||
collapsableViewers.add(viewer);
|
||||
} else {
|
||||
VerticalPanel contentPanel = new VerticalPanel();
|
||||
DisclosurePanel panel = createDisclosePanel(contentPanel, "Panel " + i, 100);
|
||||
contentPanel.add(new Label("Content of panel " + i));
|
||||
mainPanel.add(panel);
|
||||
SimpleComponentGroup<Object> componentGroup = new SimpleComponentGroup<Object>("Component Group " + i);
|
||||
componentGroup.addComponent(new SimpleComponent("My Component"));
|
||||
componentGroup.addComponent(new SimpleComponent("My Component 2"));
|
||||
componentGroup.addComponent(new SimpleComponent("My Component 3"));
|
||||
|
||||
//LeaderboardPanel leaderboardPanel = LeaderboardPanel();
|
||||
CollapsableComponentViewer<Object> viewer = new CollapsableComponentViewer<Object>(componentGroup, stringMessages);
|
||||
collapsableViewers.add(viewer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DisclosurePanel createDisclosePanel(Panel contentPanel, String panelTitle, int heightInPx) {
|
||||
DisclosurePanel disclosurePanel = new DisclosurePanel (resources.openIcon(), resources.closeIcon(), panelTitle);
|
||||
disclosurePanel.setSize("100%", "100%");
|
||||
disclosurePanel.addStyleName("disclosePanel");
|
||||
disclosurePanel.setOpen(true);
|
||||
contentPanel.setSize("100%", heightInPx + "px");
|
||||
disclosurePanel.setContent(contentPanel);
|
||||
|
||||
disclosurePanel.addOpenHandler(new OpenHandler<DisclosurePanel>() {
|
||||
@Override
|
||||
public void onOpen(OpenEvent<DisclosurePanel> event) {
|
||||
}
|
||||
});
|
||||
disclosurePanel.addCloseHandler(new CloseHandler<DisclosurePanel>() {
|
||||
@Override
|
||||
public void onClose(CloseEvent<DisclosurePanel> event) {
|
||||
}
|
||||
});
|
||||
return disclosurePanel;
|
||||
for (CollapsableComponentViewer<?> viewer : collapsableViewers) {
|
||||
mainPanel.add(viewer.getViewerWidget());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -132,3 +104,4 @@ public class RaceBoardPanel extends FormPanel implements Component<RaceBoardSett
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -11,4 +11,6 @@ interface RaceBoardResources extends ClientBundle {
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/close.png")
|
||||
ImageResource closeIcon();
|
||||
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/settings.png")
|
||||
ImageResource settingsIcon();
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package com.sap.sailing.gwt.ui.raceboard;
|
||||
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.ui.shared.components.Component;
|
||||
import com.sap.sailing.gwt.ui.shared.components.SettingsDialogComponent;
|
||||
|
||||
public class SimpleComponent implements Component<SimpleComponentSettings> {
|
||||
|
||||
private String componentName;
|
||||
|
||||
private final Label label;
|
||||
public SimpleComponent(String componentName) {
|
||||
this.componentName = componentName;
|
||||
|
||||
label = new Label("Ich bin eine Label component");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocalizedShortName() {
|
||||
return componentName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Widget getEntryWidget() {
|
||||
return label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSettings() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SettingsDialogComponent<SimpleComponentSettings> getSettingsDialogComponent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSettings(SimpleComponentSettings newSettings) {
|
||||
}
|
||||
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
package com.sap.sailing.gwt.ui.raceboard;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.ui.shared.components.Component;
|
||||
import com.sap.sailing.gwt.ui.shared.components.ComponentGroup;
|
||||
import com.sap.sailing.gwt.ui.shared.components.SettingsDialogComponent;
|
||||
|
||||
public class SimpleComponentGroup<SettingsType> implements ComponentGroup<SettingsType> {
|
||||
|
||||
private String groupName;
|
||||
|
||||
private final List<Component<?>> components;
|
||||
|
||||
public SimpleComponentGroup(String groupName) {
|
||||
this.groupName = groupName;
|
||||
components = new ArrayList<Component<?>>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSettings() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SettingsDialogComponent<SettingsType> getSettingsDialogComponent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSettings(SettingsType newSettings) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocalizedShortName() {
|
||||
return groupName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Widget getEntryWidget() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addComponent(Component<?> component) {
|
||||
return components.add(component);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeComponent(Component<?> component) {
|
||||
return components.remove(component);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Component<?>> getComponents() {
|
||||
return components;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package com.sap.sailing.gwt.ui.raceboard;
|
||||
|
||||
public class SimpleComponentSettings {
|
||||
|
||||
}
|
||||
-8
@@ -53,7 +53,6 @@ import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.LegType;
|
||||
import com.sap.sailing.domain.common.NoWindError;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.Placemark;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
@@ -131,13 +130,6 @@ import com.sap.sailing.server.api.RaceIdentifier;
|
||||
* The server side implementation of the RPC service.
|
||||
*/
|
||||
public class SailingServiceImpl extends RemoteServiceServlet implements SailingService, RaceFetcher, EventFetcher {
|
||||
//
|
||||
@Override
|
||||
public Placemark testPlacemarkSerialization() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
//
|
||||
private static final Logger logger = Logger.getLogger(SailingServiceImpl.class.getName());
|
||||
|
||||
private static final long serialVersionUID = 9031688830194537489L;
|
||||
|
||||
@@ -33,6 +33,7 @@ public class EventDAO extends NamedDAO implements IsSerializable {
|
||||
public String getLocationAsString() {
|
||||
//TODO Finish the format of the location string
|
||||
if (locations == null) {
|
||||
locations = "";
|
||||
for (RegattaDAO regattaDAO : regattas) {
|
||||
for (RaceDAO raceDAO : regattaDAO.races) {
|
||||
RacePlaceOrder placeOrder = raceDAO.racePlaces;
|
||||
|
||||
+439
@@ -0,0 +1,439 @@
|
||||
package com.sap.sailing.gwt.ui.shared.components;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.google.gwt.animation.client.Animation;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.event.logical.shared.CloseEvent;
|
||||
import com.google.gwt.event.logical.shared.CloseHandler;
|
||||
import com.google.gwt.event.logical.shared.HasCloseHandlers;
|
||||
import com.google.gwt.event.logical.shared.HasOpenHandlers;
|
||||
import com.google.gwt.event.logical.shared.OpenEvent;
|
||||
import com.google.gwt.event.logical.shared.OpenHandler;
|
||||
import com.google.gwt.event.shared.HandlerRegistration;
|
||||
import com.google.gwt.resources.client.ImageResource;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.Element;
|
||||
import com.google.gwt.user.client.Event;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.Grid;
|
||||
import com.google.gwt.user.client.ui.HasAnimation;
|
||||
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
|
||||
import com.google.gwt.user.client.ui.HasText;
|
||||
import com.google.gwt.user.client.ui.HasVerticalAlignment;
|
||||
import com.google.gwt.user.client.ui.HasWidgets;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.Image;
|
||||
import com.google.gwt.user.client.ui.IsWidget;
|
||||
import com.google.gwt.user.client.ui.SimplePanel;
|
||||
import com.google.gwt.user.client.ui.UIObject;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
|
||||
/**
|
||||
* A widget that consists of a header and a content panel that discloses the content when a user clicks on the header.
|
||||
*
|
||||
* <h3>CSS Style Rules</h3>
|
||||
* <dl class="css">
|
||||
* <dt>.gwt-DisclosurePanel
|
||||
* <dd>the panel's primary style
|
||||
* <dt>.gwt-DisclosurePanel-open
|
||||
* <dd>dependent style set when panel is open
|
||||
* <dt>.gwt-DisclosurePanel-closed
|
||||
* <dd>dependent style set when panel is closed
|
||||
* </dl>
|
||||
* <p>
|
||||
* The header and content sections can be easily selected using css with a child selector:<br/>
|
||||
* .gwt-DisclosurePanel-open .header { ... }
|
||||
* </p>
|
||||
*/
|
||||
public final class CollapsablePanel extends Composite implements HasWidgets.ForIsWidget, HasAnimation,
|
||||
HasOpenHandlers<CollapsablePanel>, HasCloseHandlers<CollapsablePanel> {
|
||||
|
||||
private static ComponentResources resources = GWT.create(ComponentResources.class);
|
||||
|
||||
/**
|
||||
* Used to wrap widgets in the header to provide click support. Effectively wraps the widget in an
|
||||
* <code>anchor</code> to get automatic keyboard access.
|
||||
*/
|
||||
private final class ClickableHeader extends SimplePanel {
|
||||
|
||||
private ClickableHeader() {
|
||||
// Anchor is used to allow keyboard access.
|
||||
super(DOM.createAnchor());
|
||||
Element elem = getElement();
|
||||
DOM.setElementProperty(elem, "href", "javascript:void(0);");
|
||||
// Avoids layout problems from having blocks in inlines.
|
||||
DOM.setStyleAttribute(elem, "display", "block");
|
||||
sinkEvents(Event.ONCLICK);
|
||||
setStyleName(STYLENAME_HEADER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBrowserEvent(Event event) {
|
||||
// no need to call super.
|
||||
switch (DOM.eventGetType(event)) {
|
||||
case Event.ONCLICK:
|
||||
// Prevent link default action.
|
||||
DOM.eventPreventDefault(event);
|
||||
setOpen(!isOpen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link Animation} used to open the content.
|
||||
*/
|
||||
private static class ContentAnimation extends Animation {
|
||||
/**
|
||||
* Whether the item is being opened or closed.
|
||||
*/
|
||||
private boolean opening;
|
||||
|
||||
/**
|
||||
* The {@link CollapsablePanel} being affected.
|
||||
*/
|
||||
private CollapsablePanel curPanel;
|
||||
|
||||
/**
|
||||
* Open or close the content.
|
||||
*
|
||||
* @param panel
|
||||
* the panel to open or close
|
||||
* @param animate
|
||||
* true to animate, false to open instantly
|
||||
*/
|
||||
public void setOpen(CollapsablePanel panel, boolean animate) {
|
||||
// Immediately complete previous open
|
||||
cancel();
|
||||
|
||||
// Open the new item
|
||||
if (animate) {
|
||||
curPanel = panel;
|
||||
opening = panel.isOpen;
|
||||
run(ANIMATION_DURATION);
|
||||
} else {
|
||||
panel.contentWrapper.setVisible(panel.isOpen);
|
||||
if (panel.isOpen) {
|
||||
// Special treatment on the visible case to ensure LazyPanel works
|
||||
panel.getContent().setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onComplete() {
|
||||
if (!opening) {
|
||||
curPanel.contentWrapper.setVisible(false);
|
||||
}
|
||||
DOM.setStyleAttribute(curPanel.contentWrapper.getElement(), "height", "auto");
|
||||
curPanel = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
if (opening) {
|
||||
curPanel.contentWrapper.setVisible(true);
|
||||
// Special treatment on the visible case to ensure LazyPanel works
|
||||
curPanel.getContent().setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUpdate(double progress) {
|
||||
int scrollHeight = DOM.getElementPropertyInt(curPanel.contentWrapper.getElement(), "scrollHeight");
|
||||
int height = (int) (progress * scrollHeight);
|
||||
if (!opening) {
|
||||
height = scrollHeight - height;
|
||||
}
|
||||
height = Math.max(height, 1);
|
||||
DOM.setStyleAttribute(curPanel.contentWrapper.getElement(), "height", height + "px");
|
||||
DOM.setStyleAttribute(curPanel.contentWrapper.getElement(), "width", "auto");
|
||||
}
|
||||
}
|
||||
|
||||
public interface Imager {
|
||||
Image makeImage();
|
||||
|
||||
void updateImage(boolean open, Image image);
|
||||
}
|
||||
|
||||
/**
|
||||
* The duration of the animation.
|
||||
*/
|
||||
private static final int ANIMATION_DURATION = 350;
|
||||
|
||||
// Stylename constants.
|
||||
private static final String STYLENAME_DEFAULT = "gwt-DisclosurePanel";
|
||||
|
||||
private static final String STYLENAME_SUFFIX_OPEN = "open";
|
||||
|
||||
private static final String STYLENAME_SUFFIX_CLOSED = "closed";
|
||||
|
||||
private static final String STYLENAME_HEADER = "header";
|
||||
|
||||
private static final String STYLENAME_CONTENT = "content";
|
||||
|
||||
/**
|
||||
* The {@link Animation} used to open and close the content.
|
||||
*/
|
||||
private static ContentAnimation contentAnimation;
|
||||
|
||||
/**
|
||||
* top level widget. The first child will be a reference to {@link #header}. The second child will be a reference to
|
||||
* {@link #contentWrapper}.
|
||||
*/
|
||||
private final VerticalPanel mainPanel = new VerticalPanel();
|
||||
|
||||
/**
|
||||
* The wrapper around the content widget.
|
||||
*/
|
||||
private final SimplePanel contentWrapper = new SimplePanel();
|
||||
|
||||
/**
|
||||
* holds the header widget.
|
||||
*/
|
||||
// private final DockPanel header = new DockPanel();
|
||||
|
||||
private final Grid header = new Grid(1,2);
|
||||
|
||||
private final ClickableHeader clickableHeader = new ClickableHeader();
|
||||
|
||||
private boolean isAnimationEnabled = false;
|
||||
|
||||
private boolean isOpen = false;
|
||||
|
||||
/**
|
||||
* Creates an empty ThePanel that is initially closed.
|
||||
*/
|
||||
private CollapsablePanel() {
|
||||
initWidget(mainPanel);
|
||||
|
||||
header.setWidth("100%");
|
||||
header.getCellFormatter().setWidth(0, 0, "50%");
|
||||
header.getCellFormatter().setWidth(0, 1, "50%");
|
||||
header.getCellFormatter().setAlignment(0, 0, HasHorizontalAlignment.ALIGN_LEFT, HasVerticalAlignment.ALIGN_MIDDLE);
|
||||
header.getCellFormatter().setAlignment(0, 1, HasHorizontalAlignment.ALIGN_RIGHT, HasVerticalAlignment.ALIGN_MIDDLE);
|
||||
|
||||
//header.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
|
||||
mainPanel.add(header);
|
||||
mainPanel.add(contentWrapper);
|
||||
DOM.setStyleAttribute(contentWrapper.getElement(), "padding", "0px");
|
||||
DOM.setStyleAttribute(contentWrapper.getElement(), "overflow", "hidden");
|
||||
setStyleName(STYLENAME_DEFAULT);
|
||||
setContentDisplay(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ThePanel with the specified header text, an initial open/close state and a bundle of images to be used
|
||||
* in the default header widget.
|
||||
*
|
||||
* @param openImage
|
||||
* the open state image resource
|
||||
* @param closedImage
|
||||
* the closed state image resource
|
||||
* @param headerText
|
||||
* the text to be displayed in the header
|
||||
*/
|
||||
public CollapsablePanel(ImageResource openImage, ImageResource closedImage, String headerText) {
|
||||
this();
|
||||
setClickableHeader(new CollapsablePanelDefaultHeader(this, openImage, closedImage, headerText));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ThePanel that will be initially closed using the specified text in the header.
|
||||
*
|
||||
* @param headerText
|
||||
* the text to be displayed in the header
|
||||
*/
|
||||
public CollapsablePanel(String headerText) {
|
||||
this(resources.openIcon(), resources.closeIcon(), headerText);
|
||||
}
|
||||
|
||||
private void setClickableHeader(Widget widget) {
|
||||
clickableHeader.add(widget);
|
||||
header.setWidget(0, 0, clickableHeader);
|
||||
// header.add(clickableHeader, DockPanel.WEST);
|
||||
}
|
||||
|
||||
public void setHeaderToolbar(HorizontalPanel toolbar) {
|
||||
// header.add(toolbar, DockPanel.EAST);
|
||||
header.setWidget(0, 1, toolbar);
|
||||
}
|
||||
|
||||
public void add(Widget w) {
|
||||
if (this.getContent() == null) {
|
||||
setContent(w);
|
||||
} else {
|
||||
throw new IllegalStateException("A DisclosurePanel can only contain two Widgets.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overloaded version for IsWidget.
|
||||
*
|
||||
* @see #add(Widget)
|
||||
*/
|
||||
public void add(IsWidget w) {
|
||||
this.add(asWidgetOrNull(w));
|
||||
}
|
||||
|
||||
public HandlerRegistration addCloseHandler(CloseHandler<CollapsablePanel> handler) {
|
||||
return addHandler(handler, CloseEvent.getType());
|
||||
}
|
||||
|
||||
public HandlerRegistration addOpenHandler(OpenHandler<CollapsablePanel> handler) {
|
||||
return addHandler(handler, OpenEvent.getType());
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
setContent(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the widget that was previously set in {@link #setContent(Widget)}.
|
||||
*
|
||||
* @return the panel's current content widget
|
||||
*/
|
||||
public Widget getContent() {
|
||||
return contentWrapper.getWidget();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the widget that is currently being used as a header.
|
||||
*
|
||||
* @return the widget currently being used as a header
|
||||
*/
|
||||
public Widget getHeader() {
|
||||
return header.asWidget();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a {@link HasText} instance to provide access to the headers's text, if the header widget does provide such
|
||||
* access.
|
||||
*
|
||||
* @return a reference to the header widget if it implements {@link HasText}, <code>null</code> otherwise
|
||||
*/
|
||||
public HasText getHeaderTextAccessor() {
|
||||
Widget widget = header.asWidget();
|
||||
return (widget instanceof HasText) ? (HasText) widget : null;
|
||||
}
|
||||
|
||||
public boolean isAnimationEnabled() {
|
||||
return isAnimationEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the panel is open.
|
||||
*
|
||||
* @return <code>true</code> if panel is in open state
|
||||
*/
|
||||
public boolean isOpen() {
|
||||
return isOpen;
|
||||
}
|
||||
|
||||
public Iterator<Widget> iterator() {
|
||||
return null;
|
||||
// return WidgetIterators.createWidgetIterator(this,
|
||||
// new Widget[] {getContent()});
|
||||
}
|
||||
|
||||
public boolean remove(Widget w) {
|
||||
if (w == getContent()) {
|
||||
setContent(null);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overloaded version for IsWidget.
|
||||
*
|
||||
* @see #remove(Widget)
|
||||
*/
|
||||
public boolean remove(IsWidget w) {
|
||||
return this.remove(asWidgetOrNull(w));
|
||||
}
|
||||
|
||||
public void setAnimationEnabled(boolean enable) {
|
||||
isAnimationEnabled = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the content widget which can be opened and closed by this panel. If there is a preexisting content widget,
|
||||
* it will be detached.
|
||||
*
|
||||
* @param content
|
||||
* the widget to be used as the content panel
|
||||
*/
|
||||
public void setContent(Widget content) {
|
||||
final Widget currentContent = getContent();
|
||||
|
||||
// Remove existing content widget.
|
||||
if (currentContent != null) {
|
||||
contentWrapper.setWidget(null);
|
||||
currentContent.removeStyleName(STYLENAME_CONTENT);
|
||||
}
|
||||
|
||||
// Add new content widget if != null.
|
||||
if (content != null) {
|
||||
contentWrapper.setWidget(content);
|
||||
content.addStyleName(STYLENAME_CONTENT);
|
||||
setContentDisplay(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the visible state of this <code>ThePanel</code>.
|
||||
*
|
||||
* @param isOpen
|
||||
* <code>true</code> to open the panel, <code>false</code> to close
|
||||
*/
|
||||
public void setOpen(boolean isOpen) {
|
||||
if (this.isOpen != isOpen) {
|
||||
this.isOpen = isOpen;
|
||||
setContentDisplay(true);
|
||||
fireEvent();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>Affected Elements:</b>
|
||||
* <ul>
|
||||
* <li>-header = the clickable header.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @see UIObject#onEnsureDebugId(String)
|
||||
*/
|
||||
@Override
|
||||
protected void onEnsureDebugId(String baseID) {
|
||||
super.onEnsureDebugId(baseID);
|
||||
header.ensureDebugId(baseID + "-header");
|
||||
}
|
||||
|
||||
private void fireEvent() {
|
||||
if (isOpen) {
|
||||
OpenEvent.fire(this, this);
|
||||
} else {
|
||||
CloseEvent.fire(this, this);
|
||||
}
|
||||
}
|
||||
|
||||
private void setContentDisplay(boolean animate) {
|
||||
if (isOpen) {
|
||||
removeStyleDependentName(STYLENAME_SUFFIX_CLOSED);
|
||||
addStyleDependentName(STYLENAME_SUFFIX_OPEN);
|
||||
} else {
|
||||
removeStyleDependentName(STYLENAME_SUFFIX_OPEN);
|
||||
addStyleDependentName(STYLENAME_SUFFIX_CLOSED);
|
||||
}
|
||||
|
||||
if (getContent() != null) {
|
||||
if (contentAnimation == null) {
|
||||
contentAnimation = new ContentAnimation();
|
||||
}
|
||||
contentAnimation.setOpen(this, animate && isAnimationEnabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
package com.sap.sailing.gwt.ui.shared.components;
|
||||
|
||||
import com.google.gwt.event.logical.shared.CloseEvent;
|
||||
import com.google.gwt.event.logical.shared.CloseHandler;
|
||||
import com.google.gwt.event.logical.shared.OpenEvent;
|
||||
import com.google.gwt.event.logical.shared.OpenHandler;
|
||||
import com.google.gwt.resources.client.ImageResource;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.Element;
|
||||
import com.google.gwt.user.client.ui.HasText;
|
||||
import com.google.gwt.user.client.ui.Image;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.ui.shared.components.CollapsablePanel.Imager;
|
||||
|
||||
/**
|
||||
* The default header widget used within a {@link CollapsablePanel}.
|
||||
*/
|
||||
public class CollapsablePanelDefaultHeader extends Widget implements HasText, OpenHandler<CollapsablePanel>,
|
||||
CloseHandler<CollapsablePanel> {
|
||||
|
||||
/**
|
||||
* imageTD holds the image for the icon, not null. labelTD holds the text for the label.
|
||||
*/
|
||||
private final Element labelTD;
|
||||
|
||||
private final Image iconImage;
|
||||
private final Imager imager;
|
||||
private final CollapsablePanel collapsablePanel;
|
||||
|
||||
protected CollapsablePanelDefaultHeader(CollapsablePanel collapsablePanel, Imager imager, String text) {
|
||||
this.imager = imager;
|
||||
this.collapsablePanel = collapsablePanel;
|
||||
iconImage = imager.makeImage();
|
||||
|
||||
// I do not need any Widgets here, just a DOM structure.
|
||||
Element root = DOM.createTable();
|
||||
Element tbody = DOM.createTBody();
|
||||
Element tr = DOM.createTR();
|
||||
final Element imageTD = DOM.createTD();
|
||||
labelTD = DOM.createTD();
|
||||
|
||||
setElement(root);
|
||||
|
||||
DOM.appendChild(root, tbody);
|
||||
DOM.appendChild(tbody, tr);
|
||||
DOM.appendChild(tr, imageTD);
|
||||
DOM.appendChild(tr, labelTD);
|
||||
|
||||
// set image TD to be same width as image.
|
||||
DOM.setElementProperty(imageTD, "align", "center");
|
||||
DOM.setElementProperty(imageTD, "valign", "middle");
|
||||
DOM.setStyleAttribute(imageTD, "width", iconImage.getWidth() + "px");
|
||||
|
||||
DOM.appendChild(imageTD, iconImage.getElement());
|
||||
|
||||
setText(text);
|
||||
|
||||
collapsablePanel.addOpenHandler(this);
|
||||
collapsablePanel.addCloseHandler(this);
|
||||
setStyle();
|
||||
}
|
||||
|
||||
protected CollapsablePanelDefaultHeader(CollapsablePanel collapsablePanel, final ImageResource openImage,
|
||||
final ImageResource closedImage, String text) {
|
||||
this(collapsablePanel, new Imager() {
|
||||
public Image makeImage() {
|
||||
return new Image(closedImage);
|
||||
}
|
||||
|
||||
public void updateImage(boolean open, Image image) {
|
||||
if (open) {
|
||||
image.setResource(openImage);
|
||||
} else {
|
||||
image.setResource(closedImage);
|
||||
}
|
||||
}
|
||||
}, text);
|
||||
}
|
||||
|
||||
public final String getText() {
|
||||
return DOM.getInnerText(labelTD);
|
||||
}
|
||||
|
||||
public final void onClose(CloseEvent<CollapsablePanel> event) {
|
||||
setStyle();
|
||||
}
|
||||
|
||||
public final void onOpen(OpenEvent<CollapsablePanel> event) {
|
||||
setStyle();
|
||||
}
|
||||
|
||||
public final void setText(String text) {
|
||||
DOM.setInnerText(labelTD, text);
|
||||
}
|
||||
|
||||
private void setStyle() {
|
||||
imager.updateImage(collapsablePanel.isOpen(), iconImage);
|
||||
}
|
||||
}
|
||||
+10
-14
@@ -1,5 +1,7 @@
|
||||
package com.sap.sailing.gwt.ui.shared.components;
|
||||
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
@@ -8,23 +10,17 @@ package com.sap.sailing.gwt.ui.shared.components;
|
||||
* the type that describes this component's settings (if any). Use {@link Object} in case your components
|
||||
* doesn't support any settings.
|
||||
*/
|
||||
public interface Component<SettingsType> extends ComponentForestEntry {
|
||||
public interface Component<SettingsType> extends ComponentSettings<SettingsType> {
|
||||
|
||||
/**
|
||||
* @return whether this component has settings that a user may change; if so,
|
||||
* @return the name to display to a user for quick navigation to this component
|
||||
*/
|
||||
boolean hasSettings();
|
||||
String getLocalizedShortName();
|
||||
|
||||
/**
|
||||
* If this component {@link #hasSettings has settings}, this method may return a component for the settings dialog.
|
||||
* It will be used to obtain a widget shown in the settings dialog, a validator for the component-specific settings,
|
||||
* as well as to produce a result from the widget's state when the settings dialog wants to validate or return the
|
||||
* settings.
|
||||
* A component may or may not have a {@link Widget} used to render its contents. Typically,
|
||||
* entries with sub-entries don't afford a widget of their own but let the framework choose a container
|
||||
* in which to aggregate their entries' widgets.
|
||||
*/
|
||||
SettingsDialogComponent<SettingsType> getSettingsDialogComponent();
|
||||
|
||||
/**
|
||||
* Updates the settings of this component. Expected to be called when a settings dialog using this component's
|
||||
* {@link #getSettingsDialogComponent()} has been confirmed.
|
||||
*/
|
||||
void updateSettings(SettingsType newSettings);
|
||||
Widget getEntryWidget();
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package com.sap.sailing.gwt.ui.shared.components;
|
||||
|
||||
public interface ComponentGroup<SettingsType> extends Component<SettingsType> {
|
||||
|
||||
boolean addComponent(Component<?> component);
|
||||
|
||||
boolean removeComponent(Component<?> component);
|
||||
|
||||
Iterable<Component<?>> getComponents();
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.sap.sailing.gwt.ui.shared.components;
|
||||
|
||||
import com.google.gwt.resources.client.ClientBundle;
|
||||
import com.google.gwt.resources.client.ImageResource;
|
||||
|
||||
interface ComponentResources extends ClientBundle {
|
||||
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/open.png")
|
||||
ImageResource openIcon();
|
||||
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/close.png")
|
||||
ImageResource closeIcon();
|
||||
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/settings.png")
|
||||
ImageResource settingsIcon();
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.sap.sailing.gwt.ui.shared.components;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
* @param <SettingsType>
|
||||
* the type that describes this component's settings (if any). Use {@link Object} in case your components
|
||||
* doesn't support any settings.
|
||||
*/public interface ComponentSettings<SettingsType> {
|
||||
|
||||
/**
|
||||
* @return whether this component has settings that a user may change; if so,
|
||||
*/
|
||||
boolean hasSettings();
|
||||
|
||||
/**
|
||||
* If this component {@link #hasSettings has settings}, this method may return a component for the settings dialog.
|
||||
* It will be used to obtain a widget shown in the settings dialog, a validator for the component-specific settings,
|
||||
* as well as to produce a result from the widget's state when the settings dialog wants to validate or return the
|
||||
* settings.
|
||||
*/
|
||||
SettingsDialogComponent<SettingsType> getSettingsDialogComponent();
|
||||
|
||||
/**
|
||||
* Updates the settings of this component. Expected to be called when a settings dialog using this component's
|
||||
* {@link #getSettingsDialogComponent()} has been confirmed.
|
||||
*/
|
||||
void updateSettings(SettingsType newSettings);
|
||||
}
|
||||
+39
-1
@@ -1,7 +1,45 @@
|
||||
package com.sap.sailing.gwt.ui.shared.components;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.resources.client.ImageResource;
|
||||
import com.google.gwt.user.client.ui.AbstractImagePrototype;
|
||||
import com.google.gwt.user.client.ui.Anchor;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
|
||||
public class ComponentTitleBar extends HorizontalPanel {
|
||||
public class ComponentToolbar<SettingsType> extends HorizontalPanel {
|
||||
|
||||
private static ComponentResources resources = GWT.create(ComponentResources.class);
|
||||
|
||||
private final Component<SettingsType> component;
|
||||
final StringMessages stringMessages;
|
||||
|
||||
public ComponentToolbar(final Component<SettingsType> component, final StringMessages stringMessages) {
|
||||
super();
|
||||
|
||||
this.setSpacing(10);
|
||||
this.component = component;
|
||||
this.stringMessages = stringMessages;
|
||||
}
|
||||
|
||||
public void addSettingsButton() {
|
||||
if(component.hasSettings()) {
|
||||
ImageResource settingsImage = resources.settingsIcon();
|
||||
Anchor showConfigAnchor = new Anchor(AbstractImagePrototype.create(settingsImage).getSafeHtml());
|
||||
showConfigAnchor.setTitle(stringMessages.configuration());
|
||||
showConfigAnchor.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
new SettingsDialog<SettingsType>(component, stringMessages).show();
|
||||
}
|
||||
});
|
||||
|
||||
this.add(showConfigAnchor);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
+30
-27
@@ -165,7 +165,6 @@ public class OverviewEventPanel extends AbstractEventPanel {
|
||||
functionPanelEvents.add(btnShowLeaderboards);
|
||||
|
||||
// Create event table
|
||||
// TODO
|
||||
{
|
||||
eventTable = new CellTable<EventDAO>();
|
||||
eventTable.setWidth("100%");
|
||||
@@ -178,6 +177,7 @@ public class OverviewEventPanel extends AbstractEventPanel {
|
||||
return locations != null ? locations : stringConstants.locationNotAvailable();
|
||||
}
|
||||
};
|
||||
locationColumn.setSortable(true);
|
||||
//Creating event name column
|
||||
TextColumn<EventDAO> nameColumn = new TextColumn<EventDAO>() {
|
||||
@Override
|
||||
@@ -185,14 +185,16 @@ public class OverviewEventPanel extends AbstractEventPanel {
|
||||
return eventDAO.name;
|
||||
}
|
||||
};
|
||||
nameColumn.setSortable(true);
|
||||
//Creating start date column
|
||||
TextColumn<EventDAO> startDateColumn = new TextColumn<EventDAO>() {
|
||||
@Override
|
||||
public String getValue(EventDAO eventDAO) {
|
||||
Date start = eventDAO.regattas.get(0).races.get(0).startOfRace;
|
||||
return start != null ? start.toString() : stringConstants.startDateNotAvailable();
|
||||
return start != null ? dateFormatter.render(start) : stringConstants.startDateNotAvailable();
|
||||
}
|
||||
};
|
||||
startDateColumn.setSortable(true);
|
||||
|
||||
eventTable.addColumn(locationColumn, stringConstants.location());
|
||||
eventTable.addColumn(nameColumn, stringConstants.eventName());
|
||||
@@ -243,7 +245,7 @@ public class OverviewEventPanel extends AbstractEventPanel {
|
||||
functionPanelLeaderboards.add(btnHideLeaderboards);
|
||||
|
||||
// Create leaderboard list
|
||||
// TODO
|
||||
// TODO
|
||||
|
||||
loadEvents();
|
||||
|
||||
@@ -254,30 +256,6 @@ public class OverviewEventPanel extends AbstractEventPanel {
|
||||
//Until here
|
||||
}
|
||||
|
||||
private ListHandler<EventDAO> getEventSortHandler(List<EventDAO> list, TextColumn<EventDAO> locationColumn,
|
||||
TextColumn<EventDAO> nameColumn, TextColumn<EventDAO> startDateColumn) {
|
||||
ListHandler<EventDAO> sortHandler = new ListHandler<EventDAO>(list);
|
||||
sortHandler.setComparator(locationColumn, new Comparator<EventDAO>() {
|
||||
@Override
|
||||
public int compare(EventDAO e1, EventDAO e2) {
|
||||
return e1.getLocationAsString().compareTo(e2.getLocationAsString());
|
||||
}
|
||||
});
|
||||
sortHandler.setComparator(nameColumn, new Comparator<EventDAO>() {
|
||||
@Override
|
||||
public int compare(EventDAO e1, EventDAO e2) {
|
||||
return e1.name.compareTo(e2.name);
|
||||
}
|
||||
});
|
||||
sortHandler.setComparator(startDateColumn, new Comparator<EventDAO>() {
|
||||
@Override
|
||||
public int compare(EventDAO e1, EventDAO e2) {
|
||||
return e1.getStartDate().compareTo(e2.getStartDate());
|
||||
}
|
||||
});
|
||||
return sortHandler;
|
||||
}
|
||||
|
||||
private void loadEvents(final Runnable actionAfterLoading) {
|
||||
sailingService.listEvents(true, new AsyncCallback<List<EventDAO>>() {
|
||||
|
||||
@@ -344,4 +322,29 @@ public class OverviewEventPanel extends AbstractEventPanel {
|
||||
|
||||
}
|
||||
|
||||
private ListHandler<EventDAO> getEventSortHandler(List<EventDAO> list, TextColumn<EventDAO> locationColumn,
|
||||
TextColumn<EventDAO> nameColumn, TextColumn<EventDAO> startDateColumn) {
|
||||
//TODO Check if comparators are correct
|
||||
ListHandler<EventDAO> sortHandler = new ListHandler<EventDAO>(list);
|
||||
sortHandler.setComparator(locationColumn, new Comparator<EventDAO>() {
|
||||
@Override
|
||||
public int compare(EventDAO e1, EventDAO e2) {
|
||||
return e1.getLocationAsString().compareTo(e2.getLocationAsString());
|
||||
}
|
||||
});
|
||||
sortHandler.setComparator(nameColumn, new Comparator<EventDAO>() {
|
||||
@Override
|
||||
public int compare(EventDAO e1, EventDAO e2) {
|
||||
return e1.name.compareTo(e2.name);
|
||||
}
|
||||
});
|
||||
sortHandler.setComparator(startDateColumn, new Comparator<EventDAO>() {
|
||||
@Override
|
||||
public int compare(EventDAO e1, EventDAO e2) {
|
||||
return e1.getStartDate().compareTo(e2.getStartDate());
|
||||
}
|
||||
});
|
||||
return sortHandler;
|
||||
}
|
||||
|
||||
}
|
||||
+1
@@ -46,6 +46,7 @@
|
||||
<!-- Specify the paths for translatable code -->
|
||||
<extend-property name="locale" values="de"/>
|
||||
<source path='client'/>
|
||||
<source path='components'/>
|
||||
<source path='adminconsole'/>
|
||||
<source path='leaderboard'/>
|
||||
<source path='shared'/>
|
||||
|
||||
+1
@@ -34,6 +34,7 @@
|
||||
<extend-property name="locale" values="de"/>
|
||||
<source path='client'/>
|
||||
<source path='raceboard'/>
|
||||
<source path='leaderboard'/>
|
||||
<source path='adminconsole'/>
|
||||
<source path='shared'/>
|
||||
</module>
|
||||
Reference in new issue
Block a user