diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/DomainFactoryImpl.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/DomainFactoryImpl.java index 9b7e4b3eae0..f9ce8195384 100755 --- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/DomainFactoryImpl.java +++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/DomainFactoryImpl.java @@ -76,14 +76,14 @@ public class DomainFactoryImpl implements DomainFactory { SAM007000 Men's Keelboat = Starboot Männer SAW010000 Women's Match Racing = Matchrace Damen Elliott 6M (modified) */ - olympicClassesByID.put("102", new BoatClassImpl("RS:X")); - olympicClassesByID.put("004", new BoatClassImpl("Laser")); - olympicClassesByID.put("103", new BoatClassImpl("Laser Radial")); - olympicClassesByID.put("002", new BoatClassImpl("Finn")); - olympicClassesByID.put("005", new BoatClassImpl("470")); - olympicClassesByID.put("009", new BoatClassImpl("49er")); - olympicClassesByID.put("007", new BoatClassImpl("Star")); - olympicClassesByID.put("010", new BoatClassImpl("Elliott 6M")); + olympicClassesByID.put("102", baseDomainFactory.getOrCreateBoatClass("RS:X")); + olympicClassesByID.put("004", baseDomainFactory.getOrCreateBoatClass("Laser")); + olympicClassesByID.put("103", baseDomainFactory.getOrCreateBoatClass("Laser Radial")); + olympicClassesByID.put("002", baseDomainFactory.getOrCreateBoatClass("Finn")); + olympicClassesByID.put("005", baseDomainFactory.getOrCreateBoatClass("470")); + olympicClassesByID.put("009", baseDomainFactory.getOrCreateBoatClass("49er")); + olympicClassesByID.put("007", baseDomainFactory.getOrCreateBoatClass("Star")); + olympicClassesByID.put("010", baseDomainFactory.getOrCreateBoatClass("Elliott 6M")); unknownBoatClass = new BoatClassImpl("Unknown"); } diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java index 1a3da0be561..596d1726db7 100644 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java @@ -27,7 +27,6 @@ import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.base.Team; import com.sap.sailing.domain.base.TimePoint; import com.sap.sailing.domain.base.Waypoint; -import com.sap.sailing.domain.base.impl.BoatClassImpl; import com.sap.sailing.domain.base.impl.BoatImpl; import com.sap.sailing.domain.base.impl.CompetitorImpl; import com.sap.sailing.domain.base.impl.CourseImpl; @@ -79,8 +78,6 @@ public class DomainFactoryImpl implements DomainFactory { private final Map teamCache = new HashMap(); - private final Map boatClassCache = new HashMap(); - /** * Caches events by their name and their boat class's name */ @@ -195,14 +192,7 @@ public class DomainFactoryImpl implements DomainFactory { @Override public BoatClass getOrCreateBoatClass(CompetitorClass competitorClass) { - synchronized (boatClassCache) { - BoatClass result = boatClassCache.get(competitorClass); - if (result == null) { - result = new BoatClassImpl(competitorClass == null ? "" : competitorClass.getName()); - boatClassCache.put(competitorClass, result); - } - return result; - } + return baseDomainFactory.getOrCreateBoatClass(competitorClass == null ? "" : competitorClass.getName()); } @Override diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/DomainFactory.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/DomainFactory.java index 3ac6ad87806..367fed0512c 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/DomainFactory.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/DomainFactory.java @@ -19,4 +19,6 @@ public interface DomainFactory { Waypoint createWaypoint(ControlPoint controlPoint); MarkPassing createMarkPassing(TimePoint timePoint, Waypoint waypoint, Competitor competitor); + + BoatClass getOrCreateBoatClass(String name); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/DomainFactoryImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/DomainFactoryImpl.java index b94e2ea29a3..82822a63b27 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/DomainFactoryImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/DomainFactoryImpl.java @@ -4,6 +4,7 @@ import java.awt.TrayIcon.MessageType; import java.util.HashMap; import java.util.Map; +import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Buoy; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.ControlPoint; @@ -23,10 +24,13 @@ public class DomainFactoryImpl implements DomainFactory { private final Map nationalityCache; private final Map buoyCache; + + private final Map boatClassCache; public DomainFactoryImpl() { nationalityCache = new HashMap(); buoyCache = new HashMap(); + boatClassCache = new HashMap(); } @Override @@ -71,4 +75,16 @@ public class DomainFactoryImpl implements DomainFactory { return new MarkPassingImpl(timePoint, waypoint, competitor); } + @Override + public BoatClass getOrCreateBoatClass(String name) { + synchronized (boatClassCache) { + BoatClass result = boatClassCache.get(name); + if (result == null) { + result = new BoatClassImpl(name); + boatClassCache.put(name, result); + } + return result; + } + } + } diff --git a/java/com.sap.sailing.gwt.ui.test/GwtTestCaseColumnToggling (proxy).launch b/java/com.sap.sailing.gwt.ui.test/GwtTestCaseColumnToggling (proxy).launch new file mode 100755 index 00000000000..e7af0c187ca --- /dev/null +++ b/java/com.sap.sailing.gwt.ui.test/GwtTestCaseColumnToggling (proxy).launch @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/TestColumnSwapping.java b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/TestColumnSwapping.java index 644250f9d31..cf5ee2cd3d4 100755 --- a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/TestColumnSwapping.java +++ b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/TestColumnSwapping.java @@ -119,8 +119,8 @@ public class TestColumnSwapping { } // check if leaderboardDAO an dleaderboardOriginalDAO same - List leaderboardList = leaderboardDAO.getRaceList(); - List leaderboardOriginalList = leaderboardOriginalDAO.getRaceList(); + List leaderboardList = leaderboardDAO.getRaceColumnNameList(); + List leaderboardOriginalList = leaderboardOriginalDAO.getRaceColumnNameList(); // ??????? assert races in list assertArrayEquals(leaderboardList.toArray(), leaderboardOriginalList.toArray()); diff --git a/java/com.sap.sailing.gwt.ui/.classpath b/java/com.sap.sailing.gwt.ui/.classpath index 1d9a1d84c13..d263fb7fd6c 100755 --- a/java/com.sap.sailing.gwt.ui/.classpath +++ b/java/com.sap.sailing.gwt.ui/.classpath @@ -6,5 +6,10 @@ + + + + + diff --git a/java/com.sap.sailing.gwt.ui/.settings/com.google.gdt.eclipse.core.prefs b/java/com.sap.sailing.gwt.ui/.settings/com.google.gdt.eclipse.core.prefs old mode 100755 new mode 100644 index 9ebb268ed2a..1421a949da3 --- a/java/com.sap.sailing.gwt.ui/.settings/com.google.gdt.eclipse.core.prefs +++ b/java/com.sap.sailing.gwt.ui/.settings/com.google.gdt.eclipse.core.prefs @@ -1,7 +1,7 @@ -#Wed Nov 23 14:14:33 CET 2011 +#Tue Nov 29 17:19:34 CET 2011 eclipse.preferences.version=1 jarsExcludedFromWebInfLib= -lastWarOutDir=C\:/Users/d056995/git/git/java/com.sap.sailing.gwt.ui/war +lastWarOutDir=C\:/Users/d056866/git/git/java/com.sap.sailing.gwt.ui/war launchConfigExternalUrlPrefix= warSrcDir=war warSrcDirIsOutput=false diff --git a/java/com.sap.sailing.gwt.ui/.settings/com.google.gwt.eclipse.core.prefs b/java/com.sap.sailing.gwt.ui/.settings/com.google.gwt.eclipse.core.prefs index 5780ec25b32..3efb764dcb4 100755 --- a/java/com.sap.sailing.gwt.ui/.settings/com.google.gwt.eclipse.core.prefs +++ b/java/com.sap.sailing.gwt.ui/.settings/com.google.gwt.eclipse.core.prefs @@ -1,5 +1,5 @@ -#Tue Nov 22 16:14:08 CET 2011 +#Tue Nov 29 17:28:42 CET 2011 eclipse.preferences.version=1 entryPointModules= filesCopiedToWebInfLib=gwt-servlet.jar -gwtCompileSettings=PGd3dC1jb21waWxlLXNldHRpbmdzPjxsb2ctbGV2ZWw+SU5GTzwvbG9nLWxldmVsPjxvdXRwdXQtc3R5bGU+T0JGVVNDQVRFRDwvb3V0cHV0LXN0eWxlPjxleHRyYS1hcmdzPjwhW0NEQVRBW11dPjwvZXh0cmEtYXJncz48dm0tYXJncz48IVtDREFUQVstWG14NTEybV1dPjwvdm0tYXJncz48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuTGVhZGVyYm9hcmQ8L2VudHJ5LXBvaW50LW1vZHVsZT48L2d3dC1jb21waWxlLXNldHRpbmdzPg\=\= +gwtCompileSettings=PGd3dC1jb21waWxlLXNldHRpbmdzPjxsb2ctbGV2ZWw+SU5GTzwvbG9nLWxldmVsPjxvdXRwdXQtc3R5bGU+T0JGVVNDQVRFRDwvb3V0cHV0LXN0eWxlPjxleHRyYS1hcmdzPjwhW0NEQVRBW11dPjwvZXh0cmEtYXJncz48dm0tYXJncz48IVtDREFUQVstWG14NTEybV1dPjwvdm0tYXJncz48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuQWRtaW5Db25zb2xlPC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLkxlYWRlcmJvYXJkPC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLkxlYWRlcmJvYXJkRWRpdGluZzwvZW50cnktcG9pbnQtbW9kdWxlPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmd3dC51aS5Vc2VyTWFuYWdlbWVudDwvZW50cnktcG9pbnQtbW9kdWxlPjwvZ3d0LWNvbXBpbGUtc2V0dGluZ3M+ diff --git a/java/com.sap.sailing.gwt.ui/SailingGWT.launch b/java/com.sap.sailing.gwt.ui/SailingGWT.launch index 0c521c018d6..593290c76f9 100755 --- a/java/com.sap.sailing.gwt.ui/SailingGWT.launch +++ b/java/com.sap.sailing.gwt.ui/SailingGWT.launch @@ -3,12 +3,6 @@ - - - - - - @@ -21,7 +15,7 @@ - + diff --git a/java/com.sap.sailing.gwt.ui/pom.xml b/java/com.sap.sailing.gwt.ui/pom.xml index e81416c4aca..5b373f3bd3e 100644 --- a/java/com.sap.sailing.gwt.ui/pom.xml +++ b/java/com.sap.sailing.gwt.ui/pom.xml @@ -39,6 +39,13 @@ 1.1.0 provided + + + com.google.code + gwt-visualization + 1.1.0 + provided + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/CompareCompetitorsChartDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/CompareCompetitorsChartDialog.java new file mode 100644 index 00000000000..ddab0bb76d5 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/CompareCompetitorsChartDialog.java @@ -0,0 +1,73 @@ +package com.sap.sailing.gwt.ui.client; + +import java.util.List; + +import com.google.gwt.dom.client.EventTarget; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.ui.Anchor; +import com.google.gwt.user.client.ui.DialogBox; +import com.google.gwt.user.client.ui.FlexTable; +import com.google.gwt.user.client.ui.HTML; +import com.google.gwt.user.client.ui.HasHorizontalAlignment; +import com.sap.sailing.gwt.ui.client.CompareCompetitorsPanel.DataLoadedEvent; +import com.sap.sailing.gwt.ui.client.CompareCompetitorsPanel.DataLoadedHandler; +import com.sap.sailing.gwt.ui.shared.CompetitorDAO; +import com.sap.sailing.gwt.ui.shared.RaceIdentifier; + +public class CompareCompetitorsChartDialog extends DialogBox { + private Anchor closeAnchor; + + public CompareCompetitorsChartDialog(SailingServiceAsync sailingService, List competitors, RaceIdentifier[] races, StringConstants stringConstants){ + super(true); + CompareCompetitorsPanel ccp = new CompareCompetitorsPanel(sailingService, competitors, races, stringConstants, (int) (Window.getClientWidth()-300), (int) (Window.getClientHeight()-200)); + ccp.addDataLoadedHandler(new DataLoadedHandler() { + + @Override + public void onDataLoaded(DataLoadedEvent event) { + CompareCompetitorsChartDialog.this.setPopupPosition(5, 5); + //CompareCompetitorsChartDialog.this.setSize((int) (Window.getClientWidth()*0.9) + "px", (int) (Window.getClientHeight() * 0.9) + "px"); + CompareCompetitorsChartDialog.this.show(); + } + }); + this.add(ccp); + + this.setPopupPosition(5, 5); + //this.setSize((int) (Window.getClientWidth()*0.9) + "px", (int) (Window.getClientHeight() * 0.9) + "px"); + closeAnchor = new Anchor("x"); + + FlexTable captionLayoutTable = new FlexTable(); + captionLayoutTable.setWidth("100%"); + captionLayoutTable.setText(0, 0, stringConstants.compareCompetitors()); + captionLayoutTable.setWidget(0, 1, closeAnchor); + captionLayoutTable.getCellFormatter().setHorizontalAlignment(0, 1,HasHorizontalAlignment.ALIGN_RIGHT); + + HTML caption = (HTML) getCaption(); + caption.getElement().appendChild(captionLayoutTable.getElement()); + + caption.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + EventTarget target = event.getNativeEvent().getEventTarget(); + Element targetElement = (Element) target.cast(); + + if (targetElement == closeAnchor.getElement()) { + closeAnchor.fireEvent(event); + } + } + }); + addCloseHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + hide(); + } + }); + + } + + public void addCloseHandler(ClickHandler handler) { + closeAnchor.addClickHandler(handler); + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/CompareCompetitorsPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/CompareCompetitorsPanel.java new file mode 100644 index 00000000000..26ad9a324ec --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/CompareCompetitorsPanel.java @@ -0,0 +1,347 @@ +package com.sap.sailing.gwt.ui.client; + +import java.util.List; + +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.shared.GwtEvent; +import com.google.gwt.safehtml.shared.SafeHtmlBuilder; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.AbsolutePanel; +import com.google.gwt.user.client.ui.Anchor; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.CaptionPanel; +import com.google.gwt.user.client.ui.DeckPanel; +import com.google.gwt.user.client.ui.FormPanel; +import com.google.gwt.user.client.ui.HasHorizontalAlignment; +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.RadioButton; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.VerticalPanel; +import com.google.gwt.visualization.client.AbstractDataTable; +import com.google.gwt.visualization.client.AbstractDataTable.ColumnType; +import com.google.gwt.visualization.client.DataTable; +import com.google.gwt.visualization.client.VisualizationUtils; +import com.google.gwt.visualization.client.visualizations.corechart.AxisOptions; +import com.google.gwt.visualization.client.visualizations.corechart.LineChart; +import com.google.gwt.visualization.client.visualizations.corechart.Options; +import com.sap.sailing.gwt.ui.shared.CompetitorDAO; +import com.sap.sailing.gwt.ui.shared.CompetitorWithRaceDAO; +import com.sap.sailing.gwt.ui.shared.RaceIdentifier; + +public class CompareCompetitorsPanel extends FormPanel { + private CompetitorWithRaceDAO[][] chartData = null; + private LineChart chart; + private final SailingServiceAsync sailingService; + private HorizontalPanel mainPanel; + private VerticalPanel chartPanel; + private final DeckPanel deckPanel; + private final RaceIdentifier[] races; + private int selectedRace = 0; + private int stepsToLoad = 100; + private final StringConstants stringConstants; + private boolean chartLoaded = false; + private boolean dataLoaded = false; + private int chartWidth; + private int chartHeight; + + public static final int DECK_PANEL_INDEX_LOADING = 0; + public static final int DECK_PANEL_INDEX_CHART = 1; + + public static final int SHOW_CURRENT_SPEED_OVER_GROUND = 0; + public static final int SHOW_VELOCITY_MADE_GOOD = 1; + public static final int SHOW_GAP_TO_LEADER = 2; + public static final int SHOW_WINDWARD_DISTANCE_TO_GO = 3; + public static final int SHOW_DISTANCE_TRAVELED = 4; + private int dataToShow = SHOW_CURRENT_SPEED_OVER_GROUND; + private AbsolutePanel loadingPanel; + + public CompareCompetitorsPanel(SailingServiceAsync sailingService, final List competitors, + RaceIdentifier[] races, StringConstants stringConstants, int chartWidth, int chartHeight) { + this.sailingService = sailingService; + this.races = races; + this.stringConstants = stringConstants; + this.chartWidth = chartWidth; + this.chartHeight = chartHeight; + mainPanel = new HorizontalPanel(); + mainPanel.setSpacing(5); + chartPanel = new VerticalPanel(); + HorizontalPanel raceChooserPanel = new HorizontalPanel(); + raceChooserPanel.setSpacing(5); + for (int i = 0; i < races.length; i++){ + RadioButton r = new RadioButton("chooseRace"); + r.setText(races[i].toString()); + raceChooserPanel.add(r); + if (i == 0){ + r.setValue(true); + } + final int index = i; + r.addClickHandler(new ClickHandler() { + + @Override + public void onClick(ClickEvent event) { + selectedRace = index; + loadData(); + } + }); + } + chartPanel.add(raceChooserPanel); + + loadingPanel = new AbsolutePanel (); + loadingPanel.setSize(chartWidth + "px", chartHeight + "px"); + + Anchor a = new Anchor(new SafeHtmlBuilder().appendHtmlConstant( + "").toSafeHtml()); + loadingPanel.add(a,chartWidth/2-32/2,chartHeight/2-32-2); + chartPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT); + chartPanel.setSpacing(5); + deckPanel = new DeckPanel(); + + deckPanel.add(loadingPanel); + final CaptionPanel configCaption = new CaptionPanel(stringConstants.configuration()); + configCaption.setHeight("100%"); + configCaption.setVisible(false); + VerticalPanel configPanel = new VerticalPanel(); + configCaption.setContentWidget(configPanel); + configPanel.setSpacing(5); + + Label lblChart = new Label(stringConstants.chooseChart()); + configPanel.add(lblChart); + final ListBox dataSelection = new ListBox(); + dataSelection.addItem(stringConstants.speedOverGroundLong(), "" + SHOW_CURRENT_SPEED_OVER_GROUND); + dataSelection.addItem(stringConstants.distanceTraveled(), "" + SHOW_DISTANCE_TRAVELED); + dataSelection.addItem(stringConstants.velocityMadeGoodLong(), "" + SHOW_VELOCITY_MADE_GOOD); + dataSelection.addItem(stringConstants.gapToLeaderLong(), "" + SHOW_GAP_TO_LEADER); + dataSelection.addItem(stringConstants.windwardDistanceToGoInMeters(), "" + SHOW_WINDWARD_DISTANCE_TO_GO); + dataSelection.addChangeHandler(new ChangeHandler() { + + @Override + public void onChange(ChangeEvent event) { + dataToShow = Integer.parseInt(dataSelection.getValue(dataSelection.getSelectedIndex())); + if (chart != null) { + chart.draw(prepareTableData(), getOptions()); + } + } + }); + configPanel.add(dataSelection); + Label lblSteps = new Label("Points to load:"); + configPanel.add(lblSteps); + final TextBox txtbSteps = new TextBox(); + txtbSteps.setText("" + stepsToLoad); + configPanel.add(txtbSteps); + Button bttSteps = new Button(stringConstants.refresh()); + bttSteps.addClickHandler(new ClickHandler() { + + @Override + public void onClick(ClickEvent event) { + stepsToLoad = Integer.parseInt(txtbSteps.getText()); + loadData(); + } + }); + configPanel.add(bttSteps); + + final Runnable onLoadCallback = new Runnable() { + + @Override + public void run() { + chart = new LineChart(prepareTableData(), getOptions()); + deckPanel.add(chart); + if (chartLoaded && dataLoaded){ + deckPanel.showWidget(DECK_PANEL_INDEX_CHART); + } + chartLoaded = true; + fireEvent(new DataLoadedEvent()); + + } + }; + VisualizationUtils.loadVisualizationApi(onLoadCallback, LineChart.PACKAGE); + loadData(); + chartPanel.add(deckPanel); + mainPanel.add(chartPanel); + Anchor showConfigAnchor = new Anchor(new SafeHtmlBuilder().appendHtmlConstant( + "").toSafeHtml()); + showConfigAnchor.setTitle(stringConstants.configuration()); + showConfigAnchor.addClickHandler(new ClickHandler() { + + @Override + public void onClick(ClickEvent event) { + configCaption.setVisible(!configCaption.isVisible()); + } + }); + mainPanel.add(showConfigAnchor); + mainPanel.add(configCaption); + this.add(mainPanel); + } + + private Options getOptions() { + Options opt = Options.create(); + opt.setWidth(chartWidth); + opt.setHeight(chartHeight); + switch (dataToShow) { + case SHOW_VELOCITY_MADE_GOOD: + opt.setTitle(stringConstants.velocityMadeGoodLong()); + break; + case SHOW_GAP_TO_LEADER: + opt.setTitle(stringConstants.gapToLeaderLong()); + break; + case SHOW_WINDWARD_DISTANCE_TO_GO: + opt.setTitle(stringConstants.windwardDistanceToGoInMeters()); + break; + case SHOW_DISTANCE_TRAVELED: + opt.setTitle(stringConstants.distanceTraveled()); + break; + default: + opt.setTitle(stringConstants.speedOverGroundLong()); + } + AxisOptions hAxisOptions = AxisOptions.create(); + hAxisOptions.setTitle("time"); + opt.setHAxisOptions(hAxisOptions); + + AxisOptions vAxisOptions = AxisOptions.create(); + switch (dataToShow) { + case SHOW_VELOCITY_MADE_GOOD: + vAxisOptions.setTitle(stringConstants.speed() + " " + stringConstants.in() + " " + stringConstants.velocityMadeGoodInKnotsUnit()); + break; + case SHOW_GAP_TO_LEADER: + vAxisOptions.setTitle(stringConstants.time() + " " + stringConstants.in() + " " + stringConstants.secondsUnit()); + break; + case SHOW_WINDWARD_DISTANCE_TO_GO: + vAxisOptions.setTitle(stringConstants.distance() + " " + stringConstants.in() + " " + stringConstants.metersUnit()); + break; + case SHOW_DISTANCE_TRAVELED: + vAxisOptions.setTitle(stringConstants.distance() + " " + stringConstants.in() + " " + stringConstants.metersUnit()); + break; + default: + vAxisOptions.setTitle(stringConstants.speed() + " " + stringConstants.in() + " " + stringConstants.currentSpeedOverGroundInKnotsUnit()); + break; + } + opt.setVAxisOptions(vAxisOptions); + return opt; + } + + private void loadData(){ + deckPanel.showWidget(DECK_PANEL_INDEX_LOADING); + dataLoaded = false; + this.sailingService.getCompetitorRaceData(races[selectedRace], stepsToLoad, + new AsyncCallback() { + + @Override + public void onFailure(Throwable caught) { + Window.alert(stringConstants.failedToLoadRaceData()); + } + + @Override + public void onSuccess(CompetitorWithRaceDAO[][] result) { + fireEvent(new DataLoadedEvent()); + chartData = result; + dataLoaded = true; + if (chartLoaded && dataLoaded){ + deckPanel.showWidget(DECK_PANEL_INDEX_CHART); + chart.draw(prepareTableData(), getOptions()); + } + } + }); + } + + private AbstractDataTable prepareTableData() { + DataTable data = DataTable.create(); + data.addColumn(ColumnType.STRING, stringConstants.time()); + + + if (chartData == null) { + return data; + } + if (chartData[0] != null) { + for (int i = 0; i < chartData.length; i++) { + data.addColumn(ColumnType.NUMBER, chartData[i][0].getCompetitor().name); + } + int length = 0; + for (int i = 0; i < chartData.length; i++) { + length = (length < chartData[i].length) ? chartData[i].length : length; + } + data.addRows(length); + long startTime = chartData[0][0].getStartTime(); + for (int n = 0; n < chartData[0].length; n++) { + long time = chartData[0][n].getLegEntry().timeInMilliseconds - startTime; + String minutes = "" + Math.abs((time/60000)); + if (minutes.length() < 2){ + minutes = ((time < 0)? "-" : "") +"0" + minutes; + } + String seconds = "" + Math.abs((time/1000)%60); + if (seconds.length() < 2){ + seconds= "0" + seconds; + } + data.setValue(n, 0, minutes + ":" + seconds); + } + for (int i = 0; i < chartData.length; i++) { + double distanceTraveledOnPreviousLegs = 0; + double lastTraveledDistance = 0; + for (int j = 0; j < chartData[i].length; j++) { + Double value = null; + switch (dataToShow) { + case SHOW_GAP_TO_LEADER: + value = chartData[i][j].getLegEntry().gapToLeaderInSeconds; + break; + case SHOW_VELOCITY_MADE_GOOD: + value = chartData[i][j].getLegEntry().velocityMadeGoodInKnots; + break; + case SHOW_WINDWARD_DISTANCE_TO_GO: + value = chartData[i][j].getLegEntry().windwardDistanceToGoInMeters; + break; + case SHOW_DISTANCE_TRAVELED: + value = chartData[i][j].getLegEntry().distanceTraveledInMeters; + if (value != null){ + if (lastTraveledDistance > value){ + distanceTraveledOnPreviousLegs += lastTraveledDistance; + } + lastTraveledDistance = value; + value += distanceTraveledOnPreviousLegs; + } + break; + default: + value = chartData[i][j].getLegEntry().currentSpeedOverGroundInKnots; + } + if (value != null) { + data.setValue(j, (i + 1), value); + } + } + } + } + + return data; + } + + // DataLoaded event handling. + public void addDataLoadedHandler(DataLoadedHandler handler) { + this.addHandler(handler, DataLoadedEvent.TYPE); + } + + interface DataLoadedHandler extends com.google.gwt.event.shared.EventHandler { + public void onDataLoaded(DataLoadedEvent event); + } + + public static class DataLoadedEvent extends GwtEvent { + public static Type TYPE = new Type(); + + public DataLoadedEvent() { + super(); + } + + @Override + protected void dispatch(DataLoadedHandler handler) { + handler.onDataLoaded(this); + } + + @Override + public com.google.gwt.event.shared.GwtEvent.Type getAssociatedType() { + return TYPE; + } + + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/CreateSwissTimingRacePanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/CreateSwissTimingRacePanel.java index f84760498e3..dc3e6d80e95 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/CreateSwissTimingRacePanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/CreateSwissTimingRacePanel.java @@ -37,7 +37,7 @@ public class CreateSwissTimingRacePanel extends FormPanel { private final SailingServiceAsync service; private ErrorReporter errorReporter; - public CreateSwissTimingRacePanel(final SailingServiceAsync sailingService, ErrorReporter errorReporter, StringConstants stringConstants){ + public CreateSwissTimingRacePanel(final SailingServiceAsync sailingService, ErrorReporter errorReporter, final StringConstants stringConstants){ this.service = sailingService; this.errorReporter = errorReporter; competitors = new ArrayList(); @@ -55,23 +55,23 @@ public class CreateSwissTimingRacePanel extends FormPanel { mainGrid.setWidget(0, 0, raceDataPanel); Grid grid = new Grid(2,2); raceDataPanel.add(grid); - Label lblRaceName = new Label("Race name:"); + Label lblRaceName = new Label(stringConstants.race() + " " + stringConstants.name() + ":"); grid.setWidget(0, 0, lblRaceName); txtbRaceName = new TextBox(); grid.setWidget(0, 1, txtbRaceName); - Label lblRaceDesc = new Label("Race description:"); + Label lblRaceDesc = new Label(stringConstants.race() + " " + stringConstants.description()+":"); grid.setWidget(1, 0, lblRaceDesc); txtbRaceDesc = new TextBox(); grid.setWidget(1, 1, txtbRaceDesc); //Competitor panel - CaptionPanel competitorPanel = new CaptionPanel("Competitors"); + CaptionPanel competitorPanel = new CaptionPanel(stringConstants.competitor()); competitorPanel.setSize("90%", "90%"); mainGrid.setWidget(1, 0, competitorPanel); grid = new Grid(3,3); competitorPanel.add(grid); - Label lblCompetitorListTitle = new Label("Competitors:"); + Label lblCompetitorListTitle = new Label(stringConstants.competitor()); grid.setWidget(0, 0, lblCompetitorListTitle); listbCompetitorList = new ListBox(false); listbCompetitorList.setVisibleItemCount(10); @@ -89,7 +89,7 @@ public class CreateSwissTimingRacePanel extends FormPanel { grid.setWidget(1, 1, compData); Grid subGrid = new Grid(3,2); compData.add(subGrid); - Label lblName = new Label("Name:"); + Label lblName = new Label(stringConstants.name() + ":"); subGrid.setWidget(0, 0, lblName); txtbCompName = new TextBox(); txtbCompName.addValueChangeHandler(new ValueChangeHandler() { @@ -100,7 +100,7 @@ public class CreateSwissTimingRacePanel extends FormPanel { } }); subGrid.setWidget(0, 1, txtbCompName); - Label lblSailNr = new Label("Sail number:"); + Label lblSailNr = new Label(stringConstants.sailNumber()+":"); subGrid.setWidget(1, 0, lblSailNr); txtbCompSailNr = new TextBox(); txtbCompSailNr.addValueChangeHandler(new ValueChangeHandler() { @@ -111,14 +111,14 @@ public class CreateSwissTimingRacePanel extends FormPanel { } }); subGrid.setWidget(1, 1, txtbCompSailNr); - Label lblCountr = new Label("Country:"); + Label lblCountr = new Label(stringConstants.country()+":"); subGrid.setWidget(2, 0, lblCountr); suggestionsCompCountr = new MultiWordSuggestOracle(); service.getCountryCodes(new AsyncCallback() { @Override public void onFailure(Throwable caught) { - CreateSwissTimingRacePanel.this.errorReporter.reportError("Unable to find the IOC 3-letter-codes."); + CreateSwissTimingRacePanel.this.errorReporter.reportError(stringConstants.no3LetterCodes()); } @Override @@ -141,7 +141,7 @@ public class CreateSwissTimingRacePanel extends FormPanel { HorizontalPanel horizontalPanel = new HorizontalPanel(); grid.setWidget(2, 0, horizontalPanel); - Button bttAddCompetitor = new Button("Add"); + Button bttAddCompetitor = new Button(stringConstants.add()); bttAddCompetitor.setWidth("100px"); bttAddCompetitor.addClickHandler(new ClickHandler() { @@ -152,7 +152,7 @@ public class CreateSwissTimingRacePanel extends FormPanel { }); horizontalPanel.add(bttAddCompetitor); - Button bttDeleteCompetitor = new Button("Delete"); + Button bttDeleteCompetitor = new Button(stringConstants.delete()); bttDeleteCompetitor.setWidth("100px"); bttDeleteCompetitor.addClickHandler(new ClickHandler() { @@ -163,7 +163,7 @@ public class CreateSwissTimingRacePanel extends FormPanel { }); horizontalPanel.add(bttDeleteCompetitor); - Button bttAddRace = new Button("Add race"); + Button bttAddRace = new Button(stringConstants.add() + " " + stringConstants.race()); bttAddRace.addClickHandler(new ClickHandler() { @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/LeaderboardConfigPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/LeaderboardConfigPanel.java old mode 100644 new mode 100755 index 167dab1ffd8..e12ea3357b4 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/LeaderboardConfigPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/LeaderboardConfigPanel.java @@ -618,7 +618,7 @@ public class LeaderboardConfigPanel extends FormPanel implements EventDisplayer, selectedLeaderboard = result; raceColumnList.getList().clear(); - for (String race : result.getRaceList()) + for(String race: result.getRaceColumnNameList()) raceColumnList.getList().add(race); selectedLeaderBoardPanel.setVisible(true); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/LeaderboardPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/LeaderboardPanel.java index 120d58d4f55..b6d1ac429ec 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/LeaderboardPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/LeaderboardPanel.java @@ -37,10 +37,14 @@ import com.google.gwt.view.client.ListDataProvider; import com.google.gwt.view.client.MultiSelectionModel; import com.sap.sailing.gwt.ui.client.DataEntryDialog.Validator; import com.sap.sailing.gwt.ui.client.LegDetailColumn.LegDetailField; +import com.sap.sailing.gwt.ui.shared.CompetitorDAO; import com.sap.sailing.gwt.ui.shared.LeaderboardDAO; import com.sap.sailing.gwt.ui.shared.LeaderboardEntryDAO; +import com.sap.sailing.gwt.ui.shared.LeaderboardNameAndRaceColumnName; import com.sap.sailing.gwt.ui.shared.LeaderboardRowDAO; import com.sap.sailing.gwt.ui.shared.LegEntryDAO; +import com.sap.sailing.gwt.ui.shared.RaceIdentifier; +import com.sap.sailing.gwt.ui.shared.RaceInLeaderboardDAO; /** * A leaderboard essentially consists of a table widget that in its columns displays the entries. @@ -69,6 +73,8 @@ public class LeaderboardPanel extends FormPanel implements TimeListener, PlaySta private final StringConstants stringConstants; private final CellTable leaderboardTable; + + private final MultiSelectionModel leaderboardSelectionModel; private ListDataProvider data; @@ -121,7 +127,7 @@ public class LeaderboardPanel extends FormPanel implements TimeListener, PlaySta public void onClick(ClickEvent event) { new LeaderboardSettingsPanel(Collections.unmodifiableList(selectedLegDetails), Collections.unmodifiableList(selectedRaceDetails), /* All races to select */ - leaderboard.getRaceList(), selectedRaceColumns, timer.getDelayBetweenAutoAdvancesInMilliseconds(), + leaderboard.getRaceColumnNameList(), selectedRaceColumns, timer.getDelayBetweenAutoAdvancesInMilliseconds(), stringConstants.leaderboardSettings(), stringConstants.selectLegDetails(), stringConstants.ok(), stringConstants.cancel(), new Validator() { @Override @@ -732,7 +738,8 @@ public class LeaderboardPanel extends FormPanel implements TimeListener, PlaySta leaderboardTable = new CellTableWithStylableHeaders( /* pageSize */100, resources); getLeaderboardTable().setWidth("100%"); - getLeaderboardTable().setSelectionModel(new MultiSelectionModel() {}); + leaderboardSelectionModel = new MultiSelectionModel() {}; + getLeaderboardTable().setSelectionModel(leaderboardSelectionModel); setData(new ListDataProvider()); getData().addDataDisplay(getLeaderboardTable()); listHandler = new ListHandler(getData().getList()); @@ -773,10 +780,21 @@ public class LeaderboardPanel extends FormPanel implements TimeListener, PlaySta playPause.addClickHandler(playPauseHandler); playStateChanged(timer.isPlaying()); refreshPanel.add(playPause); + Anchor chartsAnchor = new Anchor(new SafeHtmlBuilder().appendHtmlConstant( + "").toSafeHtml()); + chartsAnchor.setTitle(stringConstants.showCharts()); + chartsAnchor.addClickHandler(new ClickHandler() { + + @Override + public void onClick(ClickEvent event) { + compareCompetitors(); + } + }); Anchor settingsAnchor = new Anchor(new SafeHtmlBuilder().appendHtmlConstant( "").toSafeHtml()); settingsAnchor.setTitle(stringConstants.settings()); settingsAnchor.addClickHandler(new SettingsClickHandler(stringConstants)); + refreshAndSettingsPanel.add(chartsAnchor); refreshAndSettingsPanel.add(refreshPanel); refreshAndSettingsPanel.add(settingsAnchor); dockPanel02.add(refreshAndSettingsPanel, DockPanel.EAST); @@ -979,8 +997,8 @@ public class LeaderboardPanel extends FormPanel implements TimeListener, PlaySta private List getRacesAddedNew(LeaderboardDAO oldLeaderboard, LeaderboardDAO newLeaderboard){ List result = new ArrayList(); - for (String s : newLeaderboard.getRaceList()) { - if (oldLeaderboard == null || !oldLeaderboard.getRaceList().contains(s)) { + for (String s : newLeaderboard.getRaceColumnNameList()) { + if (oldLeaderboard == null || !oldLeaderboard.getRaceColumnNameList().contains(s)) { result.add(s); } } @@ -1114,7 +1132,7 @@ public class LeaderboardPanel extends FormPanel implements TimeListener, PlaySta private void createMissingAndAdjustExistingRaceColumns(LeaderboardDAO leaderboard) { // Correct order of races in selectedRaceColum List correctedOrderSelectedRaces = new ArrayList(); - for (String string : leaderboard.getRaceList()) { + for (String string : leaderboard.getRaceColumnNameList()) { if (selectedRaceColumns.contains(string)) { correctedOrderSelectedRaces.add(string); } @@ -1285,4 +1303,23 @@ public class LeaderboardPanel extends FormPanel implements TimeListener, PlaySta playPause.setHTML(getPlayPauseImgHtml(isPlaying)); playPause.setTitle(isPlaying ? stringConstants.pauseAutomaticRefresh() : stringConstants.autoRefresh()); } + + private void compareCompetitors(){ + List competitors = new ArrayList(); + List races = new ArrayList(); + for (RaceInLeaderboardDAO race : getLeaderboard().getRaceList()) { + races.add(new LeaderboardNameAndRaceColumnName(leaderboardName, race.getRaceColumnName())); + } + if (leaderboardSelectionModel.getSelectedSet().size() > 0){ + for (LeaderboardRowDAO leaderboardRowDAO : leaderboardSelectionModel.getSelectedSet()) { + competitors.add(leaderboardRowDAO.competitor); + } + } + else { + for (LeaderboardRowDAO leaderboardRowDAO : leaderboardTable.getVisibleItems()){ + competitors.add(leaderboardRowDAO.competitor); + } + } + new CompareCompetitorsChartDialog(sailingService, competitors, races.toArray(new LeaderboardNameAndRaceColumnName[0]), stringConstants); + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/RaceDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/RaceDialog.java index 751da75ce7c..d5cba3e03ca 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/RaceDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/RaceDialog.java @@ -12,8 +12,6 @@ public class RaceDialog extends DataEntryDialog>{ private final TextBox raceNameBox; private final CheckBox isMedalRace; - private final StringConstants stringConstants; - private Pair raceDaoAndIsMedalRace; private static class RaceDialogValidator implements Validator>{ @@ -52,7 +50,6 @@ public class RaceDialog extends DataEntryDialog>{ raceNameBox = createTextBox(raceDaoAndIsMedalRace.getA()); isMedalRace = createCheckbox(stringConstants.medalRace()); isMedalRace.setValue(raceDaoAndIsMedalRace.getB().booleanValue()); - this.stringConstants = stringConstants; } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java index ee3dd515382..7f2d00d7898 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java @@ -8,6 +8,7 @@ import java.util.Map; import com.google.gwt.user.client.rpc.RemoteService; import com.google.gwt.user.client.rpc.RemoteServiceRelativePath; import com.sap.sailing.gwt.ui.shared.CompetitorDAO; +import com.sap.sailing.gwt.ui.shared.CompetitorWithRaceDAO; import com.sap.sailing.gwt.ui.shared.EventAndRaceIdentifier; import com.sap.sailing.gwt.ui.shared.EventDAO; import com.sap.sailing.gwt.ui.shared.EventIdentifier; @@ -131,6 +132,7 @@ public interface SailingService extends RemoteService { String[] getCountryCodes(); + CompetitorWithRaceDAO[][] getCompetitorRaceData(RaceIdentifier race, int steps) throws Exception; Map> getDouglasPoints(RaceIdentifier raceIdentifier, Map from, Map to, double meters); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java index 411549da2a6..aa848fab97e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java @@ -9,6 +9,7 @@ import com.google.gwt.user.client.rpc.AsyncCallback; import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.leaderboard.RaceInLeaderboard; import com.sap.sailing.gwt.ui.shared.CompetitorDAO; +import com.sap.sailing.gwt.ui.shared.CompetitorWithRaceDAO; import com.sap.sailing.gwt.ui.shared.EventAndRaceIdentifier; import com.sap.sailing.gwt.ui.shared.EventDAO; import com.sap.sailing.gwt.ui.shared.GPSFixDAO; @@ -178,6 +179,7 @@ public interface SailingServiceAsync { void getCountryCodes(AsyncCallback callback); + void getCompetitorRaceData(RaceIdentifier race, int steps, AsyncCallback callback); void getDouglasPoints(RaceIdentifier raceIdentifier, Map from, Map to, double meters, AsyncCallback>> callback); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringConstants.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringConstants.java old mode 100644 new mode 100755 index e74d2f28f09..e9dac237199 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringConstants.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringConstants.java @@ -128,4 +128,26 @@ public interface StringConstants extends Constants { String medalRaceIsNull(); String maneuverTypes(); String raceNameEmpty(); + String configuration(); + String chooseChart(); + String distanceTraveled(); + String velocityMadeGoodLong(); + String speedOverGroundLong(); + String gapToLeaderLong(); + String pointsToLoad(); + String speed(); + String distance(); + String in(); + String secondsUnit(); + String metersUnit(); + String failedToLoadRaceData(); + String close(); + String compareCompetitors(); + String description(); + String sailNumber(); + String country(); + String no3LetterCodes(); + String add(); + String delete(); + String showCharts(); } \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringConstants.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringConstants.properties index 49a9153aab4..b7eb8325e96 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringConstants.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringConstants.properties @@ -121,5 +121,27 @@ tacks=Tacks jibes=Jibes penaltyCircles=Penalty Circles medalRaceIsNull=Medalrace value not allowed +configuration=Configuration maneuverTypes=Maneuver types -raceNameEmpty=The name of the race is empty \ No newline at end of file +raceNameEmpty=The name of the race is empty +chooseChart=Choose chart +distanceTraveled=Distance Traveled +velocityMadeGoodLong=Velocity Made Good +speedOverGroundLong=Speed Over Ground +gapToLeaderLong=Gap To Leader +pointsToLoad=Points to load +speed=Speed +distance=Distance +in=in +secondsUnit=[s] +metersUnit=[m] +failedToLoadRaceData=Failed to laod race data. +close=Close +compareCompetitors=Compare competitors +description=description +sailNumber=Sail number +country=Country +no3LetterCodes=Unable to find the IOC 3-letter-codes. +add=Add +delete=Delete +showCharts=Show charts \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringConstants_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringConstants_de.properties index 532173797d0..d224b73dfb6 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringConstants_de.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringConstants_de.properties @@ -15,7 +15,7 @@ map=Map race=Race races=Races tracked=tracked -time=Time +time=Zeit acceleration=Acceleration accelerationHelp=Use "1" for regular play-back speed, "2" for double-speed playback and so on delay=Delay (s) @@ -122,4 +122,27 @@ jibes=Halsen penaltyCircles=Strafkringel medalRaceIsNull=Medialienwert nicht erlaubt maneuverTypes=Manövertypen -raceNameEmpty=Der Name des Rennens ist leer \ No newline at end of file +raceNameEmpty=Der Name des Rennens ist leer +configuration=Konfiguration +chooseChart=Diagramm wählen +raceNameEmpty=Rennname leer +distanceTraveled=Zurückgelegte Strecke +velocityMadeGoodLong=Velocity Made Good +speedOverGroundLong=Speed Over Ground +gapToLeaderLong=Abstand zum führenden Boot +pointsToLoad=Points to load +speed=Geschwindigkeit +distance=Strecke +in=in +secondsUnit=[s] +metersUnit=[m] +failedToLoadRaceData=Failed to laod race data. +close=Close +compareCompetitors=Kompetitoren vergleichen +description=Beschreibung +sailNumber=Segelnummer +country=Land +no3LetterCodes=IOC 3-Buchstaben-Codes können nicht gefunden werden. +add=Hinzufügen +delete=Löschen +showCharts=Grafische Ansicht \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 5379c5661db..138c5df2fd4 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -76,6 +76,7 @@ import com.sap.sailing.domain.tractracadapter.TracTracConfiguration; import com.sap.sailing.gwt.ui.client.SailingService; import com.sap.sailing.gwt.ui.shared.BoatClassDAO; import com.sap.sailing.gwt.ui.shared.CompetitorDAO; +import com.sap.sailing.gwt.ui.shared.CompetitorWithRaceDAO; import com.sap.sailing.gwt.ui.shared.EventAndRaceIdentifier; import com.sap.sailing.gwt.ui.shared.EventDAO; import com.sap.sailing.gwt.ui.shared.EventFetcher; @@ -1175,9 +1176,37 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS Collections.sort(countryCodes); return countryCodes.toArray(new String[0]); } - + @Override - public Map> getDouglasPoints(RaceIdentifier raceIdentifier, + public CompetitorWithRaceDAO[][] getCompetitorRaceData(RaceIdentifier race, int steps) throws NoWindException { + List competitorData; + TrackedRace trackedRace = getTrackedRace(race); + Iterable competitors = trackedRace.getRace().getCompetitors(); + + competitorData = new ArrayList(); + for (Competitor c : competitors){ + List entries = new ArrayList(); + for (long time = trackedRace.getStart().asMillis()-20000; time < trackedRace.getTimePointOfNewestEvent().asMillis(); time += (trackedRace.getTimePointOfNewestEvent().asMillis()-trackedRace.getStart().asMillis()-20000)/steps){ + MillisecondsTimePoint timePoint = new MillisecondsTimePoint(time); + CompetitorWithRaceDAO competitorWithRaceEntry = new CompetitorWithRaceDAO(); + competitorWithRaceEntry.setCompetitor(getCompetitorDAO(c)); + competitorWithRaceEntry.setStartTime(trackedRace.getStart().asMillis()); + if (trackedRace != null){ + LegEntryDAO legEntry = createLegEntry(trackedRace.getTrackedLeg(c, timePoint), timePoint); + if (legEntry == null){ + legEntry = new LegEntryDAO(); + } + legEntry.timeInMilliseconds = time; + competitorWithRaceEntry.setLegEntry(legEntry); + } + entries.add(competitorWithRaceEntry); + } + competitorData.add(entries.toArray(new CompetitorWithRaceDAO[0])); + } + return competitorData.toArray(new CompetitorWithRaceDAO[0][0]); + } + +public Map> getDouglasPoints(RaceIdentifier raceIdentifier, Map from, Map to, double meters) { Map> result = new HashMap>(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/CompetitorWithRaceDAO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/CompetitorWithRaceDAO.java new file mode 100644 index 00000000000..f074ab7d662 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/CompetitorWithRaceDAO.java @@ -0,0 +1,70 @@ +package com.sap.sailing.gwt.ui.shared; + +import com.google.gwt.user.client.rpc.IsSerializable; + +public class CompetitorWithRaceDAO implements IsSerializable { + private CompetitorDAO competitor; + private LegEntryDAO legEntry; + private long startTime; + + public long getStartTime() { + return startTime; + } + public void setStartTime(long startTime) { + this.startTime = startTime; + } + public CompetitorDAO getCompetitor() { + return competitor; + } + public void setCompetitor(CompetitorDAO competitor) { + this.competitor = competitor; + } + public LegEntryDAO getLegEntry() { + return legEntry; + } + public void setLegEntry(LegEntryDAO legEntry) { + this.legEntry = legEntry; + } + + /* Updates the legEntry. Only updates a value if the value of {@link: legEntry} is not 0. + * + * @param legEntry The LegEntryDAO providing the update information. + */ + public void updateLegEntry(LegEntryDAO legEntry){ + if (!this.legEntry.started & legEntry.started){ + this.legEntry.started = legEntry.started; + } + if (!this.legEntry.finished & legEntry.finished){ + this.legEntry.finished = legEntry.finished; + } + if (legEntry.averageSpeedOverGroundInKnots != 0){ + this.legEntry.averageSpeedOverGroundInKnots = legEntry.averageSpeedOverGroundInKnots; + } + if (legEntry.currentSpeedOverGroundInKnots != 0){ + this.legEntry.currentSpeedOverGroundInKnots = legEntry.currentSpeedOverGroundInKnots; + } + if (legEntry.distanceTraveledInMeters != 0){ + this.legEntry.distanceTraveledInMeters = legEntry.distanceTraveledInMeters; + } + if (legEntry.estimatedTimeToNextWaypointInSeconds != 0){ + this.legEntry.estimatedTimeToNextWaypointInSeconds = legEntry.estimatedTimeToNextWaypointInSeconds; + } + if (legEntry.gapToLeaderInSeconds != 0){ + this.legEntry.gapToLeaderInSeconds = legEntry.gapToLeaderInSeconds; + } + if (legEntry.rank != 0){ + this.legEntry.rank = legEntry.rank; + } + if (legEntry.timeInMilliseconds != 0){ + this.legEntry.timeInMilliseconds = legEntry.timeInMilliseconds; + } + if (legEntry.velocityMadeGoodInKnots != 0){ + this.legEntry.velocityMadeGoodInKnots = legEntry.velocityMadeGoodInKnots; + } + if (legEntry.windwardDistanceToGoInMeters != 0){ + this.legEntry.windwardDistanceToGoInMeters = legEntry.windwardDistanceToGoInMeters; + } + } + + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventNameAndRaceName.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventNameAndRaceName.java index b9272b52b74..5fe93cf0ec9 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventNameAndRaceName.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventNameAndRaceName.java @@ -34,4 +34,11 @@ public class EventNameAndRaceName implements EventAndRaceIdentifier { public Object getEvent(EventFetcher eventFetcher) { return eventFetcher.getEvent(this); } + + @Override + public String toString() { + return raceName; + } + + } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/LeaderboardDAO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/LeaderboardDAO.java index 36b1cf3fb32..cffeb5f7111 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/LeaderboardDAO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/LeaderboardDAO.java @@ -3,7 +3,6 @@ package com.sap.sailing.gwt.ui.shared; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; -import java.util.HashMap; import java.util.List; import java.util.Map; @@ -20,9 +19,7 @@ import com.google.gwt.user.client.rpc.IsSerializable; public class LeaderboardDAO implements IsSerializable { public String name; public List competitors; - private List raceNames; - private Map racesMedalRace; - private Map racesTracked; + private List races; public Map displayNames; public Map rows; public boolean hasCarriedPoints; @@ -35,9 +32,7 @@ public class LeaderboardDAO implements IsSerializable { public LeaderboardDAO() { totalRankingComparator = new TotalRankingComparator(); competitorsOrderedAccordingToTotalRank = false; - raceNames = new ArrayList(); - racesMedalRace = new HashMap(); - racesTracked = new HashMap(); + races = new ArrayList(); } public String getDisplayName(CompetitorDAO competitor) { @@ -76,8 +71,8 @@ public class LeaderboardDAO implements IsSerializable { */ public boolean scoredInMedalRace(CompetitorDAO competitor) { LeaderboardRowDAO row = rows.get(competitor); - for (String race : raceNames) { - if (raceIsMedalRace(race) && row.fieldsByRaceName.get(race).totalPoints > 0) { + for (RaceInLeaderboardDAO race : races) { + if (race.isMedalRace() && row.fieldsByRaceName.get(race.getRaceColumnName()).totalPoints > 0) { return true; } } @@ -189,9 +184,9 @@ public class LeaderboardDAO implements IsSerializable { private int getMedalRaceScore(CompetitorDAO competitor) { int result = 0; LeaderboardRowDAO row = rows.get(competitor); - for (String race : raceNames) { - if (raceIsMedalRace(race) && row.fieldsByRaceName.containsKey(race)) { - result += row.fieldsByRaceName.get(race).netPoints; + for (RaceInLeaderboardDAO race : races) { + if (race.isMedalRace() && row.fieldsByRaceName.containsKey(race.getRaceColumnName())) { + result += row.fieldsByRaceName.get(race.getRaceColumnName()).netPoints; } } return result; @@ -215,12 +210,12 @@ public class LeaderboardDAO implements IsSerializable { */ private String getNameOfLastRaceSoFar(CompetitorDAO c1, CompetitorDAO c2) { String nameOfLastRaceSoFar = null; - for (String race : raceNames) { + for (RaceInLeaderboardDAO race : races) { for (LeaderboardRowDAO row : rows.values()) { if (row.competitor.equals(c1) || row.competitor.equals(c2)) { - LeaderboardEntryDAO leaderboardEntryDAO = row.fieldsByRaceName.get(race); + LeaderboardEntryDAO leaderboardEntryDAO = row.fieldsByRaceName.get(race.getRaceColumnName()); if (leaderboardEntryDAO != null && leaderboardEntryDAO.netPoints != 0) { - nameOfLastRaceSoFar = race; + nameOfLastRaceSoFar = race.getRaceColumnName(); break; } } @@ -233,8 +228,8 @@ public class LeaderboardDAO implements IsSerializable { int result = 0; LeaderboardRowDAO row = rows.get(competitor); if (row != null) { - for (String race : raceNames) { - LeaderboardEntryDAO field = row.fieldsByRaceName.get(race); + for (RaceInLeaderboardDAO race : races) { + LeaderboardEntryDAO field = row.fieldsByRaceName.get(race.getRaceColumnName()); if (field != null && field.netPoints == 1) { result++; } @@ -256,81 +251,94 @@ public class LeaderboardDAO implements IsSerializable { return competitors.indexOf(competitor)+1; }; - public boolean raceIsTracked(String raceName){ - return racesTracked.get(raceName); + public boolean raceIsTracked(String raceColumnName){ + for (RaceInLeaderboardDAO race : races){ + if (race.getRaceColumnName().equals(raceColumnName)){ + return race.isTrackedRace(); + } + } + return false; } - public boolean raceIsMedalRace(String raceName){ - return racesMedalRace.get(raceName); + public boolean raceIsMedalRace(String raceColumnName){ + return getRaceInLeaderboardByName(raceColumnName).isMedalRace(); } - public void addRace(String name, boolean isMedalRace, boolean isTracked){ - raceNames.add(name); - racesMedalRace.put(name, isMedalRace); - racesTracked.put(name, isTracked); + public void addRace(String raceColumnName, boolean medalRace, boolean trackedRace){ + RaceInLeaderboardDAO raceInLeaderboardDAO = new RaceInLeaderboardDAO(); + raceInLeaderboardDAO.setRaceColumnName(raceColumnName); + raceInLeaderboardDAO.setMedalRace(medalRace); + raceInLeaderboardDAO.setTrackedRace(trackedRace); + races.add(raceInLeaderboardDAO); } - public void addRaceAt(String name, boolean isMedalRace, boolean isTracked, int index){ - raceNames.add(index, name); - racesMedalRace.put(name, isMedalRace); - racesTracked.put(name, isTracked); + public void addRaceAt(String raceColumnName, boolean medalRace, boolean trackedRace, int index){ + RaceInLeaderboardDAO raceInLeaderboardDAO = new RaceInLeaderboardDAO(); + raceInLeaderboardDAO.setRaceColumnName(raceColumnName); + raceInLeaderboardDAO.setMedalRace(medalRace); + raceInLeaderboardDAO.setTrackedRace(trackedRace); + races.add(index, raceInLeaderboardDAO); } - public void removeRace(String name){ - racesMedalRace.remove(name); - racesTracked.remove(name); - raceNames.remove(getRaceIdByName(name)); + public void removeRace(String raceColumnName){ + races.remove(getRaceInLeaderboardByName(raceColumnName)); } public void renameRace(String oldName, String newName){ - int index = getRaceIdByName(oldName); - racesMedalRace.put(newName, racesMedalRace.get(oldName)); - racesTracked.put(newName, racesTracked.get(oldName)); - racesMedalRace.remove(oldName); - racesTracked.remove(oldName); - raceNames.set(index, newName); + RaceInLeaderboardDAO race = getRaceInLeaderboardByName(oldName); + race.setRaceColumnName(newName); } - public List getRaceList(){ - return raceNames; - } - - public boolean raceListContains(String raceName) { - return getRaceIdByName(raceName) != -1; - } - - public int getRaceIdByName(String raceName) { - for (int i = 0; i < raceNames.size(); i++) { - if (raceNames.get(i).equals(raceName)) { - return i; + private RaceInLeaderboardDAO getRaceInLeaderboardByName(String raceColumnName) { + for (RaceInLeaderboardDAO race : races){ + if (race.getRaceColumnName().equals(raceColumnName)){ + return race; } } - return -1; + return null; } - public void moveRaceUp(String raceName) { - int index = getRaceIdByName(raceName); + public List getRaceColumnNameList(){ + List raceColumnNames = new ArrayList(); + for (RaceInLeaderboardDAO raceInLeaderboardDAO : races){ + raceColumnNames.add(raceInLeaderboardDAO.getRaceColumnName()); + } + return raceColumnNames; + } + + public List getRaceList(){ + return races; + } + + public boolean raceListContains(String raceColumnName) { + return getRaceInLeaderboardByName(raceColumnName) != null; + } + + public void moveRaceUp(String raceColumnName) { + RaceInLeaderboardDAO race = getRaceInLeaderboardByName(raceColumnName); + int index = races.indexOf(race); index--; if (index >= 0) { - raceNames.remove(index + 1); - raceNames.add(index, raceName); + races.remove(index + 1); + races.add(index, race); } } - public void moveRaceDown(String raceName) { - int index = getRaceIdByName(raceName); + public void moveRaceDown(String raceColumnName) { + RaceInLeaderboardDAO race = getRaceInLeaderboardByName(raceColumnName); + int index = races.indexOf(race); if (index != -1) { index++; - if (index < raceNames.size()) { - raceNames.remove(index - 1); - raceNames.add(index, raceName); + if (index < races.size()) { + races.remove(index - 1); + races.add(index, race); } } } - public void setIsMedalRace(String raceName, boolean isMedalRace){ - racesMedalRace.put(raceName, isMedalRace); + public void setIsMedalRace(String raceColumnName, boolean medalRace){ + getRaceInLeaderboardByName(raceColumnName).setMedalRace(medalRace); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/LeaderboardNameAndRaceColumnName.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/LeaderboardNameAndRaceColumnName.java index a7b368f8d92..816aeb307c8 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/LeaderboardNameAndRaceColumnName.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/LeaderboardNameAndRaceColumnName.java @@ -32,4 +32,11 @@ public class LeaderboardNameAndRaceColumnName implements RaceIdentifier { public Object getExistingTrackedRace(RaceFetcher raceFetcher) { return raceFetcher.getExistingTrackedRace(this); } + + @Override + public String toString() { + return raceColumnName; + } + + } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RaceInLeaderboardDAO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RaceInLeaderboardDAO.java new file mode 100644 index 00000000000..ba12c412b21 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RaceInLeaderboardDAO.java @@ -0,0 +1,29 @@ +package com.sap.sailing.gwt.ui.shared; + +import com.google.gwt.user.client.rpc.IsSerializable; + +public class RaceInLeaderboardDAO implements IsSerializable { + private String raceColumnName; + private boolean medalRace; + private boolean trackedRace; + public String getRaceColumnName() { + return raceColumnName; + } + public void setRaceColumnName(String raceColumnName) { + this.raceColumnName = raceColumnName; + } + public boolean isMedalRace() { + return medalRace; + } + public void setMedalRace(boolean medalRace) { + this.medalRace = medalRace; + } + public boolean isTrackedRace() { + return trackedRace; + } + public void setTrackedRace(boolean trackedRace) { + this.trackedRace = trackedRace; + } + + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/AdminConsole.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/AdminConsole.gwt.xml index 25033f410ed..6d0edd433c2 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/AdminConsole.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/AdminConsole.gwt.xml @@ -17,6 +17,9 @@ + + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/Leaderboard.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/Leaderboard.gwt.xml index b264218dc64..6012cdc2250 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/Leaderboard.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/Leaderboard.gwt.xml @@ -18,6 +18,9 @@ + + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/LeaderboardEditing.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/LeaderboardEditing.gwt.xml index da2c3e44569..d4066bed6ad 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/LeaderboardEditing.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/LeaderboardEditing.gwt.xml @@ -17,6 +17,9 @@ + + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/UserManagement.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/UserManagement.gwt.xml index e40f0a4a0ec..bd7a5916b7c 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/UserManagement.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/UserManagement.gwt.xml @@ -17,6 +17,9 @@ + + + diff --git a/java/com.sap.sailing.gwt.ui/war/images/ajax-loader.gif b/java/com.sap.sailing.gwt.ui/war/images/ajax-loader.gif new file mode 100644 index 00000000000..3288d1035d7 Binary files /dev/null and b/java/com.sap.sailing.gwt.ui/war/images/ajax-loader.gif differ diff --git a/java/com.sap.sailing.gwt.ui/war/images/chart_small.png b/java/com.sap.sailing.gwt.ui/war/images/chart_small.png new file mode 100644 index 00000000000..ca61a429bee Binary files /dev/null and b/java/com.sap.sailing.gwt.ui/war/images/chart_small.png differ