VerticalWindChart now uses SailingSerive

This commit is contained in:
Alexander Ries committed 2014-12-07 19:20:42 +01:00
1 parent b19cb2064b
commit 35f8bbbad9
21 files changed
+537 -178

No files matched your search

@@ -0,0 +1,7 @@
package com.sap.sailing.dashboards.gwt.client;
import java.util.List;
public interface NumberOfWindBotsChangeListener {
public void numberOfWindBotsChanged(List<String> windBotIDs, WindBotDataRetrieverProvider windBotDataRetrieverProvider);
}
@@ -1,12 +1,15 @@
package com.sap.sailing.dashboards.gwt.client;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.RootPanel;
import com.sap.sailing.dashboards.gwt.client.bottomnotification.BottomNotification;
import com.sap.sailing.dashboards.gwt.client.device.Location;
import com.sap.sailing.dashboards.gwt.client.popups.RacingNotYetStartedPopup;
import com.sap.sailing.dashboards.gwt.client.popups.RacingNotYetStartedPopupListener;
@@ -15,6 +18,10 @@ import com.sap.sailing.dashboards.gwt.client.popups.competitorselection.Competit
import com.sap.sailing.dashboards.gwt.client.startanalysis.NewStartAnalysisListener;
import com.sap.sailing.dashboards.gwt.shared.dto.RibDashboardRaceInfoDTO;
import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisDTO;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.gwt.ui.client.RaceSelectionChangeListener;
import com.sap.sailing.gwt.ui.client.RaceSelectionProvider;
import com.sap.sse.gwt.client.player.TimeListener;
/**
* Class calls method {@link #requestLiveRaceInfoFromRibDashboadService()) to retrieve new
@@ -24,36 +31,38 @@ import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisDTO;
* @author Alexander Ries
*
*/
public class RibDashboardDataRetriever implements RacingNotYetStartedPopupListener, CompetitorSelectionPopupListener{
public class RibDashboardDataRetriever implements RacingNotYetStartedPopupListener, CompetitorSelectionPopupListener,
TimeListener, RaceSelectionProvider {
private int numberOfChachedStartAnalysisDTOs;
private String leaderboardGroupName;
private Timer dataRetrieverTimer;
private ArrayList<RibDashboardDataRetrieverListener> dataRetrieverListener;
private ArrayList<NewStartAnalysisListener> newStartAnalysisListeners;
private ArrayList<RaceSelectionChangeListener> raceSelectionChangeListener;
private final RibDashboardServiceAsync ribDashboardService;
private final Object MUTEX = new Object();
private final Object MUTEX;
private static RibDashboardDataRetriever INSTANCE = null;
private static final String PARAM_LEADERBOARD_GROUP_NAME = "leaderboardName";
private static final int REQUEST_INTERVAL = 5000;
private String selectedTeamName;
private CompetitorSelectionPopup competitorSelectionPopup;
private RacingNotYetStartedPopup popupRacingNotYetStarted;
private BottomNotification bottomNotification;
public RibDashboardDataRetriever() {
dataRetrieverListener = new ArrayList<RibDashboardDataRetrieverListener>();
newStartAnalysisListeners = new ArrayList<NewStartAnalysisListener>();
initNonFinalMemberVariablesWithNoArgumentConstructor();
initRacingNotYetStartedPopup();
MUTEX = new Object();
ribDashboardService = GWT.create(RibDashboardService.class);
this.leaderboardGroupName = Window.Location.getParameter(PARAM_LEADERBOARD_GROUP_NAME);
numberOfChachedStartAnalysisDTOs = 0;
popupRacingNotYetStarted = new RacingNotYetStartedPopup();
popupRacingNotYetStarted.addListener(this);
startRequestingData();
competitorSelectionPopup = new CompetitorSelectionPopup();
initBottomNotification();
}
public static RibDashboardDataRetriever getInstance() {
@@ -65,36 +74,33 @@ public class RibDashboardDataRetriever implements RacingNotYetStartedPopupListen
return INSTANCE;
}
public void startRequestingData() {
if (dataRetrieverTimer == null) {
dataRetrieverTimer = new Timer() {
@Override
public void run() {
requestLiveRaceInfoFromRibDashboadService();
}
};
dataRetrieverTimer.scheduleRepeating(REQUEST_INTERVAL);
dataRetrieverTimer.run();
}
private void initRacingNotYetStartedPopup() {
popupRacingNotYetStarted = new RacingNotYetStartedPopup();
popupRacingNotYetStarted.addListener(this);
}
private void stopRequestingData() {
if (dataRetrieverTimer.isRunning()) {
dataRetrieverTimer.cancel();
dataRetrieverTimer = null;
}
private void initBottomNotification() {
bottomNotification = new BottomNotification();
RootPanel.get().add(bottomNotification);
}
private void requestLiveRaceInfoFromRibDashboadService() {
System.out.println("Request with team "+selectedTeamName);
private void initNonFinalMemberVariablesWithNoArgumentConstructor() {
dataRetrieverListener = new ArrayList<RibDashboardDataRetrieverListener>();
newStartAnalysisListeners = new ArrayList<NewStartAnalysisListener>();
raceSelectionChangeListener = new ArrayList<RaceSelectionChangeListener>();
}
private void loadLiveRaceInfoFromRibDashboadService() {
ribDashboardService.getLiveRaceInfo(leaderboardGroupName, selectedTeamName,
new AsyncCallback<RibDashboardRaceInfoDTO>() {
@Override
public void onSuccess(RibDashboardRaceInfoDTO result) {
switch (result.responseMessage) {
case OK:
popupRacingNotYetStarted.hide(true);
popupRacingNotYetStarted.hide(/* remove blur effect */true);
List<RegattaAndRaceIdentifier> singletonList = Collections
.singletonList(result.idOfLastTrackedRace);
setSelection(singletonList);
if (result.startAnalysisDTOList != null) {
int numberOfReceivedStartAnalysisDTOs = result.startAnalysisDTOList.size();
if (numberOfChachedStartAnalysisDTOs != numberOfReceivedStartAnalysisDTOs) {
@@ -103,21 +109,25 @@ public class RibDashboardDataRetriever implements RacingNotYetStartedPopupListen
}
}
notifyDataObservers(result);
competitorSelectionPopup.hide();
break;
case NO_COMPETITOR_SELECTED:
popupRacingNotYetStarted.hide(true);
if (result.competitorNamesFromLastTrackedRace != null
&& result.competitorNamesFromLastTrackedRace.size() > 0) {
competitorSelectionPopup = new CompetitorSelectionPopup(
result.competitorNamesFromLastTrackedRace);
&& result.competitorNamesFromLastTrackedRace.size() > 0 && !competitorSelectionPopup.isShown()) {
competitorSelectionPopup.setCompetitorList(result.competitorNamesFromLastTrackedRace);
competitorSelectionPopup.addListener(RibDashboardDataRetriever.this);
competitorSelectionPopup.show();
stopRequestingData();
}
break;
case NO_RACE_LIVE:
popupRacingNotYetStarted.showWithMessageAndImageAndButtonText("Racing not yet started", RibDashboardImageResources.INSTANCE.beach(), "Retry");
stopRequestingData();
if (numberOfChachedStartAnalysisDTOs == 0) {
popupRacingNotYetStarted.showWithMessageAndImageAndButtonText("Racing not yet started",
RibDashboardImageResources.INSTANCE.beach(), "Retry");
} else {
bottomNotification.show("Race finished!", "#418bcb", "#FFFFFF", false);
setSelection(null);
}
break;
default:
break;
@@ -178,13 +188,57 @@ public class RibDashboardDataRetriever implements RacingNotYetStartedPopupListen
@Override
public void popupButtonClicked() {
startRequestingData();
}
@Override
public void didClickedOKWithCompetitorName(String competitorName) {
System.out.println("Did clicked with competitor "+competitorName);
System.out.println("Did clicked with competitor " + competitorName);
this.selectedTeamName = competitorName;
startRequestingData();
}
@Override
public void timeChanged(Date newTime, Date oldTime) {
loadLiveRaceInfoFromRibDashboadService();
}
@Override
public void addRaceSelectionChangeListener(RaceSelectionChangeListener listener) {
synchronized (MUTEX) {
if (listener != null) {
raceSelectionChangeListener.add(listener);
}
}
}
@Override
public void removeRaceSelectionChangeListener(RaceSelectionChangeListener listener) {
synchronized (MUTEX) {
raceSelectionChangeListener.remove(listener);
}
}
@Override
public void setSelection(List<RegattaAndRaceIdentifier> newSelection,
RaceSelectionChangeListener... listenersNotToNotify) {
synchronized (MUTEX) {
for (RaceSelectionChangeListener currentRaceSelectionChangeListener : raceSelectionChangeListener) {
currentRaceSelectionChangeListener.onRaceSelectionChange(newSelection);
}
}
}
@Override
public List<RegattaAndRaceIdentifier> getAllRaces() {
return null;
}
@Override
public void setAllRaces(List<RegattaAndRaceIdentifier> newAllRaces,
RaceSelectionChangeListener... listenersNotToNotify) {
}
@Override
public List<RegattaAndRaceIdentifier> getSelectedRaces() {
return null;
}
}
@@ -3,18 +3,14 @@ package com.sap.sailing.dashboards.gwt.client;
import java.util.logging.Logger;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.ui.RootLayoutPanel;
import com.googlecode.mgwt.ui.client.MGWT;
import com.googlecode.mgwt.ui.client.MGWTSettings;
import com.googlecode.mgwt.ui.client.MGWTSettings.StatusBarStyle;
import com.googlecode.mgwt.ui.client.MGWTSettings.ViewPort;
import com.googlecode.mgwt.ui.client.MGWTStyle;
import com.sap.sailing.gwt.ui.client.RemoteServiceMappingConstants;
import com.sap.sailing.gwt.ui.client.SailingService;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sse.gwt.client.EntryPointHelper;
import com.sap.sse.gwt.client.player.Timer;
import com.sap.sse.gwt.client.player.Timer.PlayModes;
/**
*
@@ -23,41 +19,33 @@ import com.sap.sse.gwt.client.EntryPointHelper;
*/
public class RibDashboardEntryPoint implements EntryPoint {
private final SailingServiceAsync sailingService = GWT.create(SailingService.class);
private final String RIBDASHBOARD_WEB_CONTEXT_PATH = "dashboards";
@SuppressWarnings("unused")
private static final Logger logger = Logger
.getLogger(RibDashboardEntryPoint.class.getName());
@SuppressWarnings("unused")
private static final Logger logger = Logger.getLogger(RibDashboardEntryPoint.class.getName());
private static final int DASHBOARD_RERFRESH_INTERVAL = 5000;
@Override
public void onModuleLoad() {
initSailingService();
applyMGWTSettings();
initAndAddRibDashboardPanel();
}
@Override
public void onModuleLoad() {
applyMGWTSettings();
RibDashboardPanel ribDashboardPanel = new RibDashboardPanel();
RootLayoutPanel.get().add(ribDashboardPanel);
WindBotDataRetriever windBotDataRetriever = new WindBotDataRetriever();
windBotDataRetriever.addNumberOfWindBotsChangeListeners(ribDashboardPanel);
RibDashboardDataRetriever.getInstance().addRaceSelectionChangeListener(windBotDataRetriever);
Timer dashboardTimer = new Timer(PlayModes.Live);
dashboardTimer.setRefreshInterval(DASHBOARD_RERFRESH_INTERVAL);
dashboardTimer.addTimeListener(windBotDataRetriever);
dashboardTimer.addTimeListener(RibDashboardDataRetriever.getInstance());
}
private void initSailingService() {
EntryPointHelper.registerASyncService(
(ServiceDefTarget) sailingService,
RIBDASHBOARD_WEB_CONTEXT_PATH,
RemoteServiceMappingConstants.sailingServiceRemotePath);
}
private void applyMGWTSettings() {
MGWTStyle.injectStyleSheet("RibDashboard.css");
ViewPort viewPort = new MGWTSettings.ViewPort();
viewPort.setUserScaleAble(false).setMinimumScale(1.0)
.setMinimumScale(1.0).setMaximumScale(1.0);
MGWTSettings settings = new MGWTSettings();
settings.setViewPort(viewPort);
settings.setFullscreen(true);
settings.setPreventScrolling(true);
settings.setStatusBarStyle(StatusBarStyle.BLACK_TRANSLUCENT);
MGWT.applySettings(settings);
}
private void initAndAddRibDashboardPanel() {
RibDashboardPanel root = new RibDashboardPanel();
RootLayoutPanel.get().add(root);
}
private void applyMGWTSettings() {
MGWTStyle.injectStyleSheet("RibDashboard.css");
ViewPort viewPort = new MGWTSettings.ViewPort();
viewPort.setUserScaleAble(false).setMinimumScale(1.0).setMinimumScale(1.0).setMaximumScale(1.0);
MGWTSettings settings = new MGWTSettings();
settings.setViewPort(viewPort);
settings.setFullscreen(true);
settings.setPreventScrolling(true);
settings.setStatusBarStyle(StatusBarStyle.BLACK_TRANSLUCENT);
MGWT.applySettings(settings);
}
}
@@ -1,7 +1,9 @@
package com.sap.sailing.dashboards.gwt.client;
import java.util.Iterator;
import java.util.Set;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
@@ -29,10 +31,11 @@ import com.sap.sailing.dashboards.gwt.shared.dto.RibDashboardRaceInfoDTO;
* @author Alexander Ries
*
*/
public class RibDashboardPanel extends Composite implements RibDashboardDataRetrieverListener{
public class RibDashboardPanel extends Composite implements RibDashboardDataRetrieverListener, NumberOfWindBotsChangeListener{
interface RootUiBinder extends UiBinder<Widget, RibDashboardPanel> {}
private static RootUiBinder uiBinder = GWT.create(RootUiBinder.class);
private static final Logger logger = Logger.getLogger(RibDashboardPanel.class.getName());
@UiField
RibDashboardPanelStyle style;
@@ -65,9 +68,10 @@ public class RibDashboardPanel extends Composite implements RibDashboardDataRetr
public StartlineAnalysisComponent startanalysisComponent;
private BottomNotification bottomNotification;
private boolean hasWindBotsInitialized;
private List<WindBotComponent> windBotComponents;
public RibDashboardPanel() {
windBotComponents = new ArrayList<WindBotComponent>();
RibDashboardDataRetriever.getInstance().addDataObserver(this);
initBottomNotification();
startanalysisComponent = new StartlineAnalysisComponent(bottomNotification);
@@ -92,28 +96,46 @@ public class RibDashboardPanel extends Composite implements RibDashboardDataRetr
RootPanel.get().add(bottomNotification);
}
private void initWindBotComponents(Set<String> windBotIDs) {
Iterator<String> windBotIDsIterator = windBotIDs.iterator();
private void initWindBotComponents(List<String> windBotIDs, WindBotDataRetrieverProvider windBotDataRetrieverProvider) {
int windBotAddedCounterTOConsiderForPanels = 0;
while (windBotIDsIterator.hasNext()) {
leftwindbotcontainer.clear();
removeWindBotComponentsAsDataRetrieverListener(windBotDataRetrieverProvider);
windBotComponents.clear();
for(String windBotID : windBotIDs){
if (windBotAddedCounterTOConsiderForPanels == 0) {
WindBotComponent leftwindBotComponent = new WindBotComponent(windBotIDsIterator.next());
WindBotComponent leftwindBotComponent = new WindBotComponent(windBotID);
leftwindbotcontainer.add(leftwindBotComponent);
windBotComponents.add(leftwindBotComponent);
} else if (windBotAddedCounterTOConsiderForPanels == 1) {
WindBotComponent rightwindBotComponent = new WindBotComponent(windBotIDsIterator.next());
WindBotComponent rightwindBotComponent = new WindBotComponent(windBotID);
rightwindbotcontainer.add(rightwindBotComponent);
windBotComponents.add(rightwindBotComponent);
}
windBotAddedCounterTOConsiderForPanels++;
}
addWindBotComponentsAsDataRetrieverListener(windBotDataRetrieverProvider);
}
private void addWindBotComponentsAsDataRetrieverListener(WindBotDataRetrieverProvider windBotDataRetrieverProvider){
for(WindBotComponent windBotComponent : windBotComponents){
windBotDataRetrieverProvider.addWindBotDataRetrieverListener(windBotComponent);
}
}
private void removeWindBotComponentsAsDataRetrieverListener(WindBotDataRetrieverProvider windBotDataRetrieverProvider){
for(WindBotComponent windBotComponent : windBotComponents){
windBotDataRetrieverProvider.removeWindBotDataRetrieverListener(windBotComponent);
}
}
@Override
public void updateUIWithNewLiveRaceInfo(RibDashboardRaceInfoDTO liveRaceInfoDTO) {
this.header.getElement().setInnerText(liveRaceInfoDTO.nameOfLastTrackedRace);
if (!hasWindBotsInitialized && liveRaceInfoDTO.windBotDTOForID != null) {
hasWindBotsInitialized = true;
Set<String> windBotIDs = liveRaceInfoDTO.windBotDTOForID.keySet();
initWindBotComponents(windBotIDs);
}
this.header.getElement().setInnerText(liveRaceInfoDTO.idOfLastTrackedRace.getRaceName());
}
@Override
public void numberOfWindBotsChanged(List<String> windBotIDs, WindBotDataRetrieverProvider windBotDataRetrieverProvider) {
logger.log(Level.INFO, "Number of Windbots changed");
initWindBotComponents(windBotIDs, windBotDataRetrieverProvider);
}
}
@@ -0,0 +1,136 @@
package com.sap.sailing.dashboards.gwt.client;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.common.WindSourceType;
import com.sap.sailing.gwt.ui.actions.GetWindInfoAction;
import com.sap.sailing.gwt.ui.client.RaceSelectionChangeListener;
import com.sap.sailing.gwt.ui.client.RemoteServiceMappingConstants;
import com.sap.sailing.gwt.ui.client.SailingService;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
import com.sap.sse.gwt.client.EntryPointHelper;
import com.sap.sse.gwt.client.async.AsyncActionsExecutor;
import com.sap.sse.gwt.client.player.TimeListener;
public class WindBotDataRetriever implements TimeListener, RaceSelectionChangeListener, WindBotDataRetrieverProvider {
private AsyncActionsExecutor asyncActionsExecutor;
private final SailingServiceAsync sailingService;
private final String RIBDASHBOARD_WEB_CONTEXT_PATH = "dashboards";
private RegattaAndRaceIdentifier currentLiveRace;
private List<NumberOfWindBotsChangeListener> numberOfWindBotsChangeListeners;
private List<WindBotDataRetrieverListener> windBotDataRetrieverListeners;
private List<String> windBotIDsInLiveRace;
private static final Logger logger = Logger.getLogger(WindBotDataRetriever.class.getName());
private static final int WIND_CHART_RESOLUTION_IN_MILLISECONDS = 5000;
public static final String LODA_WIND_CHART_DATA_CATEGORY = "loadWindChartData";
private boolean didInitialLoading;
public WindBotDataRetriever() {
currentLiveRace = null;
didInitialLoading = false;
sailingService = GWT.create(SailingService.class);
EntryPointHelper.registerASyncService((ServiceDefTarget) sailingService, RIBDASHBOARD_WEB_CONTEXT_PATH,
RemoteServiceMappingConstants.sailingServiceRemotePath);
asyncActionsExecutor = new AsyncActionsExecutor();
numberOfWindBotsChangeListeners = new ArrayList<NumberOfWindBotsChangeListener>();
windBotDataRetrieverListeners = new ArrayList<WindBotDataRetrieverListener>();
windBotIDsInLiveRace = new ArrayList<String>();
}
private void loadWindBotData(Date from, Date to, RegattaAndRaceIdentifier selectedRaceIdentifier) {
if(!didInitialLoading){
didInitialLoading = true;
from = new Date(from.getTime()-1000*60*15);
}
GetWindInfoAction getWindInfoAction = new GetWindInfoAction(sailingService, selectedRaceIdentifier, from, to,
WIND_CHART_RESOLUTION_IN_MILLISECONDS, null, /*
* onlyUpToNewestEvent==true because we don't want to
* overshoot the evidence so far
*/true);
asyncActionsExecutor.execute(getWindInfoAction, LODA_WIND_CHART_DATA_CATEGORY,
new AsyncCallback<WindInfoForRaceDTO>() {
@Override
public void onSuccess(WindInfoForRaceDTO result) {
if (result != null) {
if(windBotIDsInLiveRace.size() != getWindBotIdsFrom(result).size()){
windBotIDsInLiveRace = getWindBotIdsFrom(result);
notifyListenersAboutNumberOfWindBotChange(windBotIDsInLiveRace);
}
notifyWindBotDataRetrieverListeners(result);
}
}
@Override
public void onFailure(Throwable caught) {
}
});
}
public List<String> getWindBotIdsFrom(WindInfoForRaceDTO windInfoForRaceDTO) {
List<String> windBotIds = new ArrayList<String>();
for (WindSource windSource : windInfoForRaceDTO.windTrackInfoByWindSource.keySet()) {
if (windSource.getType().equals(WindSourceType.EXPEDITION) && windSource.getId() != null) {
windBotIds.add(windSource.getId().toString());
}
}
return windBotIds;
}
public void addNumberOfWindBotsChangeListeners(NumberOfWindBotsChangeListener numberOfWindBotsChangeListener) {
numberOfWindBotsChangeListeners.add(numberOfWindBotsChangeListener);
}
public void removeNumberOfWindBotsChangeListeners(NumberOfWindBotsChangeListener numberOfWindBotsChangeListener) {
numberOfWindBotsChangeListeners.remove(numberOfWindBotsChangeListener);
}
private void notifyListenersAboutNumberOfWindBotChange(List<String> windBotIDs) {
for (NumberOfWindBotsChangeListener numberOfWindBotsChangeListener : numberOfWindBotsChangeListeners) {
numberOfWindBotsChangeListener.numberOfWindBotsChanged(windBotIDs, this);
}
}
@Override
public void addWindBotDataRetrieverListener(WindBotDataRetrieverListener windBotDataRetrieverListener) {
windBotDataRetrieverListeners.add(windBotDataRetrieverListener);
}
@Override
public void removeWindBotDataRetrieverListener(WindBotDataRetrieverListener windBotDataRetrieverListener) {
windBotDataRetrieverListeners.remove(windBotDataRetrieverListener);
}
@Override
public void notifyWindBotDataRetrieverListeners(WindInfoForRaceDTO windInfoForRaceDTO) {
for (WindBotDataRetrieverListener windBotDataRetrieverListener : windBotDataRetrieverListeners) {
windBotDataRetrieverListener.updateWindBotUI(windInfoForRaceDTO);
}
}
@Override
public void timeChanged(Date newTime, Date oldTime) {
if (currentLiveRace != null) {
loadWindBotData(oldTime, newTime, currentLiveRace);
}
}
@Override
public void onRaceSelectionChange(List<RegattaAndRaceIdentifier> selectedRaces) {
if (selectedRaces == null) {
currentLiveRace = null;
} else if (selectedRaces.size() > 0) {
currentLiveRace = selectedRaces.get(0);
}
}
}
@@ -0,0 +1,8 @@
package com.sap.sailing.dashboards.gwt.client;
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
public interface WindBotDataRetrieverListener {
public void updateWindBotUI(WindInfoForRaceDTO windInfoForRaceDTO);
}
@@ -0,0 +1,10 @@
package com.sap.sailing.dashboards.gwt.client;
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
public interface WindBotDataRetrieverProvider {
public void addWindBotDataRetrieverListener(WindBotDataRetrieverListener windBotDataRetrieverListener);
public void removeWindBotDataRetrieverListener(WindBotDataRetrieverListener windBotDataRetrieverListener);
public void notifyWindBotDataRetrieverListeners(WindInfoForRaceDTO windInfoForRaceDTO);
}
@@ -9,9 +9,8 @@ import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.FocusPanel;
/**
* This class is a notification that pops up from the bottom of the screen.
* In the dashboard it is used to tell the user that there happened something important
* in the app. I.e if there is a new start analysis available.
* This class is a notification that pops up from the bottom of the screen. In the dashboard it is used to tell the user
* that there happened something important in the app. I.e if there is a new start analysis available.
*
* @author Alexander Ries
*
@@ -43,19 +42,22 @@ public class BottomNotification extends FocusPanel {
public void initClickHander() {
}
public void show(String message) {
public void show(String message, String backgroundColorAsHex, String textcolorAsHex, boolean dismissAfter20Seconds) {
shown = true;
this.removeStyleName("bottomnotificationhidden");
this.addStyleName("bottomnotificationshow");
this.getElement().setInnerHTML(message);
Timer timer = new Timer() {
public void run() {
hide();
}
};
timer.schedule(20000);
this.getElement().getStyle().setBackgroundColor(backgroundColorAsHex);
this.getElement().getStyle().setColor(textcolorAsHex);
if (dismissAfter20Seconds) {
Timer timer = new Timer() {
public void run() {
hide();
}
};
timer.schedule(20000);
}
}
public void hide() {
@@ -67,17 +69,17 @@ public class BottomNotification extends FocusPanel {
this.addStyleName("bottomnotificationhidden");
this.getElement().setInnerHTML("");
}
public void addBottomNotificationClickListener(BottomNotificationClickListener bottomNotificationClickListener){
public void addBottomNotificationClickListener(BottomNotificationClickListener bottomNotificationClickListener) {
bottomNotificationClickListeners.add(bottomNotificationClickListener);
}
public void removeBottomNotificationClickListener(BottomNotificationClickListener bottomNotificationClickListener){
public void removeBottomNotificationClickListener(BottomNotificationClickListener bottomNotificationClickListener) {
bottomNotificationClickListeners.remove(bottomNotificationClickListener);
}
private void nofitifyBottomNotificationClickListenersAboutClick(){
for(BottomNotificationClickListener bncl: bottomNotificationClickListeners){
private void nofitifyBottomNotificationClickListenersAboutClick() {
for (BottomNotificationClickListener bncl : bottomNotificationClickListeners) {
bncl.bottomNotificationClicked();
}
}
@@ -45,6 +45,7 @@ public class CompetitorSelectionPopup extends Composite implements HasWidgets, C
Button button;
private String currentCompetitorSelected;
private boolean isVisible;
private List<CompetitorSelectionPopupListener> competitorSelectionPopupListener;
@@ -53,15 +54,15 @@ public class CompetitorSelectionPopup extends Composite implements HasWidgets, C
interface CompetitorSelectionPopupUiBinder extends UiBinder<Widget, CompetitorSelectionPopup> {
}
public CompetitorSelectionPopup(List<String> competitorList) {
public CompetitorSelectionPopup() {
competitorSelectionPopupListener = new ArrayList<CompetitorSelectionPopupListener>();
competitortable = new CompetitorTable(competitorList, this);
competitortable = new CompetitorTable(this);
isVisible = false;
initWidget(uiBinder.createAndBindUi(this));
initPopUp();
}
private void initPopUp() {
show();
public void setCompetitorList(List<String> competitorList){
competitortable.setTableContent(competitorList);
}
public void show() {
@@ -70,6 +71,7 @@ public class CompetitorSelectionPopup extends Composite implements HasWidgets, C
this.getElement().addClassName(style.popupshow());
this.getElement().removeClassName(style.popuphide());
RootLayoutPanel.get().addStyleName(style.blurred());
isVisible = true;
}
public void hide() {
@@ -77,6 +79,7 @@ public class CompetitorSelectionPopup extends Composite implements HasWidgets, C
this.getElement().removeClassName(style.popupshow());
RootLayoutPanel.get().addStyleName(style.not_blurred());
RootPanel.get().remove(this);
isVisible = false;
}
public void addListener(CompetitorSelectionPopupListener o) {
@@ -94,6 +97,10 @@ public class CompetitorSelectionPopup extends Composite implements HasWidgets, C
newStartAnalysisListener.didClickedOKWithCompetitorName(competitorName);
}
}
public boolean isShown(){
return isVisible;
}
@UiHandler("button")
void handleClick(ClickEvent e) {
@@ -16,11 +16,13 @@ public class CompetitorTable extends AbsolutePanel {
private CellTable<String> table;
private CompetitorTableRowSelectionListener competitorTableRowSelectionListener;
public CompetitorTable(List<String> competitorNames, CompetitorTableRowSelectionListener competitorTableRowSelectionListener) {
initTable(competitorNames);
public CompetitorTable(CompetitorTableRowSelectionListener competitorTableRowSelectionListener) {
this.competitorTableRowSelectionListener = competitorTableRowSelectionListener;
}
public void setTableContent(List<String> competitorNames){
initTable(competitorNames);
}
private void initTable(List<String> competitorNames) {
CellTable.Resources tableRes = GWT.create(CompetitorTableStyleResource.class);
@@ -212,7 +212,7 @@ public class StartlineAnalysisComponent extends Composite implements HasWidgets,
@Override
public void addNewStartAnalysisCard(List<StartAnalysisDTO> startAnalysisDTOs) {
this.bottomNotification.show("New Start Analysis available.");
this.bottomNotification.show("New Start Analysis available.", "#F0AB00", "#000000", true);
for (int i = numberOfStartAnalysisCards; i <= startAnalysisDTOs.size() - 1; i++) {
addStartAnalysisCard(startAnalysisDTOs.get(i));
starts.add(startAnalysisDTOs.get(i));
@@ -99,6 +99,7 @@ public class LiveAverageComponent extends Composite implements HasWidgets {
}
public void updateValues(String liveValue, String averageValue) {
System.out.println("UPDATE VALUES");
this.liveNumber.setInnerText(liveValue);
this.averageNumber.setInnerText(averageValue);
}
@@ -37,7 +37,7 @@ import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.dashboards.gwt.client.RibDashboardEntryPoint;
import com.sap.sailing.gwt.ui.client.shared.charts.ChartPointRecalculator;
import com.sap.sailing.dashboards.gwt.shared.MovingAverage;
/**
* The class represents a wind chart that is displayed vertically. Because it is meant to be used to display wind fixes,
@@ -51,6 +51,8 @@ import com.sap.sailing.gwt.ui.client.shared.charts.ChartPointRecalculator;
public class VerticalWindChart extends Composite implements HasWidgets {
private Series verticalWindChartSeries;
private String positiveSeriesColorAsHex;
private String negativeSeriesColorAsHex;
/**
* The field is used to cache the current selected display interval. It is either
@@ -105,7 +107,8 @@ public class VerticalWindChart extends Composite implements HasWidgets {
setChartOptions();
setXAxisOptions();
setYAxisOptions();
initAndConfigureVerticalWindChartSeriesWithColors(positiveFillColor, negativeFillColor);
positiveSeriesColorAsHex = positiveFillColor;
negativeSeriesColorAsHex = negativeFillColor;
}
private void setChartOptions() {
@@ -152,14 +155,14 @@ public class VerticalWindChart extends Composite implements HasWidgets {
}));
}
private void initAndConfigureVerticalWindChartSeriesWithColors(String positiveFillColor, String negativeFillColor) {
private void initVerticalWindChartSeries() {
verticalWindChartSeries = verticalWindChart.createSeries();
AreaPlotOptions areaPlotOptions = new AreaPlotOptions();
verticalWindChart.addSeries(verticalWindChartSeries.setName(null).setPlotOptions(
areaPlotOptions.setDashStyle(DashStyle.SOLID).setLineWidth(0.1)
.setMarker(new Marker().setEnabled(false)).setShadow(false).setHoverStateEnabled(false)
.setLineColor("#FFFFFF").setFillColor(positiveFillColor)
.setOption("negativeFillColor", negativeFillColor)));
.setLineColor("#FFFFFF").setFillColor(positiveSeriesColorAsHex)
.setOption("negativeFillColor", negativeSeriesColorAsHex)));
}
/**
@@ -171,23 +174,20 @@ public class VerticalWindChart extends Composite implements HasWidgets {
* {@link #setXAxisExtremesForSeriesPointRangeIsSmallerThanChartDisplayIntervall()} and
* {@link #setXAxisExtremesForSeriesPointRangeIsBiggerThanChartDisplayIntervall()}.
* */
public void addPointToSeriesWithAverage(Point point, double average, boolean pointContainsWindDirectionValue) {
if (pointContainsWindDirectionValue == true) {
adaptWindDirectionPointToStayCloseToLastPoint(point);
public void addPointsToSeriesWithAverage(Point[] points, double average) {
if (verticalWindChartSeries == null) {
initVerticalWindChartSeries();
verticalWindChartSeries.setPoints(points, true);
} else {
for (Point point : points) {
verticalWindChartSeries.addPoint(point, true, false, false);
}
}
verticalWindChartSeries.addPoint(point, true, false, true);
verticalWindChartSeries.updateThreshold("" + average);
adaptVerticalWindChartExtemes();
verticalWindChart.setSizeToMatchContainer();
}
private void adaptWindDirectionPointToStayCloseToLastPoint(Point newPoint) {
Point lastPointOfVerticalWindChartSeries = getLastPointOfVerticalWindChartSeries();
if (lastPointOfVerticalWindChartSeries != null) {
newPoint = ChartPointRecalculator.stayClosestToPreviousPoint(lastPointOfVerticalWindChartSeries, newPoint);
}
}
/**
* Depending on the series points time range and the selected display interval, the series fits into the display
* interval or not. So there are two cases where the extreme points of the x-axis get calculated differently.
@@ -246,10 +246,12 @@ public class VerticalWindChart extends Composite implements HasWidgets {
private Point getLastPointOfVerticalWindChartSeries() {
Point lastPointOfVerticalWindChartSeries = null;
Point[] seriesPoints = verticalWindChartSeries.getPoints();
int seriesPointsLenght = seriesPoints.length;
if (seriesPointsLenght > 0) {
lastPointOfVerticalWindChartSeries = seriesPoints[seriesPointsLenght - 1];
if (verticalWindChartSeries != null) {
Point[] seriesPoints = verticalWindChartSeries.getPoints();
int seriesPointsLenght = seriesPoints.length;
if (seriesPointsLenght > 0) {
lastPointOfVerticalWindChartSeries = seriesPoints[seriesPointsLenght - 1];
}
}
return lastPointOfVerticalWindChartSeries;
}
@@ -1,7 +1,7 @@
package com.sap.sailing.dashboards.gwt.client.windchart;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import org.moxieapps.gwt.highcharts.client.Point;
@@ -10,16 +10,24 @@ import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.dashboards.gwt.client.RibDashboardDataRetriever;
import com.sap.sailing.dashboards.gwt.client.RibDashboardDataRetrieverListener;
import com.sap.sailing.dashboards.gwt.client.WindBotDataRetrieverListener;
import com.sap.sailing.dashboards.gwt.client.startlineadvantage.LiveAverageComponent;
import com.sap.sailing.dashboards.gwt.client.windchart.compass.LocationPointerCompass;
import com.sap.sailing.dashboards.gwt.shared.dto.RibDashboardRaceInfoDTO;
import com.sap.sailing.dashboards.gwt.shared.dto.WindBotComponentDTO;
import com.sap.sailing.dashboards.gwt.shared.MovingAverage;
import com.sap.sailing.dashboards.gwt.shared.SinWave;
import com.sap.sailing.dashboards.gwt.shared.WindType;
import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.common.WindSourceType;
import com.sap.sailing.gwt.ui.client.shared.charts.ChartPointRecalculator;
import com.sap.sailing.gwt.ui.shared.WindDTO;
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
import com.sap.sailing.gwt.ui.shared.WindTrackInfoDTO;
/**
* The class is an actual widget on the dashboard and shows the measured data of wind bot in a race. It contains a
@@ -31,9 +39,18 @@ import com.sap.sailing.dashboards.gwt.shared.dto.WindBotComponentDTO;
* @author Alexander Ries (D062114)
*
*/
public class WindBotComponent extends Composite implements HasWidgets, RibDashboardDataRetrieverListener {
public class WindBotComponent extends Composite implements HasWidgets, WindBotDataRetrieverListener {
private String windBotID = null;
private SinWave speedSinWave;
private SinWave directionSinWave;
private boolean inSimulationMode;
private MovingAverage movingAverageSpeed;
private MovingAverage movingAverageDirection;
private static WindBotComponentUiBinder uiBinder = GWT.create(WindBotComponentUiBinder.class);
private static final String IN_SIMULATION_MODE = "simulation";
interface WindBotComponentUiBinder extends UiBinder<Widget, WindBotComponent> {
}
@@ -86,32 +103,28 @@ public class WindBotComponent extends Composite implements HasWidgets, RibDashbo
public WindBotComponent(String windBotId) {
this.windBotId = windBotId;
RibDashboardDataRetriever.getInstance().addDataObserver(this);
if (Window.Location.getParameter(IN_SIMULATION_MODE).toString().equals("true")) {
inSimulationMode = true;
this.speedSinWave = new SinWave(50, 8);
this.directionSinWave = new SinWave(100, 8);
} else {
inSimulationMode = false;
}
movingAverageSpeed = new MovingAverage(500);
movingAverageDirection = new MovingAverage(500);
initWidget(uiBinder.createAndBindUi(this));
windBotNamePanel.getElement().setInnerText("Wind Bot " + windBotId);
}
/**
* Updates the classes {@link LiveAverageComponent}s and {@link VerticalWindChart}s with data AND updates the
* {@link #locationPointerCompass} with a new wind bot position !!!
* */
@Override
public void updateUIWithNewLiveRaceInfo(RibDashboardRaceInfoDTO liveRaceInfoDTO) {
WindBotComponentDTO windBotDTO = liveRaceInfoDTO.windBotDTOForID.get(windBotId);
if (windBotDTO != null) {
double now = new Date().getTime();
trueWindSpeedLiveAverageComponent.updateValues(
"" + NumberFormat.getFormat("#0.0").format(windBotDTO.liveWindSpeedInKts), ""
+ NumberFormat.getFormat("#0.0").format(windBotDTO.averageWindSpeedInKts));
trueWindDirectionLiveAverageComponent.updateValues(
"" + NumberFormat.getFormat("#0.0").format(windBotDTO.liveWindDirectionInDegrees), ""
+ NumberFormat.getFormat("#0.0").format(windBotDTO.averageWindDirectionInDegrees));
trueWindSpeedVerticalWindChart.addPointToSeriesWithAverage(new Point(now, windBotDTO.liveWindSpeedInKts),
windBotDTO.averageWindSpeedInKts, false);
trueWindDirectionVerticalWindChart.addPointToSeriesWithAverage(new Point(now,
windBotDTO.liveWindDirectionInDegrees), windBotDTO.averageWindDirectionInDegrees, true);
locationPointerCompass.windBotPositionChanged(windBotDTO.position);
public WindTrackInfoDTO getWindTrackInfoDTOFromAndWindBotID(WindInfoForRaceDTO windInfoForRaceDTO, String id) {
WindTrackInfoDTO windTrackInfo = null;
for (WindSource windSource : windInfoForRaceDTO.windTrackInfoByWindSource.keySet()) {
if (windSource.getType().equals(WindSourceType.EXPEDITION) && windSource.getId() != null) {
if (windSource.getId().toString().equals(id))
windTrackInfo = windInfoForRaceDTO.windTrackInfoByWindSource.get(windSource);
}
}
return windTrackInfo;
}
@Override
@@ -133,4 +146,81 @@ public class WindBotComponent extends Composite implements HasWidgets, RibDashbo
public boolean remove(Widget w) {
return false;
}
/**
* Updates the classes {@link LiveAverageComponent}s and {@link VerticalWindChart}s with data AND updates the
* {@link #locationPointerCompass} with a new wind bot position !!!
* */
@Override
public void updateWindBotUI(WindInfoForRaceDTO windInfoForRaceDTO) {
if (windInfoForRaceDTO != null) {
WindTrackInfoDTO windTrackInfoDTO = getWindTrackInfoDTOFromAndWindBotID(windInfoForRaceDTO, windBotId);
if (windTrackInfoDTO != null) {
if (windTrackInfoDTO.windFixes != null && windTrackInfoDTO.windFixes.size() > 0) {
Point[] speedPoints = convertWindFixListIntoPointsArray(windTrackInfoDTO.windFixes, WindType.SPEED);
Point[] directionPoints = convertWindFixListIntoPointsArray(windTrackInfoDTO.windFixes,
WindType.DIRECTION);
trueWindSpeedLiveAverageComponent.updateValues(
""
+ NumberFormat.getFormat("#0.0").format(
speedPoints[speedPoints.length - 1].getY().doubleValue()), ""
+ NumberFormat.getFormat("#0.0").format(movingAverageSpeed.getAverage()));
trueWindDirectionLiveAverageComponent.updateValues(
""
+ NumberFormat.getFormat("#0.0").format(
directionPoints[directionPoints.length - 1].getY().doubleValue()), ""
+ NumberFormat.getFormat("#0.0").format(movingAverageDirection.getAverage()));
trueWindSpeedVerticalWindChart.addPointsToSeriesWithAverage(speedPoints,
movingAverageSpeed.getAverage());
trueWindDirectionVerticalWindChart.addPointsToSeriesWithAverage(directionPoints,
movingAverageDirection.getAverage());
locationPointerCompass.windBotPositionChanged(windTrackInfoDTO.windFixes
.get(windTrackInfoDTO.windFixes.size() - 1).position);
}
}
}
}
private Point[] convertWindFixListIntoPointsArray(List<WindDTO> windFixes, WindType windtype) {
if (windFixes != null && windFixes.size() > 0) {
Point[] points = new Point[windFixes.size()];
int counter = 0;
if (windtype.equals(WindType.DIRECTION)) {
Point previouspoint = new Point(windFixes.get(0).requestTimepoint, windFixes.get(0).trueWindBearingDeg);
for (WindDTO windDTO : windFixes) {
double nextSinusValue = 0;
if (inSimulationMode == true) {
nextSinusValue = directionSinWave.getNexNumber();
}
points[counter] = new Point(windDTO.requestTimepoint, windDTO.trueWindBearingDeg + nextSinusValue);
points[counter] = adaptWindDirectionPointToStayCloseToLastPoint(previouspoint, points[counter]);
previouspoint = points[counter];
movingAverageDirection.add(windDTO.trueWindBearingDeg + nextSinusValue);
counter++;
}
} else if (windtype.equals(WindType.SPEED)) {
Point previouspoint = new Point(windFixes.get(0).requestTimepoint,
windFixes.get(0).trueWindSpeedInKnots);
for (WindDTO windDTO : windFixes) {
double nextSinusValue = 0;
if (inSimulationMode == true) {
nextSinusValue = speedSinWave.getNexNumber();
}
points[counter] = new Point(windDTO.requestTimepoint, windDTO.trueWindSpeedInKnots + nextSinusValue);
points[counter] = adaptWindDirectionPointToStayCloseToLastPoint(previouspoint, points[counter]);
previouspoint = points[counter];
movingAverageSpeed.add(windDTO.trueWindSpeedInKnots + nextSinusValue);
counter++;
}
}
return points;
} else {
return null;
}
}
private Point adaptWindDirectionPointToStayCloseToLastPoint(Point previousPoint, Point point) {
return ChartPointRecalculator.stayClosestToPreviousPoint(previousPoint, point);
}
}
@@ -17,7 +17,7 @@ import org.osgi.util.tracker.ServiceTracker;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.sap.sailing.dashboards.gwt.client.RibDashboardService;
import com.sap.sailing.dashboards.gwt.server.utils.MovingAverage;
import com.sap.sailing.dashboards.gwt.shared.MovingAverage;
import com.sap.sailing.dashboards.gwt.shared.ResponseMessage;
import com.sap.sailing.dashboards.gwt.shared.dto.RibDashboardRaceInfoDTO;
import com.sap.sailing.dashboards.gwt.shared.dto.StartLineAdvantageDTO;
@@ -216,7 +216,7 @@ public class RibDashboardServiceImpl extends RemoteServiceServlet implements
private void fillLiveRaceInfoDTOWithRaceData(
RibDashboardRaceInfoDTO lRInfo, TimePoint now) {
if (runningRace != null) {
lRInfo.nameOfLastTrackedRace = runningRace.getRace().getName();
lRInfo.idOfLastTrackedRace = runningRace.getRaceIdentifier();
try {
List<Competitor> competitors = runningRace
.getCompetitorsFromBestToWorst(now);
@@ -1,4 +1,4 @@
package com.sap.sailing.dashboards.gwt.server.utils;
package com.sap.sailing.dashboards.gwt.shared;
import java.util.ArrayList;
import java.util.List;
@@ -1,7 +1,7 @@
/**
*
*/
package com.sap.sailing.dashboards.gwt.server.utils;
package com.sap.sailing.dashboards.gwt.shared;
/**
@@ -0,0 +1,22 @@
package com.sap.sailing.dashboards.gwt.shared;
public class SinWave {
private double period = 100; // loop every 8 calls to updateNumber
private double scale = 5; // go between 0 and this
private int _pos = 0;
private double Number1 = 0;
public SinWave(double period, double scale) {
this.period = period;
this.scale = scale;
}
public double getNexNumber() {
_pos++;
Number1 = (double) (Math.sin(_pos * 2 * Math.PI / period) * (scale / 2) + (scale / 2));
return Number1;
}
}
@@ -0,0 +1,6 @@
package com.sap.sailing.dashboards.gwt.shared;
public enum WindType {
SPEED,
DIRECTION
}
@@ -9,6 +9,7 @@ import java.util.Map;
import com.sap.sailing.dashboards.gwt.shared.ResponseMessage;
import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisDTO;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
/**
* @author Alexander Ries
@@ -22,7 +23,7 @@ public class RibDashboardRaceInfoDTO implements Serializable{
public StartLineAdvantageDTO startLineAdvantageDTO;
public List<StartAnalysisDTO> startAnalysisDTOList;
public List<String> competitorNamesFromLastTrackedRace;
public String nameOfLastTrackedRace;
public RegattaAndRaceIdentifier idOfLastTrackedRace;
public ResponseMessage responseMessage;
public RibDashboardRaceInfoDTO() {}
@@ -59,7 +59,8 @@ Bundle-ClassPath: WEB-INF/classes/,
WEB-INF/lib/gwt-ajaxloader.jar,
WEB-INF/lib/gwt-bootstrap-2.3.2.0.jar
TrackLifecycle: true
Export-Package: com.sap.sailing.gwt.ui.client,
Export-Package: com.sap.sailing.gwt.ui.actions,
com.sap.sailing.gwt.ui.client,
com.sap.sailing.gwt.ui.client.shared.charts,
com.sap.sailing.gwt.ui.client.shared.racemap,
com.sap.sailing.gwt.ui.server,