From 7b2440784c2684d499109cfbfcacc5a92a0d5f92 Mon Sep 17 00:00:00 2001 From: Papick Garcia Taboada Date: Tue, 26 May 2015 09:36:11 +0200 Subject: [PATCH 01/72] 2796: Click/cursor behavior incorrect for stage area of Home.html Task-Url: http://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=2796 --- .../sap/sailing/gwt/home/client/shared/stage/StageTeaser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/StageTeaser.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/StageTeaser.java index 00207af8640..9c5057fd270 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/StageTeaser.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/StageTeaser.java @@ -92,7 +92,7 @@ public abstract class StageTeaser extends Composite implements LazyLoadable { return; } Element element = eventTarget.cast(); - if (stageTeaserBandsPanel.getElement().isOrHasChild(element)) { + if (bandCount.isOrHasChild(element)) { return; } handleUserAction(); From 12264611da4660fb90cc2638324f31133e027880 Mon Sep 17 00:00:00 2001 From: Papick Garcia Taboada Date: Sat, 23 May 2015 03:14:25 +0200 Subject: [PATCH 02/72] Fixed regatta overview gwt compile issues --- .../regattaoverview/RegattaOverview.gwt.xml | 1 + .../client/eventheader/EventHeader.gss | 310 ------------------ .../client/eventheader/EventHeader.java | 49 --- .../client/eventheader/EventHeader.ui.xml | 30 -- .../eventheader/EventHeaderResources.java | 64 ---- .../{home => }/server/HomeServiceImpl.java | 0 .../{home => }/server/HomeServiceUtil.java | 0 .../sailing/gwt/ui/SourceAdminConsole.gwt.xml | 15 + 8 files changed, 16 insertions(+), 453 deletions(-) delete mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/eventheader/EventHeader.gss delete mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/eventheader/EventHeader.java delete mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/eventheader/EventHeader.ui.xml delete mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/eventheader/EventHeaderResources.java rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/{home => }/server/HomeServiceImpl.java (100%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/{home => }/server/HomeServiceUtil.java (100%) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/SourceAdminConsole.gwt.xml diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/RegattaOverview.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/RegattaOverview.gwt.xml index 496d4f56664..f89a1f9790d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/RegattaOverview.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/RegattaOverview.gwt.xml @@ -48,6 +48,7 @@ + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/eventheader/EventHeader.gss b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/eventheader/EventHeader.gss deleted file mode 100644 index 2f0408dba82..00000000000 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/eventheader/EventHeader.gss +++ /dev/null @@ -1,310 +0,0 @@ -/** - * The header of the pages to an event - */ -.jsdropdown { - position: relative; -} -.jsdropdown_head, -.jsdropdown_content { - text-indent: 0; -} -.dropdown { - font-size: 1rem; - width: 20em; - max-width: 100%; - display: inline-block; - text-align: left; -} -.dropdown_head { - display: block; -} -.dropdown_head_title { - font-size: 1.866666666666667em; - cursor: pointer; - background: #f8f8f8; - color: #cfcfcf; - height: 1.464285714285714em; - line-height: 1.428571428571429em; - padding-left: 0.535714285714286em; - font-weight: 700; -} -.dropdown_head_title_button { - float: right; -} -.dropdown_content { - position: absolute; - z-index: 1; - background: #f6f9fc; - display: none; - width: 20em; - height: auto; - max-height: 23.333333333333332em; - overflow: auto; - box-shadow: 0 0.066666666666667em 0.266666666666667em #eee; - border-bottom: solid 1px #eee; -} -.jsdropdownactive .dropdown_content { - display: block; -} -.dropdown_content_link { - display: block; - cursor: pointer; - padding: 1.333333333333333em 3.333333333333333em 1em 1em; - border-bottom: 1px solid #f4f4f4; -} -.dropdown_content_link:hover, -.dropdown_content_link:focus { - background: #f8f8f8; - text-decoration: none; -} -.dropdown_content_link:hover .dropdown_content_link_title, -.dropdown_content_link:focus .dropdown_content_link_title { - text-decoration: underline; -} -.dropdown_content_link_title { - color: #008fcc; - display: block; - font-weight: 600; - font-size: 1.2em; -} -.dropdown_content_link_subtitle { - color: #cfcfcf; - font-size: 1.066666666666667em; -} -.dropdownregattas { - width: 100%; - min-width: 21.333333333333332em; - margin-left: -0.666666666666667em; -} -.dropdownregattas_head { - display: inherit; -} -.dropdownregattas_head_title { - padding-left: 0.357142857142857em; - background: #f2f2f2; - color: #333; - border-radius: 0.107142857142857em; - border: 1px solid transparent; -} -.dropdownregattas_head_title:hover { - border: 1px solid #cfcfcf; - background-color: #eee; - text-decoration: none; -} -.dropdownregattas_head_title_button { - position: relative; - display: inline-block; - margin-left: 0.714285714285714em; - top: 50%; - height: 0.285714285714286em; - width: 0.428571428571429em; - background-image: url("images/home/dropdown__button--arrow@2x.png"); - background-position: center bottom; - background-repeat: no-repeat; - background-size: 100%; - -webkit-transform: translate(-50%, -50%); - -moz-transform: translate(-50%, -50%); - -ms-transform: translate(-50%, -50%); - transform: translate(-50%, -50%); - float: none; -} -.dropdownregattas_content { - width: auto; - background-color: #fff; - border: 1px solid #ccc; - box-shadow: 0.133333333333333em 0.133333333333333em 0.333333333333333em #ccc; -} -.dropdownregattas_content_link { - position: relative; - border: none; -} -.dropdownregattas_content_link:hover { - text-decoration: none; -} -.dropdownregattas_content_linkactive:after { - content: ''; - position: absolute; - right: 1.333333333333333em; - top: 50%; - height: 0.933333333333333em; - width: 0.933333333333333em; - background-image: url("images/home/dropdown__check@2x.png"); - background-repeat: no-repeat; - background-position: right center; - background-size: contain; - -webkit-transform: translate(0, -50%); - -moz-transform: translate(0, -50%); - -ms-transform: translate(0, -50%); - transform: translate(0, -50%); -} -.dropdownregattas_content_link_title { - color: #666; -} -.leaderboardquickaccess { - font-size: 1rem; - text-align: right; -} -.eventheader { - position: relative; - font-size: 1rem; - color: #666; - background: #f2f2f2; - border-bottom: 1px solid #dedede; -} -.eventheader_breadcrumb { - font-size: 1rem; - /* @alternate */font-size: 0.866666666666667em; - font-weight: 600; - padding: 0.666666666666667em 0; -} -.eventheader_breadcrumbback { - position: absolute; - top: 0; - bottom: 0; - left: 0; - width: 1.333333333333333em; - border-right: 1px solid #cfcfcf; - background-color: #dedede; - background-image: url("images/home/breadcrumb-arrow__back.png"); - background-position: center center; - background-repeat: no-repeat; - background-size: 50%; - -webkit-transition: background-color 0.2s, border-color 0.2s; - -moz-transition: background-color 0.2s, border-color 0.2s; - transition: background-color 0.2s, border-color 0.2s; -} -.eventheader_breadcrumbback:hover { - background-color: #cfcfcf; -} -.eventheader_intro { - padding-left: 6em; - margin: 0.666666666666667em 0; - min-height: 5em; - position: relative; -} -.eventheader_intro_logo { - position: absolute; - top: 0; - left: 0; - width: 5em; - height: 5em; - border: 0.333333333333333em solid #f6f9fc; - box-shadow: 0 0 5px rgba(238,238,238,0.5); -} -.eventheader_intro_logo_image { - height: 100%; - width: 100%; - background-position: center; - background-size: contain; - background-repeat: no-repeat; -} -.eventheader_intro_name { - display: inline-block; - margin: 0 0.333333333333333em 0 0; - font-size: 1.866666666666667em; - color: #333; -} -.eventheader_intro_details { - margin-bottom: 0.666666666666667em; - padding-bottom: 0.666666666666667em; - font-weight: 700; - color: #333; -} -.eventheader_intro_details_item { - display: inline-block; - border-left: 1px solid #cfcfcf; - margin: 0.266666666666667em 0 0.266666666666667em 0.333333333333333em; - padding-left: 0.666666666666667em; - color: #666; -} -.eventheader_intro_details_itemlink { - color: inherit; -} -.eventheader_intro_details_item:first-child { - margin-left: 0; - padding-left: 0; - border: none; -} -.eventheader_status { - text-align: right; -} -.eventheader_status_title { - text-transform: uppercase; -} -.eventheader_status_body { - font-size: 1rem; -} -.locationicon { - vertical-align: text-bottom; - margin-right: 0.333333333333333em; -} -.eventnavigation { - font-size: 0; - margin-bottom: -1px; -} -.eventnavigationnormal { - position: relative; -} -.eventnavigation_dropdown { - display: inline-block; - position: relative; -} -.eventnavigation_dropdown_toggle { - cursor: pointer; - display: inline-block; -} -@media (min-width: 61em) { - .eventnavigation_dropdown_toggle { - display: none; - } -} -.eventnavigation_dropdown_toggle_icon { - display: inline-block; - position: relative; - top: 50%; - width: 0.8em; - height: 0.533333333333333em; - vertical-align: middle; - background-image: url("images/home/dropdown__button--arrow@2x.png"); - background-size: 100%; - background-repeat: no-repeat; - background-position: center bottom; -} -.eventnavigation_dropdown_container { - position: absolute; - left: 0; - z-index: 99; -} -@media (min-width: 61em) { - .eventnavigation_dropdown_container { - display: inline-block; - position: relative; - left: auto; - } -} -.eventnavigation_dropdown_containerhidden { - display: none; -} -@media (min-width: 61em) { - .eventnavigation_dropdown_containerhidden { - display: inline-block; - } -} -.eventnavigation_dropdown_container .navbar_button { - border-top-width: 0; - width: 16.666666666666668em; -} -@media (min-width: 61em) { - .eventnavigation_dropdown_container .navbar_button { - border-top-width: 1px; - width: auto; - } -} -@media (min-width: 61em) { - .eventnavigation_dropdown_container .navbar_buttonhidden { - display: inline-block; - } -} -.eventnavigation .navbar_button { - font-size: 1.2rem; -} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/eventheader/EventHeader.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/eventheader/EventHeader.java deleted file mode 100644 index 755f501f2c7..00000000000 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/eventheader/EventHeader.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.sap.sailing.gwt.regattaoverview.client.eventheader; - -import java.util.Date; - -import com.google.gwt.core.client.GWT; -import com.google.gwt.dom.client.DivElement; -import com.google.gwt.dom.client.SpanElement; -import com.google.gwt.uibinder.client.UiBinder; -import com.google.gwt.uibinder.client.UiField; -import com.google.gwt.user.client.ui.Composite; -import com.google.gwt.user.client.ui.Widget; -import com.sap.sailing.gwt.home.client.shared.EventDatesFormatterUtil; - -public class EventHeader extends Composite { - private static EventHeaderUiBinder uiBinder = GWT.create(EventHeaderUiBinder.class); - - interface EventHeaderUiBinder extends UiBinder { - } - - - @UiField DivElement eventLogo; - @UiField SpanElement eventName; - @UiField DivElement eventDate; - @UiField SpanElement eventVenue; - @UiField DivElement eventVenueContainer; - - - - public EventHeader() { - EventHeaderResources.INSTANCE.css().ensureInjected(); - initWidget(uiBinder.createAndBindUi(this)); - } - - public void setLogoUrl(String displayName, Date startDate, Date endDate, String venue, String url) { - final String logoUrl = url != null ? url : EventHeaderResources.INSTANCE.defaultEventLogoImage().getSafeUri() - .asString(); - eventLogo.getStyle().setBackgroundImage("url(" + logoUrl + ")"); - eventLogo.setTitle(displayName); - eventDate.setInnerHTML(EventDatesFormatterUtil.formatDateRangeWithYear(startDate, endDate)); - eventVenue.setInnerText(venue); - // String venue = event.getLocationAndVenue(); - // if(event.getVenueCountry() != null && !event.getVenueCountry().isEmpty()) { - // venue += ", " + event.getVenueCountry(); - // } - } - - - -} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/eventheader/EventHeader.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/eventheader/EventHeader.ui.xml deleted file mode 100644 index c52daf22615..00000000000 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/eventheader/EventHeader.ui.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - -
-
-
-
-
-

- -

-
- -
-
-
- - -
-
-
-
- - \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/eventheader/EventHeaderResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/eventheader/EventHeaderResources.java deleted file mode 100644 index 80917fce370..00000000000 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/eventheader/EventHeaderResources.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.sap.sailing.gwt.regattaoverview.client.eventheader; - -import com.google.gwt.core.client.GWT; -import com.google.gwt.resources.client.ClientBundle; -import com.google.gwt.resources.client.CssResource; -import com.google.gwt.resources.client.ImageResource; - -public interface EventHeaderResources extends ClientBundle { - public static final EventHeaderResources INSTANCE = GWT.create(EventHeaderResources.class); - - @Source("EventHeader.gss") - LocalCss css(); - - public interface LocalCss extends CssResource { - String jsdropdown(); - String jsdropdown_head(); - String jsdropdown_content(); - String dropdown(); - String dropdown_head(); - String dropdown_head_title(); - String dropdown_head_title_button(); - String dropdown_content(); - String jsdropdownactive(); - String dropdown_content_link(); - String dropdown_content_link_title(); - String dropdown_content_link_subtitle(); - String dropdownregattas(); - String dropdownregattas_head(); - String dropdownregattas_head_title(); - String dropdownregattas_head_title_button(); - String dropdownregattas_content(); - String dropdownregattas_content_link(); - String dropdownregattas_content_linkactive(); - String dropdownregattas_content_link_title(); - String leaderboardquickaccess(); - String eventheader(); - String eventheader_breadcrumb(); - String eventheader_breadcrumbback(); - String eventheader_intro(); - String eventheader_intro_logo(); - String eventheader_intro_logo_image(); - String eventheader_intro_name(); - String eventheader_intro_details(); - String eventheader_intro_details_item(); - String eventheader_intro_details_itemlink(); - String eventheader_status(); - String eventheader_status_title(); - String eventheader_status_body(); - String locationicon(); - String eventnavigation(); - String eventnavigationnormal(); - String eventnavigation_dropdown(); - String eventnavigation_dropdown_toggle(); - String eventnavigation_dropdown_toggle_icon(); - String eventnavigation_dropdown_container(); - String eventnavigation_dropdown_containerhidden(); - String navbar_button(); - String navbar_buttonhidden(); - } - - @Source("com/sap/sailing/gwt/home/images/default_event_logo.jpg") - ImageResource defaultEventLogoImage(); - -} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/HomeServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java similarity index 100% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/HomeServiceImpl.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/HomeServiceUtil.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java similarity index 100% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/HomeServiceUtil.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/SourceAdminConsole.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/SourceAdminConsole.gwt.xml new file mode 100644 index 00000000000..d09180f5f37 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/SourceAdminConsole.gwt.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file From 146e8c1e7b2ba97fd7ff8e52dfa7b5084389567d Mon Sep 17 00:00:00 2001 From: Papick Garcia Taboada Date: Sat, 23 May 2015 03:17:18 +0200 Subject: [PATCH 03/72] Moved services out of client code packages --- .../main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java | 2 +- .../main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java | 2 +- .../ui/shared/dispatch/event/GetEventOverviewStageAction.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java index bac55591141..e316f94a1da 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java @@ -1,4 +1,4 @@ -package com.sap.sailing.gwt.home.server; +package com.sap.sailing.gwt.server; import java.net.MalformedURLException; import java.net.URL; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java index 34a202bcde9..496f852a088 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java @@ -1,4 +1,4 @@ -package com.sap.sailing.gwt.home.server; +package com.sap.sailing.gwt.server; import java.net.URL; import java.util.ArrayList; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java index 77be7e27766..8591ce2195e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java @@ -6,7 +6,7 @@ import java.util.UUID; import com.google.gwt.core.shared.GwtIncompatible; import com.sap.sailing.domain.base.Event; import com.sap.sailing.domain.common.media.MimeType; -import com.sap.sailing.gwt.home.server.HomeServiceUtil; +import com.sap.sailing.gwt.server.HomeServiceUtil; import com.sap.sailing.gwt.ui.shared.dispatch.Action; import com.sap.sailing.gwt.ui.shared.dispatch.DispatchContext; import com.sap.sailing.gwt.ui.shared.dispatch.ResultWithTTL; From 6d6b081a8d59be0e3333d30921dd53ea914ad59a Mon Sep 17 00:00:00 2001 From: Papick Garcia Taboada Date: Sat, 23 May 2015 03:43:09 +0200 Subject: [PATCH 04/72] Moved services out of client code packages --- java/com.sap.sailing.gwt.ui/WEB-INF/web.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/WEB-INF/web.xml b/java/com.sap.sailing.gwt.ui/WEB-INF/web.xml index c77ef3e8b06..3e00dc9e9cb 100755 --- a/java/com.sap.sailing.gwt.ui/WEB-INF/web.xml +++ b/java/com.sap.sailing.gwt.ui/WEB-INF/web.xml @@ -75,7 +75,7 @@ Home Service HomeService - com.sap.sailing.gwt.home.server.HomeServiceImpl + com.sap.sailing.gwt.server.HomeServiceImpl HomeService From 0ab2ec457e1abcce4af916d0a70805a26ffc60db Mon Sep 17 00:00:00 2001 From: Papick Garcia Taboada Date: Sat, 23 May 2015 03:53:43 +0200 Subject: [PATCH 05/72] Fixed source entry --- .../src/main/resources/com/sap/sailing/gwt/Home.gwt.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/Home.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/Home.gwt.xml index e8b8275b9ec..990a01dc90a 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/Home.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/Home.gwt.xml @@ -92,7 +92,7 @@ - + From 4f33b61b002284c2ff5377284de698be3583e0bf Mon Sep 17 00:00:00 2001 From: Papick Garcia Taboada Date: Sat, 23 May 2015 15:49:33 +0200 Subject: [PATCH 06/72] Bug 2882: fixed styles so that links are blue and have pointer cursor. Title elements are clickable if their couterparts in the columns where clickable --- .../client/RegattaOverviewPanel.java | 3 +- .../client/RegattaRaceStatesComponent.java | 153 ++++++++++++------ .../client/RegattaRaceStatesTable.css | 3 +- 3 files changed, 110 insertions(+), 49 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewPanel.java index a06217f470e..46fe03b9a73 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewPanel.java @@ -16,7 +16,6 @@ import com.google.gwt.user.client.ui.Anchor; import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.FlexTable; import com.google.gwt.user.client.ui.FlowPanel; -import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.TabPanel; import com.google.gwt.user.client.ui.VerticalPanel; @@ -67,7 +66,7 @@ public class RegattaOverviewPanel extends SimplePanel { private final Anchor startStopUpdatingButton; private final CheckBox leaderboardCheckBox; private final UserAgentDetails userAgent; - private final Label repeatedInfoLabel = new Label(); + private final FlowPanel repeatedInfoLabel = new FlowPanel(); private final RegattaOverviewResources.LocalCss style = RegattaOverviewResources.INSTANCE.css(); private final ThemeResources RES = ThemeResources.INSTANCE; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java index c9b0f4cb7cb..348428df003 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java @@ -31,12 +31,16 @@ import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler; import com.google.gwt.user.cellview.client.ColumnSortList; import com.google.gwt.user.cellview.client.ColumnSortList.ColumnSortInfo; import com.google.gwt.user.cellview.client.TextColumn; +import com.google.gwt.user.client.Command; +import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Anchor; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.DialogBox; +import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.Grid; import com.google.gwt.user.client.ui.HasHorizontalAlignment; +import com.google.gwt.user.client.ui.InlineLabel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.VerticalPanel; @@ -104,7 +108,7 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component private EntryHandler entryClickedHandler; private TextColumn courseAreaColumn; private Column regattaNameColumn; - private Label repeatedInfoLabel; + private FlowPanel repeatedInfoLabel; private Column raceCourseColumn; private TextColumn boatClass; private TextColumn startTimeColumn; @@ -180,7 +184,17 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component boolean canRemoveBoatClass = true; boolean canRemoveLastUpdate = true; boolean canRemoveProtestTime = true; + boolean isAppending = false; + RegattaOverviewEntryDTO firstEntry = null; for (RegattaOverviewEntryDTO entryDTO : allEntries) { + if (firstEntry == null) { + firstEntry = entryDTO; + } + if (lastRegattaName == null) { + lastRegattaName = entryDTO.regattaDisplayName; + } else if (canRemoveRegatta && !lastRegattaName.equals(entryDTO.regattaDisplayName)) { + canRemoveRegatta = false; + } if (canRemoveLastUpdate && timePassedInSeconds(entryDTO.raceInfo.lastUpdateTime) <= HIDE_COL_TIME_THRESHOLD) { canRemoveLastUpdate = false; } @@ -198,27 +212,40 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component } else if (canRemoveCourse && !lastCourseName.equals(entryDTO.raceInfo.lastCourseName)) { canRemoveCourse = false; } - if (lastRegattaName == null) { - lastRegattaName = entryDTO.regattaDisplayName; - } else if (canRemoveRegatta && !lastRegattaName.equals(entryDTO.regattaDisplayName)) { - canRemoveRegatta = false; - } + if (lastBoatClass == null) { lastBoatClass = entryDTO.boatClassName; } else if (canRemoveBoatClass && !lastBoatClass.equals(entryDTO.boatClassName)) { canRemoveBoatClass = false; } } - StringBuilder repeatedInfosBuilder = new StringBuilder(); - collectRepeatedInfos(stringMessages.regatta(), lastRegattaName, canRemoveRegatta, repeatedInfosBuilder); - collectRepeatedInfos(stringMessages.courseArea(), lastCourseAreaName, canRemoveCourseArea, repeatedInfosBuilder); - collectRepeatedInfos(stringMessages.course(), lastCourseName, canRemoveCourse, repeatedInfosBuilder); - collectRepeatedInfos(stringMessages.boatClass(), lastBoatClass, canRemoveBoatClass, repeatedInfosBuilder); - collectRepeatedInfos("", "", canRemoveLastUpdate, repeatedInfosBuilder); - collectRepeatedInfos("", "", canRemoveProtestTime, repeatedInfosBuilder); - if (repeatedInfoLabel != null) { - repeatedInfoLabel.setText(repeatedInfosBuilder.toString()); - } + final RegattaOverviewEntryDTO entryForRepeatedInfos = firstEntry; + repeatedInfoLabel.clear(); + isAppending = collectRepeatedInfos(stringMessages.regatta(), lastRegattaName, canRemoveRegatta, + repeatedInfoLabel, isAppending, new Command() { + @Override + public void execute() { + Window.open(createRegattaLink(entryForRepeatedInfos), "_blank", ""); + } + }); + // private boolean collectRepeatedInfos(String label, String info, + // boolean canRemove, FlowPanel panel, boolean append, + // final Command linkAction) { + isAppending = collectRepeatedInfos(stringMessages.courseArea(), lastCourseAreaName, canRemoveCourseArea, + repeatedInfoLabel, + isAppending, null); + isAppending = collectRepeatedInfos(stringMessages.course(), lastCourseName, canRemoveCourse, repeatedInfoLabel, + isAppending, new Command() { + @Override + public void execute() { + raceCourseClicked(entryForRepeatedInfos); + } + }); + isAppending = collectRepeatedInfos(stringMessages.boatClass(), lastBoatClass, canRemoveBoatClass, + repeatedInfoLabel, + isAppending, null); + isAppending = collectRepeatedInfos("", "", canRemoveLastUpdate, repeatedInfoLabel, isAppending, null); + isAppending = collectRepeatedInfos("", "", canRemoveProtestTime, repeatedInfoLabel, isAppending, null); LinkedList sortInfos = new LinkedList(); if (table != null) { ColumnSortList columnSortList = table.getColumnSortList(); @@ -288,13 +315,30 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component } } - private void collectRepeatedInfos(String label, String info, boolean canRemove, StringBuilder repeatedInfosBuilder) { + private boolean collectRepeatedInfos(String label, String info, boolean canRemove, FlowPanel panel, boolean append, + final Command linkAction) { if (canRemove && info != null && !info.isEmpty()) { - if (repeatedInfosBuilder.length() > 0) { - repeatedInfosBuilder.append(", "); + + if (append) { + panel.add(new InlineLabel(", ")); } - repeatedInfosBuilder.append(label).append(": ").append(info); + if (linkAction == null) { + panel.add(new InlineLabel(new StringBuilder(label).append(": ").append(info).toString())); + } else { + panel.add(new InlineLabel(new StringBuilder(label).append(": ").toString())); + Anchor anchor = new Anchor(info); + anchor.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + linkAction.execute(); + } + }); + panel.add(anchor); + + } + return true; } + return false; } protected void loadAndUpdateEventLog() { @@ -359,14 +403,12 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component regattaNameColumn = new Column(leaderboardAnchorCell) { @Override public Anchor getValue(RegattaOverviewEntryDTO entryDTO) { - Map leaderboardLinkParameters = new HashMap(); - leaderboardLinkParameters.put("name", entryDTO.regattaName); - leaderboardLinkParameters.put("showRaceDetails", String.valueOf(true)); - leaderboardLinkParameters.put("displayName", entryDTO.regattaDisplayName); - String leaderboardLink = EntryPointLinkFactory.createLeaderboardLink(leaderboardLinkParameters); + String leaderboardLink = createRegattaLink(entryDTO); Anchor result = new Anchor(entryDTO.regattaDisplayName, leaderboardLink); return result; } + + }; regattaNameColumn.setSortable(true); regattaOverviewListHandler.setComparator(regattaNameColumn, new Comparator() { @@ -395,21 +437,17 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component raceNameColumn = new Column(raceCell) { @Override public Anchor getValue(RegattaOverviewEntryDTO entryDTO) { - Anchor result = null; - if (entryDTO.raceInfo.raceIdentifier != null && entryDTO.raceInfo.isTracked) { - Map raceLinkParameters = new HashMap(); - raceLinkParameters.put("leaderboardName", entryDTO.regattaName); - raceLinkParameters.put("raceName", entryDTO.raceInfo.raceIdentifier.getRaceName()); - raceLinkParameters.put("canReplayDuringLiveRaces", "true"); - raceLinkParameters.put("regattaName", entryDTO.regattaName); - String raceBoardLink = EntryPointLinkFactory.createRaceBoardLink(raceLinkParameters); - result = new Anchor(entryDTO.raceInfo.raceName, raceBoardLink); - } else { - result = new Anchor(entryDTO.raceInfo.raceName); - result.setEnabled(false); + String raceBoardLink = createRaceLink(entryDTO); + String raceName = entryDTO.raceInfo.raceName; + Anchor result = new Anchor(raceName); + result.setEnabled(raceBoardLink != null); + if (raceBoardLink != null) { + result.setHref(raceBoardLink); } return result; } + + }; raceNameColumn.setSortable(true); regattaOverviewListHandler.setComparator(raceNameColumn, new Comparator() { @@ -490,14 +528,7 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component raceCourseColumn.setFieldUpdater(new FieldUpdater() { @Override public void update(int index, RegattaOverviewEntryDTO object, SafeHtml value) { - RaceCourseDTO courseDTO = object.raceInfo.lastCourseDesign; - if (courseDTO != null && courseDTO.waypoints.size() > 0) { - DialogBox courseViewDialogBox = createCourseViewDialogBox(object.raceInfo); - courseViewDialogBox.center(); - courseViewDialogBox.setGlassEnabled(true); - courseViewDialogBox.setAnimationEnabled(true); - courseViewDialogBox.show(); - } + raceCourseClicked(object); } }); // raceCourseColumn.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER); @@ -808,6 +839,17 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component return result; } + private void raceCourseClicked(RegattaOverviewEntryDTO object) { + RaceCourseDTO courseDTO = object.raceInfo.lastCourseDesign; + if (courseDTO != null && courseDTO.waypoints.size() > 0) { + DialogBox courseViewDialogBox = createCourseViewDialogBox(object.raceInfo); + courseViewDialogBox.center(); + courseViewDialogBox.setGlassEnabled(true); + courseViewDialogBox.setAnimationEnabled(true); + courseViewDialogBox.show(); + } + } + private String getPassingInstructionsAsText(PassingInstruction passingInstructions) { switch (passingInstructions) { case Port: @@ -836,7 +878,26 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component return "regattaRaceStates"; } - public void setRepeatedInfoLabel(Label repeatedInfoLabel) { + private String createRaceLink(RegattaOverviewEntryDTO entryDTO) { + if (entryDTO.raceInfo.raceIdentifier != null && entryDTO.raceInfo.isTracked) { + Map raceLinkParameters = new HashMap(); + raceLinkParameters.put("leaderboardName", entryDTO.regattaName); + raceLinkParameters.put("raceName", entryDTO.raceInfo.raceIdentifier.getRaceName()); + raceLinkParameters.put("canReplayDuringLiveRaces", "true"); + raceLinkParameters.put("regattaName", entryDTO.regattaName); + return EntryPointLinkFactory.createRaceBoardLink(raceLinkParameters); + } + return null; + } + private String createRegattaLink(RegattaOverviewEntryDTO entryDTO) { + Map leaderboardLinkParameters = new HashMap(); + leaderboardLinkParameters.put("name", entryDTO.regattaName); + leaderboardLinkParameters.put("showRaceDetails", String.valueOf(true)); + leaderboardLinkParameters.put("displayName", entryDTO.regattaDisplayName); + String leaderboardLink = EntryPointLinkFactory.createLeaderboardLink(leaderboardLinkParameters); + return leaderboardLink; + } + public void setRepeatedInfoLabel(FlowPanel repeatedInfoLabel) { this.repeatedInfoLabel = repeatedInfoLabel; } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesTable.css b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesTable.css index dde276c60fd..7a8e30b3821 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesTable.css +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesTable.css @@ -3,8 +3,9 @@ font-size:16px; } .cellTableWidget a { - color: black; + text-decoration: underline; + cursor: pointer; } From 2b6961cc645f112901f517c65577f56e39a7c456 Mon Sep 17 00:00:00 2001 From: Papick Garcia Taboada Date: Sat, 23 May 2015 17:20:16 +0200 Subject: [PATCH 07/72] Bug 2885: fixed sorting --- .../client/RegattaRaceStatesComponent.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java index 348428df003..37b9a89341e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java @@ -27,6 +27,7 @@ import com.google.gwt.safehtml.shared.SafeHtmlBuilder; import com.google.gwt.storage.client.Storage; import com.google.gwt.user.cellview.client.CellTable; import com.google.gwt.user.cellview.client.Column; +import com.google.gwt.user.cellview.client.ColumnSortEvent; import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler; import com.google.gwt.user.cellview.client.ColumnSortList; import com.google.gwt.user.cellview.client.ColumnSortList.ColumnSortInfo; @@ -287,6 +288,13 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component } table.addColumn(raceAdditionalInformationColumn, stringMessages.additionalInformation()); table.addColumnSortHandler(regattaOverviewListHandler); + regattaOverviewDataProvider.getList().clear(); + regattaOverviewDataProvider.getList().addAll(allEntries); + if (entryClickedHandler != null) { + for (RegattaOverviewEntryDTO entry : allEntries) { + entryClickedHandler.onEntryUpdated(entry); + } + } boolean isSortedOk = false; if (sortInfos.size() > 0) { GWT.log("Using existing sort info"); @@ -306,13 +314,7 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component ColumnSortInfo initialSortinfo = new ColumnSortInfo(courseAreaColumn, /* ascending */false); table.getColumnSortList().push(initialSortinfo); } - regattaOverviewDataProvider.getList().clear(); - regattaOverviewDataProvider.getList().addAll(allEntries); - if (entryClickedHandler != null) { - for (RegattaOverviewEntryDTO entry : allEntries) { - entryClickedHandler.onEntryUpdated(entry); - } - } + ColumnSortEvent.fire(table, table.getColumnSortList()); } private boolean collectRepeatedInfos(String label, String info, boolean canRemove, FlowPanel panel, boolean append, From 53ab729f8c47208302d8e8be5d49fef9e0fd920a Mon Sep 17 00:00:00 2001 From: Papick Garcia Taboada Date: Sat, 23 May 2015 20:50:05 +0200 Subject: [PATCH 08/72] Bug 2885: fixed memory leak --- .../regattaoverview/client/RegattaRaceStatesComponent.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java index 37b9a89341e..faaa936dd71 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java @@ -253,9 +253,14 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component for (int i = 0; i < columnSortList.size(); i++) { sortInfos.addFirst(columnSortList.get(i)); } + table.removeFromParent(); + while (table.getColumnCount() > 0) { + table.removeColumn(0); + } } table = new CellTable(/* pageSize */10000, tableRes); tableHolder.setWidget(table); + regattaOverviewDataProvider.getList().clear(); regattaOverviewDataProvider.addDataDisplay(table); table.setWidth("100%"); if (!canRemoveRegatta) { From 3c597bcf96606a74533d14bb0b272ff3b3ef3ab7 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Sun, 24 May 2015 17:32:16 +0200 Subject: [PATCH 09/72] Fixed Showing Leaderboards when switching between Regattas via EventHeader --- .../gwt/home/client/place/event/AbstractEventActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/AbstractEventActivity.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/AbstractEventActivity.java index 49f19a739f7..1bf3b410c4e 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/AbstractEventActivity.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/AbstractEventActivity.java @@ -117,7 +117,7 @@ public abstract class AbstractEventActivity ex } protected EventContext contextForRegatta(String regattaId) { - return new EventContext(ctx).withRegattaId(regattaId); + return new EventContext(ctx).withRegattaId(regattaId).withRegattaAnalyticsManager(null); } @Override From b5091a1f5d59838facd30380d51cf1a796dede51 Mon Sep 17 00:00:00 2001 From: Papick Garcia Taboada Date: Tue, 26 May 2015 14:02:04 +0200 Subject: [PATCH 10/72] Disabled single regatta overview tab --- .../place/event/regatta/tabs/RegattaOverviewTabView.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regatta/tabs/RegattaOverviewTabView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regatta/tabs/RegattaOverviewTabView.java index acfdb82eed4..9422074fdc5 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regatta/tabs/RegattaOverviewTabView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regatta/tabs/RegattaOverviewTabView.java @@ -15,7 +15,6 @@ import com.sap.sailing.gwt.home.client.place.event.regatta.RegattaTabView; import com.sap.sailing.gwt.home.client.place.event.regatta.tabs.reload.RefreshManager; import com.sap.sailing.gwt.ui.shared.dispatch.event.GetEventOverviewStageAction; import com.sap.sailing.gwt.ui.shared.dispatch.event.GetLiveRacesForRegattaAction; -import com.sap.sailing.gwt.ui.shared.eventview.EventViewDTO.EventType; /** * Created by pgtaboada on 25.11.14. @@ -32,8 +31,12 @@ public class RegattaOverviewTabView extends Composite implements RegattaTabView< @Override public TabView.State getState() { - return currentPresenter.getCtx().getEventDTO().getType() == EventType.MULTI_REGATTA ? TabView.State.NOT_AVAILABLE_SHOW_NEXT_AVAILABLE - : TabView.State.VISIBLE; + // Made not available until we have something to show + // TODO: implement backend and required UI + // return currentPresenter.getCtx().getEventDTO().getType() == EventType.MULTI_REGATTA ? + // TabView.State.NOT_AVAILABLE_SHOW_NEXT_AVAILABLE + // : TabView.State.VISIBLE; + return TabView.State.NOT_AVAILABLE_SHOW_NEXT_AVAILABLE; } @Override From 45d3fc8d4775bb604af302d4cd79aae9dd3ec959 Mon Sep 17 00:00:00 2001 From: Papick Garcia Taboada Date: Tue, 26 May 2015 14:20:18 +0200 Subject: [PATCH 11/72] Bug 2872: Make boat class icon a link to regatta --- .../client/place/event/partials/Regatta.java | 16 ++++++++++++++++ .../client/place/event/partials/Regatta.ui.xml | 4 ++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/Regatta.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/Regatta.java index ed1b6eb3225..8fc80fe07df 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/Regatta.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/Regatta.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.AnchorElement; import com.google.gwt.dom.client.DivElement; import com.google.gwt.dom.client.HeadingElement; import com.google.gwt.dom.client.SpanElement; @@ -13,6 +14,7 @@ import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.EventListener; import com.google.gwt.user.client.ui.Anchor; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.Image; @@ -68,6 +70,8 @@ public class Regatta extends Composite { @UiField Anchor regattaDetailsLink; @UiField Image boatClassImage; + @UiField + AnchorElement boatClassLinkUi; private Presenter presenter; @@ -83,6 +87,7 @@ public class Regatta extends Composite { RegattaResources.INSTANCE.css().ensureInjected(); initWidget(uiBinder.createAndBindUi(this)); + } public void setData(LeaderboardGroupDTO leaderboardGroup, boolean hasMultipleLeaderboardGroups, StrippedLeaderboardDTO leaderboard, @@ -95,6 +100,17 @@ public class Regatta extends Composite { } else { regattaNavigation = presenter.getRegattaNavigation(leaderboard.regattaName != null ? leaderboard.regattaName : leaderboard.name); regattaDetailsLink.setHref(regattaNavigation.getTargetUrl()); + boatClassLinkUi.setHref(regattaNavigation.getTargetUrl()); + Event.sinkEvents(boatClassLinkUi, Event.ONCLICK); + Event.setEventListener(boatClassLinkUi, new EventListener() { + @Override + public void onBrowserEvent(Event event) { + if (LinkUtil.handleLinkClick(event)) { + event.preventDefault(); + regattaNavigation.goToPlace(); + } + } + }); } boolean hasLiveRace = leaderboard.hasLiveRace(presenter.getTimerForClientServerOffset().getLiveTimePointInMillis()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/Regatta.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/Regatta.ui.xml index b3de40450a5..caa49a4963d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/Regatta.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/Regatta.ui.xml @@ -11,9 +11,9 @@
-
+ -
+
From 5b6560e9de85a9543dccd483f91d5b258ae36510 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 26 May 2015 10:12:29 +0200 Subject: [PATCH 12/72] Bug 2816: Changed many font-family declarations to use the new "Open Sans" @font-face --- .../com.sap.sailing.gwt.ui/CommonControls.css | 1841 +++++++++-------- java/com.sap.sailing.gwt.ui/DataMining.css | 13 +- java/com.sap.sailing.gwt.ui/Leaderboard.css | 12 +- .../LeaderboardNewHome.css | 10 +- java/com.sap.sailing.gwt.ui/PolarSheets.css | 12 +- java/com.sap.sailing.gwt.ui/RaceBoard.css | 15 +- .../com.sap.sailing.gwt.ui/SettingsDialog.css | 6 +- java/com.sap.sailing.gwt.ui/Simulator.css | 31 +- java/com.sap.sailing.gwt.ui/Spectator.css | 24 +- .../shared/racemap/RaceSimulationOverlay.java | 2 +- .../ui/simulator/PathLegendCanvasOverlay.java | 2 +- .../spectator/LeaderboardGroupFullTable.css | 123 +- 12 files changed, 1065 insertions(+), 1026 deletions(-) mode change 100755 => 100644 java/com.sap.sailing.gwt.ui/CommonControls.css diff --git a/java/com.sap.sailing.gwt.ui/CommonControls.css b/java/com.sap.sailing.gwt.ui/CommonControls.css old mode 100755 new mode 100644 index d476a4a7b31..a15efd6a2c7 --- a/java/com.sap.sailing.gwt.ui/CommonControls.css +++ b/java/com.sap.sailing.gwt.ui/CommonControls.css @@ -1,918 +1,925 @@ -@import url("SettingsDialog.css"); - -body ::-webkit-scrollbar { - width: 16px; - height: 10px; -} - -body ::-webkit-scrollbar-thumb { - min-height: 28px; - padding-top: 100px; - border-left: 6px solid transparent; - border-right: 1px solid transparent; - border-top: 0 solid transparent; - border-bottom: 0 solid transparent; - background-clip: padding-box; - background-color: rgba(0, 0, 0, 0.2); - -webkit-box-shadow: inset 1px 1px 0 rgba(0, 0, 0, 0.1), inset 0 -1px 0 - rgba(0, 0, 0, 0.07); -} - -body ::-webkit-scrollbar-button { - height: 0; - width: 0; -} - -body ::-webkit-scrollbar-track { - border-left: 6px solid transparent; - border-right: 1px solid transparent; -} - -.collapsablePanel { - background: #b6b6b6; - -webkit-border-radius: 5px; - -moz-border-radius: 5px; - -o-border-radius: 5px; - -ms-border-radius: 5px; - border-radius: 5px; - overflow: hidden; - border: 1px solid #aaaaaa; - margin: 0 0 15px 0; -} - -.collapsablePanel-content { - background: #fff; - margin: 12px; - -webkit-border-radius: 5px; - -moz-border-radius: 5px; - -o-border-radius: 5px; - -ms-border-radius: 5px; - border-radius: 5px; - width: auto !important; - border: 1px solid #aaaaaa; -} - -.collapsablePanel-header { - background: url(images/titlebar-background.png) 0 0 repeat-x; - padding: 0; - margin: 0; - height: 42px; - position: relative; - -webkit-border-top-left-radius: 4px; - -moz-border-top-left-radius: 4px; - -o-border-top-left-radius: 4px; - -ms-border-top-left-radius: 4px; - border-top-left-radius: 4px; - -webkit-border-top-right-radius: 4px; - -moz-border-top-right-radius: 4px; - -o-border-top-right-radius: 4px; - -ms-border-top-right-radius: 4px; - border-top-right-radius: 4px; -} - -.collapsablePanel:last-child { - margin-bottom: 0; -} - -.collapsablePanel-open { - -} - -.collapsablePanel-closed { - -} - -.collapsablePanel-header-text { - font-family: 'OpenSansSemiBold', Arial, Verdana, sans-serif; - text-transform: uppercase; - margin: 15px 0 0 13px; - float: left; -} - -.collapsablePanel-header-image { - float: left; - margin: 13px 0 0 0; -} - -.collapsablePanel-header-collapse { - height: 100%; - display: block; - padding: 0 0 0 10px; - color: #3b3b3b; -} - -.collapsablePanel-header-collapse:hover { - color: #3b3b3b; -} - -.collapsablePanel-toolbar { - position: absolute; - top: 0; - right: 0; - height: 43px; - width: 43px; - overflow: hidden; -} - -.collapsablePanel-toolbar table { - border-collapse: collapse; -} - -.collapsablePanel-toolbar a { - display: block; - padding: 9px; -} - -.breadcrumbPanel-NextArrow { - display: none; -} - -.breadcrumbPanel-ActiveBreadcrumb { - font-size: 18px; - font-family: 'OpenSansLight', Arial, Verdana, sans-serif; - margin: 5px 10px 0 0; -} - -.breadcrumbPanel-InactiveBreadcrumb { - font-size: 24px; -} - -.breadcrumbPanel-ActiveBreadcrumb a, .breadcrumbPanel-InactiveBreadcrumb a, - .breadcrumbPanel-NextArrow a { - color: #A1A1A1; -} - -.breadcrumbPanel-ActiveBreadcrumb, .breadcrumbPanel-InactiveBreadcrumb, - .breadcrumbPanel-NextArrow { - color: #A1A1A1; -} - -.gwt-ToggleButton { - background: url(images/btn-cta-orangeleft.png) center top repeat-x; - padding: 8px; - margin: 0 11px 0 0; - border: 0; -} - -.gwt-ToggleButton-down { - background: url(images/btn-cta-orangeleft.png) center -30px repeat-x; - color: #fff; -} - -.gwt-SplitLayoutPanel-NorthSouthToggleButton-Panel { - position: absolute; - right: 10px; - top: 3px; -} - -.gwt-SplitLayoutPanel-EastToggleButton-Panel { - position: absolute; - bottom: 77px; - margin-left: -35px; -} - -.gwt-SplitLayoutPanel-EastToggleButton { - height: 40px; - background-color: white; - border: none; - -webkit-transform: rotate(-90deg); - -moz-transform: rotate(-90deg); - -o-transform: rotate(-90deg); - -ms-transform: rotate(-90deg); - padding-right: 25px; - padding-left: 30px; - margin-left: -15px; - border-bottom: 1px solid #cecece; - border-right: 1px solid #cecece; - border-left: 1px solid #cecece; - border-bottom-right-radius: 10px; - border-bottom-left-radius: 10px; -} - -.gwt-SplitLayoutPanel-EastToggleButton-Open { - background: white url(images/arrows_top_black_small.png) 96% 50% - no-repeat; -} - -.gwt-SplitLayoutPanel-EastToggleButton-Closed { - background: white url(images/arrows_bottom_black_small.png) 96% 50% - no-repeat; -} - -.gwt-SplitLayoutPanel-EastToggleButton:hover { - background-color: #ececec; -} - -.gwt-SplitLayoutPanel-EastToggleButton:focus { - outline: 0 !important; -} - -.gwt-SplitLayoutPanel-NorthSouthToggleButton { - height: 33px; - background-color: #fff; - border: 1px solid #cecece; - margin-left: 5px; - padding: 2px 40px; - border-radius: 7px; - margin-top: 0px; -} - -.gwt-SplitLayoutPanel-NorthSouthToggleButton-Closed { - background: white url(images/arrows_top_black_small.png) 95% 50% - no-repeat; - font-weight: normal; -} - -.gwt-SplitLayoutPanel-NorthSouthToggleButton-Open { - background: white url(images/arrows_bottom_black_small.png) 95% 50% - no-repeat; - font-weight: bold; - border-width: 3px; -} - -.gwt-SplitLayoutPanel-NorthSouthToggleButton:focus { - outline: 0 !important; -} - -.gwt-SplitLayoutPanel-NorthSouthToggleButton:hover { - background-color: #ececec; -} - -.gwt-SplitLayoutPanel-HDragger { - position: absolute; - height: 60px !important; - width: 25px !important; - margin-left: 3px; - top: 40% !important; - background: #ffffff url(images/thumb_vertical.png) 70% 50% no-repeat; - border: 2px solid #cecece; - border-left: 0px; - cursor: col-resize; - border-top-right-radius: 25px; - border-bottom-right-radius: 25px; - z-index: 1; -} - -.SplitLayoutPanel-Divider-Horizontal { - background: #ffffff; -} - -.SplitLayoutPanel-Divider-Vertical { - background: #ffffff; - border-top: 1px solid #cecece; -} - -.gwt-SplitLayoutPanel-VDragger { - position: absolute; - width: 60px !important; - height: 21px !important; - left: 48% !important; - top: 2px !important; - background: #ffffff url(images/thumb_horz.png) 50% 30% no-repeat; - cursor: row-resize; - border: 2px solid #cecece; - border-bottom: 0px; - border-top-left-radius: 25px; - border-top-right-radius: 25px; - opacity: .7; - z-index: 1; -} - -.gwt-SplitLayoutPanel-CloseAndSettingsButton-Panel { - position: absolute; - right: 2px; - top: 2px; - z-index: 1; -} - -.gwt-SplitLayoutPanel-CloseButton { - margin-left: 10px; - border-top-left-radius: 25px; - border-top-right-radius: 25px; - border-bottom-left-radius: 25px; - border-bottom-right-radius: 25px; - background: white url(images/close_black.png) center no-repeat; - z-index: 1; - width: 28px; - height: 28px; - cursor: pointer; -} - -.gwt-SplitLayoutPanel-CloseButton:focus { - outline: 0 !important; -} - -.gwt-SplitLayoutPanel-CloseButton:hover { - background-color: #ececec; -} - -.gwt-SettingsButton { - border: none; - background: grey url(images/SAP_RV_Settings.png) center no-repeat; - z-index: 1; - width: 28px; - height: 28px; - cursor: pointer; -} - -.gwt-SettingsButton:hover { - background-color: #cecece; -} - -.gwt-SettingsButton:focus { - outline: 0 !important; -} - -.gwt-MapSettingsButton { - margin-right: 30px; - margin-top: 5px; - border-top-left-radius: 25px; - border-top-right-radius: 25px; - border-bottom-left-radius: 25px; - border-bottom-right-radius: 25px; - border: none; - background: white url(images/SAP_RV_SettingsBlack.png) center no-repeat; - z-index: 1; - width: 28px; - height: 28px; - cursor: pointer; -} - -.gwt-ToggleButton-up-hovering, .gwt-ToggleButton-down-hovering { - background: url(images/btn-cta-orangeleft-down.png) center top repeat-x; - color: #fff; -} - -.gwt-TabBar { - margin-top: 20px; - border-bottom: 1px solid #dedede; - margin-bottom: 10px; -} - -.gwt-TabBar .gwt-TabBarFirst { - width: 5px; /* first tab distance from the left */ -} - -.gwt-TabBar .gwt-TabBarRest { - -} - -.gwt-TabBar .gwt-TabBarItem { - margin-left: 4px; - padding: 10px 12px; - cursor: pointer; - cursor: hand; - color: black; - font-weight: normal; - text-align: center; - background: #ebebeb; - border-radius: 4px 4px 0px 0px; - border-left: 1px solid #dedede; - border-top: 1px solid #dedede; - border-right: 1px solid #dedede; -} - -.gwt-TabBarItem:FOCUS { - outline: none; -} - -.gwt-TabBar .gwt-TabBarItem-selected { - cursor: default; - background: white; - color: black; -} - -.gwt-TabBar .gwt-TabBarItem-disabled { - cursor: default; - color: #999999; -} - -.gwt-TabPanel { - -} - -.titleLabelWrapper { - position: absolute; - width: 100%; -} - -.titleLabel { - text-align: center; - font-family: 'OpenSansSemiBold', Arial, Verdana, sans-serif; - font-size: 18px; - color: #fff; - margin-top: 13px; -} - -.titleLabelRight { - text-align: right; - font-family: 'OpenSansSemiBold', Arial, Verdana, sans-serif; - font-size: 18px; - color: #fff; - margin-top: 13px; - margin-right: 12px; -} - -.subTitleLabelWrapper { - position: absolute; - min-width: 200px; - text-align: right; - height: 68px; - right: 0; - top: 0; - font-family: 'OpenSansSemiBold', Arial, Verdana, sans-serif; - font-size: 16px; - color: #fff; // - background: url(images/titleLabelWrapper.png) right center no-repeat; -} - -.subTitleLabel { - background: url(images/titleLabelInner.png) left center no-repeat; - height: 26px; - padding: 42px 7px 0 130px; -} - -.gwt-MenuBarPopup .menuPopupTopLeft { - background: none !important; -} - -.gwt-MenuBarPopup .menuPopupTopCenter { - background: none !important; -} - -.gwt-MenuBarPopup .menuPopupTopCenter { - background: none !important; -} - -.gwt-MenuBarPopup .menuPopupTopRight { - background: none !important; -} - -.gwt-MenuBarPopup .menuPopupMiddleLeft { - background: none !important; -} - -.gwt-MenuBarPopup .menuPopupMiddleRight { - background: none !important; -} - -.gwt-MenuBarPopup .menuPopupMiddleRight { - background: none !important; -} - -.gwt-MenuBarPopup .menuPopupBottomCenter { - background: none !important; -} - -.gwt-MenuBarPopup .menuPopupBottomRight { - background: none !important; -} - -.gwt-MenuBarPopup .menuPopupBottomLeft { - background: none !important; -} - -.gwt-MenuBar-vertical .gwt-MenuItem { - padding: 10px; - padding-bottom: 5px; - padding-top: 5px; -} - -.gwt-MenuBar .gwt-MenuItem-selected { - background: none repeat scroll 0 0 #efaa00; -} - -.dateBoxPopup { - z-Index: 2000; -} - -.timeLinePanel { - color: black; - width: 100%; - position: fixed; - bottom: 0; - z-index: 9; - background: #f6f6f6; - border-top: 2px solid #cecece; -} - -.timeLineInnerBgPanel { - -} - -.footerShadowPanel { - position: fixed; - height: 15px; - bottom: 0; - background: url(images/footer_shadow.png) left bottom repeat-x; - width: 100%; - z-index: 10; -} - -.timePanel-controls { - margin: 0; - padding: 7px 12px 0 12px; - height: 29px; -} - -.timePanel-controls-play { - float: left; - padding: 0 10px 0 0; - border-right: 1px solid #fcbb22; - height: 24px; - margin: 0 14px 0 0; -} - -.timePanel-timeslider-play { - float: left; - padding: 10px 4px; - height: 24px; - margin: 5px 14px 5px 0; -} - -.timePanel-controls-playSpeed { - vertical-align: middle; - line-height: 25px; - float: left; - padding: 0 14px 0 0; - margin: 0 14px 0 0; - border-right: 1px solid #fcbb22; - height: 24px; -} - -.timePanel-label { - float: left; -} - -.timePanel-controls-time { - float: left; - padding: 0 0 0 0; -} - -.timePanel-controls-time .dateLabel, .timePanel-controls-time .timeLabel - { - padding: 4px 20px 0 0; - float: left; -} - -.timePanel-controls-timeToStart { - float: left; - padding: 0 0 0 0; - border-left: 1px solid #fcbb22; -} - -.timePanel-controls-timeToStart .timeToStartLabel { - float: left; - padding: 4px 20px 0 20px; -} - -.timePanel-controls-timeDelay { - float: right; - margin: 0 50px 0 0; -} - -.timePanel-controls-playmode { - float: left; - padding: 0 14px 0 0; - margin: 0 14px 0 0; - height: 24px; - border-right: 1px solid #fcbb22; -} - -.timePanel-controls-playmode .playModeLabel { - padding: 4px 0 0 5px; -} - -.timePanelSettings { - float: right; -} - -.timePanelSlider { - margin: 0 12px; - height: 49px; - padding-top: 5px; -} - -.timePanelInnerWrapper { - -} - -.LogoAndTitlePanel { - height: 68px; - font-family: Arial, Verdana, sans-serif; - position: fixed; - width: 100%; - top: 0; - background-image: url(images/white_gradient_header.png), - url(images/header_bg_modern.png); - background-position: center top, 0 0; - background-repeat: no-repeat, repeat-x; - box-shadow: 0 0 20px #858585; - -moz-box-shadow: 0 0 20px #858585; - -webkit-box-shadow: 0 0 20px #858585; - -o-box-shadow: 0 0 20px #858585; - -ms-box-shadow: 0 0 20px #858585; - z-index: 1; -} - -.LogoAndTitlePanel:after { - content: " "; - display: block; - height: 0; - clear: both; - visibility: hidden; -} - -.globalNavigation { - position: absolute; - top: 0; - right: 0; -} - -.globalNavigation-Link, .globalNavigation-Link:visited { - font-family: OpenSansSemiBold, Verdana, Arial, sans-serif; - border: none; - display: inline-block; - padding: 2px 10px 4px; - color: #fff; - text-decoration: none; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; - border-radius: 5px; - -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); - -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); - text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.25); - border-bottom: 1px solid rgba(0, 0, 0, 0.25); - cursor: pointer; - height: 24px; - white-space: nowrap; -} - -.globalNavigation-Link:active { - top: 1px; - position: relative; - border: none; -} - -.globalNavigation-Link:hover { - background: url(images/btn-cta-orangeleft.png) center -30px repeat-x; - cursor: pointer; -} - -.globalNavigation-leaderBoardGroup a, .globalNavigation-home a { - background: url(images/globalNavigation-home_bg.png) 11px 8px no-repeat; -} - -.globalNavigation-leaderBoard a { - background: url(images/globalNavigation-leaderBoard_bg.png) 11px 8px - no-repeat; -} - -.globalNavigation-leaderBoardGroup, .globalNavigation-leaderBoard, - .globalNavigation-home { - margin: -4px 10px 0 0; - padding: 0px 0px 4px; - float: left; - background: #7c7b7c url(images/alert-overlay.png) repeat-x; -} - -.globalNavigation-leaderBoard { - margin-right: 5px; -} - -.globalNavigation-leaderBoardGroup a, .globalNavigation-leaderBoard a, - .globalNavigation-home a { - color: #fff; - text-decoration: none; - display: block; - padding: 8px 13px 6px 36px; -} - -.sapLogo { - float: left; - margin-top: 13px; - margin-left: 12px; -} - -.sailingAnalyticsLabelPanel { - margin: 10px 0 0 0; -} - -.sailingAnalyticsLabel { - float: left; - color: #fff; - font-size: 14px; - font-weight: bold; - margin: 15px 0 0 0; -} - -.gwt-DialogBox { - line-height: 1.4; - background-color: #cecece; - border: 1px solid #3e3e3e; - border-radius: 4px; - box-shadow: 0px 0px 10px 0px #3e3e3e; -} - -.gwt-PopupPanelGlass { - background-color: rgba(140, 140, 140, 0.5); -} - -.gwt-DialogBox .Caption { - font-size: 14px; - padding: 8px 10px; - background-color: #ededed; - border-bottom: 1px solid #3e3e3e; - font-family: OpenSansSemiBold, Verdana, Arial, sans-serif; -} - -.gwt-DialogBox .dialogContent { - background: #ffffff; - padding: 10px; -} - -.gwt-Button, .gwt-Button:visited { - font-size: 0, 9rem; - display: inline-block; - color: #fff; - border: none; - padding: 5px 10px; - border-radius: 4px; - background-color: #efaa00; - -webkit-transition: background-color 0.2s; - -moz-transition: background-color 0.2s; - transition: background-color 0.2s; - text-decoration: none; - cursor: pointer; -} - -.gwt-Button:active { - border: none; -} - -.gwt-Button:hover { - background-color: #d79900; - outline: none; - text-decoration: none; -} - -.gwt-Button[disabled] { - cursor: not-allowed; - background: #cfcfcf; -} - -.gwt-Button[disabled]:hover { - cursor: default; - background: #cfcfcf; - cursor: not-allowed; -} - -.gwt-Button[disabled]:active { - cursor: default; - background: #cfcfcf; - cursor: not-allowed; -} - -.gwt-ButtonLarge -.gwt-ButtonMedium -.gwt-ButtonSmall - -.gwt-DialogBox .boxPanel { - padding: 0 0 10px 0; -} - -.gwt-DialogBox .boxPanel:after { - display: inline-block; - content: " "; - display: block; - height: 0; - clear: both; - visibility: hidden; -} - -.gwt-DialogBox .settingsDialogLabel { - float: left; - padding: 3px 6px 0 0; -} - -.gwt-DialogBox .settingsDialogValue { - float: right; -} - -.gwt-DialogBox .additionalWidgets { - padding: 5px 0 0 0; - text-align: right; -} - -.gwt-DialogBox .gwt-Label { - line-height: 1.4; -} - -.timingSettings .dialogInnerContent { - padding: 0 9px 0 9px; -} - -.timingSettings .gwt-Label { - float: left; - padding: 0 10px 0 0; -} - -.helpPanel { - margin-top: 15px; -} - -.minMaxBackgroundBar { - left: 0px; - background-image: url(images/yellowBar.png); - background-position: left; - background-repeat: no-repeat; -} - -.minMaxBackgroundBarBad { - left: 0px; - background-image: url(images/redBar.png); - background-position: left; - background-repeat: no-repeat; -} - -.minMaxBackgroundBarGood { - left: 0px; - background-image: url(images/greenBar.png); - background-position: left; - background-repeat: no-repeat; -} - -.inlineButton { - height: 20px; - padding: 0px 10px 3px; - float: left; - background: #de8a2e url(images/alert-overlay.png) repeat-x; - font-family: OpenSansRegular, Arial, Verdana, sans-serif; -} - -.chartCloseButton { - cursor: pointer; - background: url(images/closeButton.png) right center no-repeat; - height: 18px; - width: 60px; - text-align: left; -} - -video { - max-width: 100%; - height: auto; -} - -.pointeredLink { -} - -.betterCheckboxCellSelected { - margin: 0px; - height: 18px; - width: 18px; - border: 1px; - background-color: #acacac; - vertical-align: middle; -} - -.betterCheckboxCellDeselected { - margin-left: 2px; - /* account for the selection border that pushes a selected checkbox to the side */ - margin-top: 0px; - margin-bottom: 0px; - margin-right: 0px; - border: 1px; - height: 18px; - width: 18px; - vertical-align: middle; -} - -.LeaderboardPanel-FilterControl-Panel { - width: 380px; - border-top: 1px solid #ececec; - margin-top: 3px; -} - -.LeaderboardPanel-FilterClear-Button { - margin-top: 2px; - font-size: 10px; - outline: 0; - height: 23px; - background-color: #fff; - border: 1px solid #cecece; - border-radius: 7px; -} - -.LeaderboardPanel-FilterClear-Button:hover { - background-color: #ececec; -} - -.LeaderboardPanel-FilterControl-StatusLabel { - padding: 8px 2px; - font-size: 10px; -} - -label { - padding-left: 4px; +@import url("SettingsDialog.css"); + +body ::-webkit-scrollbar { + width: 16px; + height: 10px; +} + +body ::-webkit-scrollbar-thumb { + min-height: 28px; + padding-top: 100px; + border-left: 6px solid transparent; + border-right: 1px solid transparent; + border-top: 0 solid transparent; + border-bottom: 0 solid transparent; + background-clip: padding-box; + background-color: rgba(0, 0, 0, 0.2); + -webkit-box-shadow: inset 1px 1px 0 rgba(0, 0, 0, 0.1), inset 0 -1px 0 + rgba(0, 0, 0, 0.07); +} + +body ::-webkit-scrollbar-button { + height: 0; + width: 0; +} + +body ::-webkit-scrollbar-track { + border-left: 6px solid transparent; + border-right: 1px solid transparent; +} + +.collapsablePanel { + background: #b6b6b6; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + -o-border-radius: 5px; + -ms-border-radius: 5px; + border-radius: 5px; + overflow: hidden; + border: 1px solid #aaaaaa; + margin: 0 0 15px 0; +} + +.collapsablePanel-content { + background: #fff; + margin: 12px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + -o-border-radius: 5px; + -ms-border-radius: 5px; + border-radius: 5px; + width: auto !important; + border: 1px solid #aaaaaa; +} + +.collapsablePanel-header { + background: url(images/titlebar-background.png) 0 0 repeat-x; + padding: 0; + margin: 0; + height: 42px; + position: relative; + -webkit-border-top-left-radius: 4px; + -moz-border-top-left-radius: 4px; + -o-border-top-left-radius: 4px; + -ms-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + -moz-border-top-right-radius: 4px; + -o-border-top-right-radius: 4px; + -ms-border-top-right-radius: 4px; + border-top-right-radius: 4px; +} + +.collapsablePanel:last-child { + margin-bottom: 0; +} + +.collapsablePanel-open { + +} + +.collapsablePanel-closed { + +} + +.collapsablePanel-header-text { + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 600; + text-transform: uppercase; + margin: 15px 0 0 13px; + float: left; +} + +.collapsablePanel-header-image { + float: left; + margin: 13px 0 0 0; +} + +.collapsablePanel-header-collapse { + height: 100%; + display: block; + padding: 0 0 0 10px; + color: #3b3b3b; +} + +.collapsablePanel-header-collapse:hover { + color: #3b3b3b; +} + +.collapsablePanel-toolbar { + position: absolute; + top: 0; + right: 0; + height: 43px; + width: 43px; + overflow: hidden; +} + +.collapsablePanel-toolbar table { + border-collapse: collapse; +} + +.collapsablePanel-toolbar a { + display: block; + padding: 9px; +} + +.breadcrumbPanel-NextArrow { + display: none; +} + +.breadcrumbPanel-ActiveBreadcrumb { + font-size: 18px; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 300; + margin: 5px 10px 0 0; +} + +.breadcrumbPanel-InactiveBreadcrumb { + font-size: 24px; +} + +.breadcrumbPanel-ActiveBreadcrumb a, .breadcrumbPanel-InactiveBreadcrumb a, + .breadcrumbPanel-NextArrow a { + color: #A1A1A1; +} + +.breadcrumbPanel-ActiveBreadcrumb, .breadcrumbPanel-InactiveBreadcrumb, + .breadcrumbPanel-NextArrow { + color: #A1A1A1; +} + +.gwt-ToggleButton { + background: url(images/btn-cta-orangeleft.png) center top repeat-x; + padding: 8px; + margin: 0 11px 0 0; + border: 0; +} + +.gwt-ToggleButton-down { + background: url(images/btn-cta-orangeleft.png) center -30px repeat-x; + color: #fff; +} + +.gwt-SplitLayoutPanel-NorthSouthToggleButton-Panel { + position: absolute; + right: 10px; + top: 3px; +} + +.gwt-SplitLayoutPanel-EastToggleButton-Panel { + position: absolute; + bottom: 77px; + margin-left: -35px; +} + +.gwt-SplitLayoutPanel-EastToggleButton { + height: 40px; + background-color: white; + border: none; + -webkit-transform: rotate(-90deg); + -moz-transform: rotate(-90deg); + -o-transform: rotate(-90deg); + -ms-transform: rotate(-90deg); + padding-right: 25px; + padding-left: 30px; + margin-left: -15px; + border-bottom: 1px solid #cecece; + border-right: 1px solid #cecece; + border-left: 1px solid #cecece; + border-bottom-right-radius: 10px; + border-bottom-left-radius: 10px; +} + +.gwt-SplitLayoutPanel-EastToggleButton-Open { + background: white url(images/arrows_top_black_small.png) 96% 50% + no-repeat; +} + +.gwt-SplitLayoutPanel-EastToggleButton-Closed { + background: white url(images/arrows_bottom_black_small.png) 96% 50% + no-repeat; +} + +.gwt-SplitLayoutPanel-EastToggleButton:hover { + background-color: #ececec; +} + +.gwt-SplitLayoutPanel-EastToggleButton:focus { + outline: 0 !important; +} + +.gwt-SplitLayoutPanel-NorthSouthToggleButton { + height: 33px; + background-color: #fff; + border: 1px solid #cecece; + margin-left: 5px; + padding: 2px 40px; + border-radius: 7px; + margin-top: 0px; +} + +.gwt-SplitLayoutPanel-NorthSouthToggleButton-Closed { + background: white url(images/arrows_top_black_small.png) 95% 50% + no-repeat; + font-weight: normal; +} + +.gwt-SplitLayoutPanel-NorthSouthToggleButton-Open { + background: white url(images/arrows_bottom_black_small.png) 95% 50% + no-repeat; + font-weight: bold; + border-width: 3px; +} + +.gwt-SplitLayoutPanel-NorthSouthToggleButton:focus { + outline: 0 !important; +} + +.gwt-SplitLayoutPanel-NorthSouthToggleButton:hover { + background-color: #ececec; +} + +.gwt-SplitLayoutPanel-HDragger { + position: absolute; + height: 60px !important; + width: 25px !important; + margin-left: 3px; + top: 40% !important; + background: #ffffff url(images/thumb_vertical.png) 70% 50% no-repeat; + border: 2px solid #cecece; + border-left: 0px; + cursor: col-resize; + border-top-right-radius: 25px; + border-bottom-right-radius: 25px; + z-index: 1; +} + +.SplitLayoutPanel-Divider-Horizontal { + background: #ffffff; +} + +.SplitLayoutPanel-Divider-Vertical { + background: #ffffff; + border-top: 1px solid #cecece; +} + +.gwt-SplitLayoutPanel-VDragger { + position: absolute; + width: 60px !important; + height: 21px !important; + left: 48% !important; + top: 2px !important; + background: #ffffff url(images/thumb_horz.png) 50% 30% no-repeat; + cursor: row-resize; + border: 2px solid #cecece; + border-bottom: 0px; + border-top-left-radius: 25px; + border-top-right-radius: 25px; + opacity: .7; + z-index: 1; +} + +.gwt-SplitLayoutPanel-CloseAndSettingsButton-Panel { + position: absolute; + right: 2px; + top: 2px; + z-index: 1; +} + +.gwt-SplitLayoutPanel-CloseButton { + margin-left: 10px; + border-top-left-radius: 25px; + border-top-right-radius: 25px; + border-bottom-left-radius: 25px; + border-bottom-right-radius: 25px; + background: white url(images/close_black.png) center no-repeat; + z-index: 1; + width: 28px; + height: 28px; + cursor: pointer; +} + +.gwt-SplitLayoutPanel-CloseButton:focus { + outline: 0 !important; +} + +.gwt-SplitLayoutPanel-CloseButton:hover { + background-color: #ececec; +} + +.gwt-SettingsButton { + border: none; + background: grey url(images/SAP_RV_Settings.png) center no-repeat; + z-index: 1; + width: 28px; + height: 28px; + cursor: pointer; +} + +.gwt-SettingsButton:hover { + background-color: #cecece; +} + +.gwt-SettingsButton:focus { + outline: 0 !important; +} + +.gwt-MapSettingsButton { + margin-right: 30px; + margin-top: 5px; + border-top-left-radius: 25px; + border-top-right-radius: 25px; + border-bottom-left-radius: 25px; + border-bottom-right-radius: 25px; + border: none; + background: white url(images/SAP_RV_SettingsBlack.png) center no-repeat; + z-index: 1; + width: 28px; + height: 28px; + cursor: pointer; +} + +.gwt-ToggleButton-up-hovering, .gwt-ToggleButton-down-hovering { + background: url(images/btn-cta-orangeleft-down.png) center top repeat-x; + color: #fff; +} + +.gwt-TabBar { + margin-top: 20px; + border-bottom: 1px solid #dedede; + margin-bottom: 10px; +} + +.gwt-TabBar .gwt-TabBarFirst { + width: 5px; /* first tab distance from the left */ +} + +.gwt-TabBar .gwt-TabBarRest { + +} + +.gwt-TabBar .gwt-TabBarItem { + margin-left: 4px; + padding: 10px 12px; + cursor: pointer; + cursor: hand; + color: black; + font-weight: normal; + text-align: center; + background: #ebebeb; + border-radius: 4px 4px 0px 0px; + border-left: 1px solid #dedede; + border-top: 1px solid #dedede; + border-right: 1px solid #dedede; +} + +.gwt-TabBarItem:FOCUS { + outline: none; +} + +.gwt-TabBar .gwt-TabBarItem-selected { + cursor: default; + background: white; + color: black; +} + +.gwt-TabBar .gwt-TabBarItem-disabled { + cursor: default; + color: #999999; +} + +.gwt-TabPanel { + +} + +.titleLabelWrapper { + position: absolute; + width: 100%; +} + +.titleLabel { + text-align: center; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 600; + font-size: 18px; + color: #fff; + margin-top: 13px; +} + +.titleLabelRight { + text-align: right; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 600; + font-size: 18px; + color: #fff; + margin-top: 13px; + margin-right: 12px; +} + +.subTitleLabelWrapper { + position: absolute; + min-width: 200px; + text-align: right; + height: 68px; + right: 0; + top: 0; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 600; + font-size: 16px; + color: #fff; // + background: url(images/titleLabelWrapper.png) right center no-repeat; +} + +.subTitleLabel { + background: url(images/titleLabelInner.png) left center no-repeat; + height: 26px; + padding: 42px 7px 0 130px; +} + +.gwt-MenuBarPopup .menuPopupTopLeft { + background: none !important; +} + +.gwt-MenuBarPopup .menuPopupTopCenter { + background: none !important; +} + +.gwt-MenuBarPopup .menuPopupTopCenter { + background: none !important; +} + +.gwt-MenuBarPopup .menuPopupTopRight { + background: none !important; +} + +.gwt-MenuBarPopup .menuPopupMiddleLeft { + background: none !important; +} + +.gwt-MenuBarPopup .menuPopupMiddleRight { + background: none !important; +} + +.gwt-MenuBarPopup .menuPopupMiddleRight { + background: none !important; +} + +.gwt-MenuBarPopup .menuPopupBottomCenter { + background: none !important; +} + +.gwt-MenuBarPopup .menuPopupBottomRight { + background: none !important; +} + +.gwt-MenuBarPopup .menuPopupBottomLeft { + background: none !important; +} + +.gwt-MenuBar-vertical .gwt-MenuItem { + padding: 10px; + padding-bottom: 5px; + padding-top: 5px; +} + +.gwt-MenuBar .gwt-MenuItem-selected { + background: none repeat scroll 0 0 #efaa00; +} + +.dateBoxPopup { + z-Index: 2000; +} + +.timeLinePanel { + color: black; + width: 100%; + position: fixed; + bottom: 0; + z-index: 9; + background: #f6f6f6; + border-top: 2px solid #cecece; +} + +.timeLineInnerBgPanel { + +} + +.footerShadowPanel { + position: fixed; + height: 15px; + bottom: 0; + background: url(images/footer_shadow.png) left bottom repeat-x; + width: 100%; + z-index: 10; +} + +.timePanel-controls { + margin: 0; + padding: 7px 12px 0 12px; + height: 29px; +} + +.timePanel-controls-play { + float: left; + padding: 0 10px 0 0; + border-right: 1px solid #fcbb22; + height: 24px; + margin: 0 14px 0 0; +} + +.timePanel-timeslider-play { + float: left; + padding: 10px 4px; + height: 24px; + margin: 5px 14px 5px 0; +} + +.timePanel-controls-playSpeed { + vertical-align: middle; + line-height: 25px; + float: left; + padding: 0 14px 0 0; + margin: 0 14px 0 0; + border-right: 1px solid #fcbb22; + height: 24px; +} + +.timePanel-label { + float: left; +} + +.timePanel-controls-time { + float: left; + padding: 0 0 0 0; +} + +.timePanel-controls-time .dateLabel, .timePanel-controls-time .timeLabel + { + padding: 4px 20px 0 0; + float: left; +} + +.timePanel-controls-timeToStart { + float: left; + padding: 0 0 0 0; + border-left: 1px solid #fcbb22; +} + +.timePanel-controls-timeToStart .timeToStartLabel { + float: left; + padding: 4px 20px 0 20px; +} + +.timePanel-controls-timeDelay { + float: right; + margin: 0 50px 0 0; +} + +.timePanel-controls-playmode { + float: left; + padding: 0 14px 0 0; + margin: 0 14px 0 0; + height: 24px; + border-right: 1px solid #fcbb22; +} + +.timePanel-controls-playmode .playModeLabel { + padding: 4px 0 0 5px; +} + +.timePanelSettings { + float: right; +} + +.timePanelSlider { + margin: 0 12px; + height: 49px; + padding-top: 5px; +} + +.timePanelInnerWrapper { + +} + +.LogoAndTitlePanel { + height: 68px; + font-family: Arial, Verdana, sans-serif; + position: fixed; + width: 100%; + top: 0; + background-image: url(images/white_gradient_header.png), + url(images/header_bg_modern.png); + background-position: center top, 0 0; + background-repeat: no-repeat, repeat-x; + box-shadow: 0 0 20px #858585; + -moz-box-shadow: 0 0 20px #858585; + -webkit-box-shadow: 0 0 20px #858585; + -o-box-shadow: 0 0 20px #858585; + -ms-box-shadow: 0 0 20px #858585; + z-index: 1; +} + +.LogoAndTitlePanel:after { + content: " "; + display: block; + height: 0; + clear: both; + visibility: hidden; +} + +.globalNavigation { + position: absolute; + top: 0; + right: 0; +} + +.globalNavigation-Link, .globalNavigation-Link:visited { + font-family: 'Open Sans', Verdana, Arial, sans-serif; + font-weight: 600; + border: none; + display: inline-block; + padding: 2px 10px 4px; + color: #fff; + text-decoration: none; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); + text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.25); + border-bottom: 1px solid rgba(0, 0, 0, 0.25); + cursor: pointer; + height: 24px; + white-space: nowrap; +} + +.globalNavigation-Link:active { + top: 1px; + position: relative; + border: none; +} + +.globalNavigation-Link:hover { + background: url(images/btn-cta-orangeleft.png) center -30px repeat-x; + cursor: pointer; +} + +.globalNavigation-leaderBoardGroup a, .globalNavigation-home a { + background: url(images/globalNavigation-home_bg.png) 11px 8px no-repeat; +} + +.globalNavigation-leaderBoard a { + background: url(images/globalNavigation-leaderBoard_bg.png) 11px 8px + no-repeat; +} + +.globalNavigation-leaderBoardGroup, .globalNavigation-leaderBoard, + .globalNavigation-home { + margin: -4px 10px 0 0; + padding: 0px 0px 4px; + float: left; + background: #7c7b7c url(images/alert-overlay.png) repeat-x; +} + +.globalNavigation-leaderBoard { + margin-right: 5px; +} + +.globalNavigation-leaderBoardGroup a, .globalNavigation-leaderBoard a, + .globalNavigation-home a { + color: #fff; + text-decoration: none; + display: block; + padding: 8px 13px 6px 36px; +} + +.sapLogo { + float: left; + margin-top: 13px; + margin-left: 12px; +} + +.sailingAnalyticsLabelPanel { + margin: 10px 0 0 0; +} + +.sailingAnalyticsLabel { + float: left; + color: #fff; + font-size: 14px; + font-weight: bold; + margin: 15px 0 0 0; +} + +.gwt-DialogBox { + line-height: 1.4; + background-color: #cecece; + border: 1px solid #3e3e3e; + border-radius: 4px; + box-shadow: 0px 0px 10px 0px #3e3e3e; +} + +.gwt-PopupPanelGlass { + background-color: rgba(140, 140, 140, 0.5); +} + +.gwt-DialogBox .Caption { + font-size: 14px; + padding: 8px 10px; + background-color: #ededed; + border-bottom: 1px solid #3e3e3e; + font-family: 'Open Sans', Verdana, Arial, sans-serif; + font-weight: 600; +} + +.gwt-DialogBox .dialogContent { + background: #ffffff; + padding: 10px; +} + +.gwt-Button, .gwt-Button:visited { + font-size: 0, 9rem; + display: inline-block; + color: #fff; + border: none; + padding: 5px 10px; + border-radius: 4px; + background-color: #efaa00; + -webkit-transition: background-color 0.2s; + -moz-transition: background-color 0.2s; + transition: background-color 0.2s; + text-decoration: none; + cursor: pointer; +} + +.gwt-Button:active { + border: none; +} + +.gwt-Button:hover { + background-color: #d79900; + outline: none; + text-decoration: none; +} + +.gwt-Button[disabled] { + cursor: not-allowed; + background: #cfcfcf; +} + +.gwt-Button[disabled]:hover { + cursor: default; + background: #cfcfcf; + cursor: not-allowed; +} + +.gwt-Button[disabled]:active { + cursor: default; + background: #cfcfcf; + cursor: not-allowed; +} + +.gwt-ButtonLarge +.gwt-ButtonMedium +.gwt-ButtonSmall + +.gwt-DialogBox .boxPanel { + padding: 0 0 10px 0; +} + +.gwt-DialogBox .boxPanel:after { + display: inline-block; + content: " "; + display: block; + height: 0; + clear: both; + visibility: hidden; +} + +.gwt-DialogBox .settingsDialogLabel { + float: left; + padding: 3px 6px 0 0; +} + +.gwt-DialogBox .settingsDialogValue { + float: right; +} + +.gwt-DialogBox .additionalWidgets { + padding: 5px 0 0 0; + text-align: right; +} + +.gwt-DialogBox .gwt-Label { + line-height: 1.4; +} + +.timingSettings .dialogInnerContent { + padding: 0 9px 0 9px; +} + +.timingSettings .gwt-Label { + float: left; + padding: 0 10px 0 0; +} + +.helpPanel { + margin-top: 15px; +} + +.minMaxBackgroundBar { + left: 0px; + background-image: url(images/yellowBar.png); + background-position: left; + background-repeat: no-repeat; +} + +.minMaxBackgroundBarBad { + left: 0px; + background-image: url(images/redBar.png); + background-position: left; + background-repeat: no-repeat; +} + +.minMaxBackgroundBarGood { + left: 0px; + background-image: url(images/greenBar.png); + background-position: left; + background-repeat: no-repeat; +} + +.inlineButton { + height: 20px; + padding: 0px 10px 3px; + float: left; + background: #de8a2e url(images/alert-overlay.png) repeat-x; + font-family: 'Open Sans', Arial, Verdana, sans-serif; +} + +.chartCloseButton { + cursor: pointer; + background: url(images/closeButton.png) right center no-repeat; + height: 18px; + width: 60px; + text-align: left; +} + +video { + max-width: 100%; + height: auto; +} + +.pointeredLink { +} + +.betterCheckboxCellSelected { + margin: 0px; + height: 18px; + width: 18px; + border: 1px; + background-color: #acacac; + vertical-align: middle; +} + +.betterCheckboxCellDeselected { + margin-left: 2px; + /* account for the selection border that pushes a selected checkbox to the side */ + margin-top: 0px; + margin-bottom: 0px; + margin-right: 0px; + border: 1px; + height: 18px; + width: 18px; + vertical-align: middle; +} + +.LeaderboardPanel-FilterControl-Panel { + width: 380px; + border-top: 1px solid #ececec; + margin-top: 3px; +} + +.LeaderboardPanel-FilterClear-Button { + margin-top: 2px; + font-size: 10px; + outline: 0; + height: 23px; + background-color: #fff; + border: 1px solid #cecece; + border-radius: 7px; +} + +.LeaderboardPanel-FilterClear-Button:hover { + background-color: #ececec; +} + +.LeaderboardPanel-FilterControl-StatusLabel { + padding: 8px 2px; + font-size: 10px; +} + +label { + padding-left: 4px; } \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/DataMining.css b/java/com.sap.sailing.gwt.ui/DataMining.css index 06a7d5b3111..3706c2632b7 100644 --- a/java/com.sap.sailing.gwt.ui/DataMining.css +++ b/java/com.sap.sailing.gwt.ui/DataMining.css @@ -26,7 +26,7 @@ body { background: url(images/spectatorview-bg.png) no-repeat left top #ebebeb; - font-family: 'OpenSansRegular', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; line-height: 1; font-size: 14px; font-weight: 400; @@ -42,7 +42,7 @@ a { table td,select,button { line-height: 1; - font-family: 'OpenSansRegular', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; font-size: 14px; } @@ -161,7 +161,8 @@ input.magnifier { } .chart-importantMessage { - font-family: 'OpenSansSemiBold',Arial,Verdana,sans-serif; + font-family: 'Open Sans',Arial,Verdana,sans-serif; + font-weight: 600; font-size: 20px; height: 70px; margin: 0 auto; @@ -172,7 +173,8 @@ input.magnifier { } .chart-busyMessage { - font-family: 'OpenSansSemiBold',Arial,Verdana,sans-serif; + font-family: 'Open Sans',Arial,Verdana,sans-serif; + font-weight: 600; font-size: 20px; height: 70px; margin: 0 auto; @@ -193,7 +195,8 @@ input.magnifier { border-top-left-radius: 3px; color: #FFFFFF; cursor: pointer; - font-family: OpenSansSemiBold,Verdana,Arial,sans-serif; + font-family: 'Open Sans',Verdana,Arial,sans-serif; + font-weight: 600; font-size: 14px; margin: 0 0 0 0; padding: 2px 7px 2px 3px; diff --git a/java/com.sap.sailing.gwt.ui/Leaderboard.css b/java/com.sap.sailing.gwt.ui/Leaderboard.css index ef8a65d5c8f..d879341d76d 100755 --- a/java/com.sap.sailing.gwt.ui/Leaderboard.css +++ b/java/com.sap.sailing.gwt.ui/Leaderboard.css @@ -24,7 +24,7 @@ body { background: #fff; - font-family: 'OpenSansRegular', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; line-height: 1; font-size: 14px; font-weight: 400; @@ -81,7 +81,8 @@ input.magnifier{ } body, table td, select, button { - font-family: 'OpenSansLight', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 300; font-size: 14px; } @@ -90,7 +91,8 @@ body, table td, select, button { } .abstractChartPanel-importantMessageOfChart { - font-family: 'OpenSansBold',Arial,Verdana,sans-serif; + font-family: 'Open Sans',Arial,Verdana,sans-serif; + font-weight: bold; font-size: 20px; height: 70px; margin: 0 auto; @@ -105,7 +107,7 @@ body, table td, select, button { margin: 0 auto; width: 400px; text-align: center; - font-family: 'OpenSansRegular', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; font-size: 18px; color: #fff; margin-top: 22px; @@ -113,7 +115,7 @@ body, table td, select, button { .leaderboardHeading { font-size: 16px; - font-family: 'OpenSansRegular', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; font-weight: bold; } diff --git a/java/com.sap.sailing.gwt.ui/LeaderboardNewHome.css b/java/com.sap.sailing.gwt.ui/LeaderboardNewHome.css index 83ea7d43ca9..fdff2cf102d 100644 --- a/java/com.sap.sailing.gwt.ui/LeaderboardNewHome.css +++ b/java/com.sap.sailing.gwt.ui/LeaderboardNewHome.css @@ -36,7 +36,8 @@ input.magnifier{ } body, table td, select, button { - font-family: 'OpenSansLight', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 300; font-size: 14px; } @@ -45,7 +46,8 @@ body, table td, select, button { } .abstractChartPanel-importantMessageOfChart { - font-family: 'OpenSansBold',Arial,Verdana,sans-serif; + font-family: 'Open Sans',Arial,Verdana,sans-serif; + font-weight: bold; font-size: 20px; height: 70px; margin: 0 auto; @@ -60,7 +62,7 @@ body, table td, select, button { margin: 0 auto; width: 400px; text-align: center; - font-family: 'OpenSansRegular', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; font-size: 18px; color: #fff; margin-top: 22px; @@ -68,7 +70,7 @@ body, table td, select, button { .leaderboardHeading { font-size: 16px; - font-family: 'OpenSansRegular', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; font-weight: bold; } diff --git a/java/com.sap.sailing.gwt.ui/PolarSheets.css b/java/com.sap.sailing.gwt.ui/PolarSheets.css index c419d2c8cd5..e94192e52cb 100644 --- a/java/com.sap.sailing.gwt.ui/PolarSheets.css +++ b/java/com.sap.sailing.gwt.ui/PolarSheets.css @@ -24,7 +24,7 @@ body { background: #fff; - font-family: 'OpenSansRegular', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; line-height: 1; font-size: 14px; font-weight: 400; @@ -85,7 +85,8 @@ input.magnifier{ } body, table td, select, button { - font-family: 'OpenSansLight', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 300; font-size: 14px; } @@ -94,7 +95,8 @@ body, table td, select, button { } .abstractChartPanel-importantMessageOfChart { - font-family: 'OpenSansSemiBold',Arial,Verdana,sans-serif; + font-family: 'Open Sans',Arial,Verdana,sans-serif; + font-weight: 600; font-size: 20px; height: 70px; margin: 0 auto; @@ -109,7 +111,7 @@ body, table td, select, button { margin: 0 auto; width: 400px; text-align: center; - font-family: 'OpenSansRegular', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; font-size: 18px; color: #fff; margin-top: 22px; @@ -117,7 +119,7 @@ body, table td, select, button { .leaderboardHeading { font-size: 16px; - font-family: 'OpenSansRegular', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; font-weight: bold; } diff --git a/java/com.sap.sailing.gwt.ui/RaceBoard.css b/java/com.sap.sailing.gwt.ui/RaceBoard.css index 00bbc007faf..66051c30350 100644 --- a/java/com.sap.sailing.gwt.ui/RaceBoard.css +++ b/java/com.sap.sailing.gwt.ui/RaceBoard.css @@ -142,13 +142,15 @@ img.openColumn { .raceBoardNavigation { float: left; margin: 9px 0 0 12px; - font-family: 'OpenSansLight', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 300; } .raceBoardControls { float: right; margin: 9px 0 0 12px; - font-family: 'OpenSansLight', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 300; } .raceBoardNavigation-navigationitem { @@ -180,7 +182,8 @@ img.openColumn { } .abstractChartPanel-importantMessageOfChart { - font-family: 'OpenSansSemiBold', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 600; font-size: 20px; height: 70px; margin: 0 auto; @@ -239,7 +242,8 @@ img.openColumn { 0 transparent; color: #FFFFFF; cursor: pointer; - font-family: OpenSansSemiBold, Verdana, Arial, sans-serif; + font-family: 'Open Sans', Verdana, Arial, sans-serif; + font-weight: 600; font-size: 14px; margin: 0 0 0 0; padding: 2px 7px 2px 3px; @@ -272,7 +276,8 @@ img.openColumn { 0 transparent; color: #FFFFFF; cursor: pointer; - font-family: OpenSansSemiBold, Verdana, Arial, sans-serif; + font-family: 'Open Sans', Verdana, Arial, sans-serif; + font-weight: 600; font-size: 14px; margin: 0 0 0 0; padding: 2px 7px 2px 3px; diff --git a/java/com.sap.sailing.gwt.ui/SettingsDialog.css b/java/com.sap.sailing.gwt.ui/SettingsDialog.css index cfb8175cc32..babd52430d5 100644 --- a/java/com.sap.sailing.gwt.ui/SettingsDialog.css +++ b/java/com.sap.sailing.gwt.ui/SettingsDialog.css @@ -5,14 +5,16 @@ .dialogInnerHeadline { border-bottom: 1px solid #CCCCCC; - font-family: OpenSansSemiBold,Arial,Verdana,sans-serif; + font-family: 'Open Sans',Arial,Verdana,sans-serif; + font-weight: 600; height: 21px; padding: 2px 0 0 2px; margin-bottom: 4px; } .dialogInnerHeadlineOther { - font-family: OpenSansSemiBold, Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 600; color: #e84a1a; padding-left: 9px; } diff --git a/java/com.sap.sailing.gwt.ui/Simulator.css b/java/com.sap.sailing.gwt.ui/Simulator.css index e3563a2f47e..e7e173f5e83 100644 --- a/java/com.sap.sailing.gwt.ui/Simulator.css +++ b/java/com.sap.sailing.gwt.ui/Simulator.css @@ -32,7 +32,8 @@ .titleLabel { text-align: center; - font-family: 'OpenSansSemiBold', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 600 font-size: 18px; color: #fff; margin: 23px 0 0 0; @@ -40,7 +41,7 @@ body { background: #ebebeb; - font-family: 'OpenSansRegular', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; line-height: 1; font-size: 14px; font-weight: 400; @@ -50,7 +51,8 @@ body { } table td,select,button { - font-family: 'OpenSansLight', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 300; line-height: 1; font-size: 14px; } @@ -64,7 +66,8 @@ table td,select,button { /** Example rules used by the template application (remove for your app) */ h1 { font-size: 2em; - font-family: 'OpenSansSemiBold', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 600 color: #777777; margin: 40px 0px 70px; text-align: center; @@ -106,7 +109,8 @@ table { /*.leaderboardLabel { border-bottom: 2px solid #007dc0; padding: 0 0 6px 0; - font-family: 'OpenSansSemiBold', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 600 }*/ .refreshAndSettings { background: #f2f2f2; @@ -144,7 +148,8 @@ input.magnifier { /*.raceBoardNavigation { float: right; margin: 26px 0 0 0; - font-family: 'OpenSansLight', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 300; } .raceBoardNavigation-navigationitem { @@ -167,7 +172,8 @@ input.magnifier { text-decoration: none; }*/ .abstractChartPanel-importantMessageOfChart { - font-family: 'OpenSansSemiBold', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 600 font-size: 20px; height: 70px; margin: 0 auto; @@ -186,14 +192,15 @@ input.magnifier { } .innerHeadline { - font-family: OpenSansSemiBold, Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; font-size: 16px; color: #7c7c7c; margin: 15px 0 } .sectorHeadline { - font-family: OpenSansLight, Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 300; font-size: 16px; } @@ -329,7 +336,8 @@ input.magnifier { #masterPanelLeft .gwt-SliderBar-shell .gwt-SliderBar-ticklabel { font-size: 12px; cursor: default; - font-family: 'OpenSansSemiBold',Arial,Verdana,sans-serif; + font-family: 'Open Sans',Arial,Verdana,sans-serif; + font-weight: 600; top: 5px; } @@ -338,7 +346,8 @@ input.magnifier { font-size: 12px; color: #bc9434; cursor: default; - font-family: 'OpenSansSemiBold',Arial,Verdana,sans-serif; + font-family: 'Open Sans',Arial,Verdana,sans-serif; + font-weight: 600; } #masterPanelLeft .gwt-SliderBar-shell-focused { diff --git a/java/com.sap.sailing.gwt.ui/Spectator.css b/java/com.sap.sailing.gwt.ui/Spectator.css index 1f2709e6023..dc81d3c43ff 100644 --- a/java/com.sap.sailing.gwt.ui/Spectator.css +++ b/java/com.sap.sailing.gwt.ui/Spectator.css @@ -26,7 +26,7 @@ body { background: url(images/spectatorview-bg.png) no-repeat left top #ebebeb; - font-family: 'OpenSansRegular', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; line-height: 1; font-size: 14px; font-weight: 400; @@ -42,7 +42,7 @@ a { table td,select,button { line-height: 1; - font-family: 'OpenSansRegular', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; font-size: 14px; } @@ -186,7 +186,8 @@ input.magnifier { float: left; margin: 5px 5px 5px 0; text-decoration: none; - font-family: 'OpenSansSemiBold', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 600 } .leaderboardGroupPanel-BoatClass { @@ -196,7 +197,8 @@ input.magnifier { margin: 5px 5px 5px 0; text-decoration: none; white-space: nowrap; - font-family: 'OpenSansSemiBold', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 600 } .leaderboardGroupPanel-ColorBox { @@ -227,7 +229,8 @@ input.magnifier { text-decoration: none; color: #fff; /*border: 1px solid #a6a6a6;*/ - font-family: 'OpenSansSemiBold', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 600 } .leaderboardGroupPanel-LiveRace, .leaderboardGroupPanel-LegendLive { @@ -244,7 +247,8 @@ input.magnifier { text-decoration: none; color: #fff; /*border: 1px solid #a6a6a6;*/ - font-family: 'OpenSansSemiBold', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 600 } .leaderboardGroupPanel-ActiveLeaderboard { @@ -260,7 +264,8 @@ input.magnifier { background: url("images/btn-cta-orangeleft.png") repeat-x -10px 0 #e7e7e7; text-decoration: none; color: #fff; - font-family: 'OpenSansSemiBold', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 600 } .leaderboardGroupPanel-ActiveButton { @@ -274,7 +279,8 @@ input.magnifier { background: url("images/btn-cta-blueleft.png") repeat-x 0px 0 #e7e7e7; text-decoration: none; color: #fff; - font-family: 'OpenSansSemiBold', Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 600 display: inline-block; } @@ -352,7 +358,7 @@ input.magnifier { .leaderboardGroupPanel-InactiveRace { background: #c0bebe; - font-family: 'OpenSansRegular', Arial, Verdana, sans-serif + font-family: 'Open Sans', Arial, Verdana, sans-serif } .errorLabel { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/RaceSimulationOverlay.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/RaceSimulationOverlay.java index 8bbec2b38fb..f8e1bf6d834 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/RaceSimulationOverlay.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/RaceSimulationOverlay.java @@ -41,7 +41,7 @@ public class RaceSimulationOverlay extends FullCanvasOverlay { public static final String GET_SIMULATION_CATEGORY = "getSimulation"; private final String textColor = "Black"; - private final String textFont = "10pt OpenSansRegular"; + private final String textFont = "10pt 'Open Sans'"; private String algorithmTimedOutText = "out-of-bounds"; private String mixedLegText = "ambiguous wind"; private int xOffset = 0; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/simulator/PathLegendCanvasOverlay.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/simulator/PathLegendCanvasOverlay.java index 39c00a6c558..43b0aa7834d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/simulator/PathLegendCanvasOverlay.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/simulator/PathLegendCanvasOverlay.java @@ -39,7 +39,7 @@ public class PathLegendCanvasOverlay extends FullCanvasOverlay { private double rectHeight = 20; private String textColor = "Black"; - private String textFont = "10pt OpenSansRegular"; + private String textFont = "10pt 'Open Sans'"; private String algorithmTimedOutText = "out-of-bounds"; private String mixedLegText = "ambiguous wind"; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/spectator/LeaderboardGroupFullTable.css b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/spectator/LeaderboardGroupFullTable.css index f3ba5599048..98e016904c3 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/spectator/LeaderboardGroupFullTable.css +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/spectator/LeaderboardGroupFullTable.css @@ -1,61 +1,62 @@ -@CHARSET "ISO-8859-1"; - -.cellTableWidget { - margin: 0; - table-layout: auto; - border-collapse: collapse; - /*border-spacing: 1em 0.5em;*/ - border: none; -} - -.cellTableHeader { - background: url(images/spectator-table-bg.png) 0 0 repeat-x !important; - - font-family: 'OpenSansSemiBold', Arial, Verdana, sans-serif; - padding: 10px 15px; - border: 1px solid #aeaeaf !important; - border-left: none !important; - border-right: none !important; - text-shadow: none !important; -} - -.cellTableFirstColumnHeader { - -} - -.cellTableLastColumnHeader { - -} - -.cellTableEvenRow { /* tr */ - background: #dddbdb; -} - -.cellTableEvenRowCell { /* td */ - border: none; - background: none; - vertical-align: top; - padding: 2px 3px; -} - -.cellTableOddRow { /* tr */ - background: none; -} - -.cellTableOddRowCell { /* td */ - border: none; - background: none; - vertical-align: top; - padding: 2px 3px; -} - -.cellTableHoveredRow { - -} - -.cellTableSelectedRow { -} - -.cellTableSelectedRowCell { - -} +@CHARSET "ISO-8859-1"; + +.cellTableWidget { + margin: 0; + table-layout: auto; + border-collapse: collapse; + /*border-spacing: 1em 0.5em;*/ + border: none; +} + +.cellTableHeader { + background: url(images/spectator-table-bg.png) 0 0 repeat-x !important; + + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: 600; + padding: 10px 15px; + border: 1px solid #aeaeaf !important; + border-left: none !important; + border-right: none !important; + text-shadow: none !important; +} + +.cellTableFirstColumnHeader { + +} + +.cellTableLastColumnHeader { + +} + +.cellTableEvenRow { /* tr */ + background: #dddbdb; +} + +.cellTableEvenRowCell { /* td */ + border: none; + background: none; + vertical-align: top; + padding: 2px 3px; +} + +.cellTableOddRow { /* tr */ + background: none; +} + +.cellTableOddRowCell { /* td */ + border: none; + background: none; + vertical-align: top; + padding: 2px 3px; +} + +.cellTableHoveredRow { + +} + +.cellTableSelectedRow { +} + +.cellTableSelectedRowCell { + +} From 595ff56c49f0bbf1e95759f5743860268e86713d Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 26 May 2015 14:08:26 +0200 Subject: [PATCH 13/72] Bug 2816: Changed more font-family declarations to use the new "Open Sans" @font-face --- java/com.sap.sailing.server.gateway/main.css | 160 +++--- java/com.sap.sailing.www/main.css | 475 +++++++++--------- java/com.sap.sailing.www/release_notes.css | 5 +- .../gwt/client/controls/slider/SliderBar.css | 177 +++---- 4 files changed, 413 insertions(+), 404 deletions(-) diff --git a/java/com.sap.sailing.server.gateway/main.css b/java/com.sap.sailing.server.gateway/main.css index c2de8aa273b..62189661f94 100644 --- a/java/com.sap.sailing.server.gateway/main.css +++ b/java/com.sap.sailing.server.gateway/main.css @@ -1,80 +1,80 @@ -/* line 2, _reset.sass */ -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, -del, dfn, em, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, -b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td, -article, aside, canvas, details, embed, -figure, figcaption, footer, header, hgroup, -menu, nav, output, ruby, section, summary, -time, mark, audio, video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; -} - -body { - height: 100%; - color: #222222; - font-size: 14px; - font-family: OpenSansRegular, Arial, Verdana, sans-serif; - font-weight: normal; - margin: 10px; - padding: 0px; - line-height: 18px; -} - -h1 { - font-size: 16px; - font-family: OpenSansRegular, Arial, Verdana, sans-serif; - font-weight: bold; - margin-top: 10px; - margin-bottom: 10px; -} - -h2 { - font-size: 16px; - font-family: OpenSansRegular, Arial, Verdana, sans-serif; - font-weight: normal; - margin-top: 5px; - margin-bottom: 10px; -} - -table td, table th -{ - padding: 5px; -} - -table { - border-spacing:0; - border-collapse:collapse; -} - -table thead tr td { - background-color: #eeeeee; -} - -table tbody tr:nth-child(odd) td { - background-color: #cccccc; -} - -table tbody tr:nth-child(even) td { - background-color: #dddddd; -} - -a { - text-decoration: none; - color: #0066b3; -} - -a:hover { - text-decoration: underline; -} - +/* line 2, _reset.sass */ +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} + +body { + height: 100%; + color: #222222; + font-size: 14px; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: normal; + margin: 10px; + padding: 0px; + line-height: 18px; +} + +h1 { + font-size: 16px; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: bold; + margin-top: 10px; + margin-bottom: 10px; +} + +h2 { + font-size: 16px; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: normal; + margin-top: 5px; + margin-bottom: 10px; +} + +table td, table th +{ + padding: 5px; +} + +table { + border-spacing:0; + border-collapse:collapse; +} + +table thead tr td { + background-color: #eeeeee; +} + +table tbody tr:nth-child(odd) td { + background-color: #cccccc; +} + +table tbody tr:nth-child(even) td { + background-color: #dddddd; +} + +a { + text-decoration: none; + color: #0066b3; +} + +a:hover { + text-decoration: underline; +} + diff --git a/java/com.sap.sailing.www/main.css b/java/com.sap.sailing.www/main.css index 7b8f32e0f7a..90cf3fb18d2 100644 --- a/java/com.sap.sailing.www/main.css +++ b/java/com.sap.sailing.www/main.css @@ -1,235 +1,240 @@ -/* line 2, _reset.sass */ -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, -del, dfn, em, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, -b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td, -article, aside, canvas, details, embed, -figure, figcaption, footer, header, hgroup, -menu, nav, output, ruby, section, summary, -time, mark, audio, video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; } - -/* HTML5 display-role reset for older browsers */ -/* line 23, _reset.sass */ -article, aside, details, figcaption, figure, -footer, header, hgroup, menu, nav, section { - display: block; } - -/* line 27, _reset.sass */ -body { - line-height: 1; } - -/* line 30, _reset.sass */ -ol, ul { - list-style: none; } - -/* line 33, _reset.sass */ -blockquote, q { - quotes: none; } - -/* line 36, _reset.sass */ -blockquote:before, blockquote:after, -q:before, q:after { - content: ""; - content: none; } - -/* line 41, _reset.sass */ -table { - border-collapse: collapse; - border-spacing: 0; } - -/* line 7, site.css.sass */ -html { - height: 100%; } - -/* line 10, site.css.sass */ -body { - height: 100%; - color: #222222; - font-size: 14px; - font-family: OpenSansRegular, Arial, Verdana, sans-serif; - font-weight: normal; - background-image: url(../images/bg-image.jpg); - background-attachment: fixed; - background-color: #222222; - background-position: 50% 0%; - background-repeat: no-repeat no-repeat; - margin: 0px; - padding: 0px; - line-height: 18px; } - -/* line 27, site.css.sass */ -ul { - font-size: 12px; - padding-left: 0px; - margin-bottom: 25px; - margin-left: 30px; } - -/* line 34, site.css.sass */ -a { - text-decoration: none; - color: #0066b3; } - /* line 38, site.css.sass */ - a:hover { - text-decoration: underline; } - -/* line 42, site.css.sass */ -#yield_content { - width: 950px; - margin: 0 auto; - min-height: 100%; } - #yield_content #logoAndTitlePanel { - height: 52px; - } - #yield_content .sapLogo { - height: 52px; - float: left; - } - #yield_content .headNavigation { - float: right; - margin: 25px 0 0 0; - padding: 0; } - #yield_content .headNavigation a { - font-family: 'OpenSansBold', Arial, Verdana, sans-serif; - color: #fff; } - /* line 47, site.css.sass */ - #yield_content #pageHeadline { - color: white; - margin: 10px 0 10px 0; - font-size: 18px; } - /* line 53, site.css.sass */ - #yield_content #keyVisual { - height: 240px; - position: relative; - background: white; } - /* line 58, site.css.sass */ - #yield_content #keyVisual #infoBox { - width: 502px; - height: 100px; - background: #999999; - position: absolute; - right: 0; - bottom: 0; - padding: 10px; } - /* line 67, site.css.sass */ - #yield_content #keyVisual #infoBox p { - color: white; - font-size: 12px; } - #yield_content #keyVisual #infoBox a { - text-decoration: none; - float: right; - background: #fcb913; - color: white; - font-size: 18px; - font-family: OpenSansRegular, Arial, Verdana, sans-serif; - padding: 6px 12px 6px 12px; } - - /* line 72, site.css.sass */ - #yield_content #mainContent { - padding: 0 10px 10px 10px; - background: white; } - /* line 79, site.css.sass */ - #yield_content #mainContent .innerContent .timeBar { - background: url(../images/timeBar-bg.png) 0 0 repeat-y; } - /* line 82, site.css.sass */ - #yield_content #mainContent .innerContent .timeBar .raceSection { - margin: 0 0 20px 0; - *display: inline-block; } - /* line 3, _helpers.sass */ - #yield_content #mainContent .innerContent .timeBar .raceSection:after { - content: " "; - display: block; - height: 0; - clear: both; - visibility: hidden; } - /* line 85, site.css.sass */ - #yield_content #mainContent .innerContent .timeBar .raceSection .date { - font-family: OpenSansRegular, Arial, Verdana, sans-serif; - font-size: 12px; - margin-left: 35px; } - /* line 91, site.css.sass */ - #yield_content #mainContent .innerContent .timeBar .raceSection .raceTimepoint { - background: url(../images/raceTimepoint-bg.png) left top no-repeat; - width: 29px; - height: 54px; - float: left; - margin: -16px 0 0 -5px; } - /* line 97, site.css.sass */ - #yield_content #mainContent .innerContent .timeBar .raceSection .racePanel { - background: url(../images/racePanel-bg.png) left bottom repeat-x #fcb913; - width: 169px; - min-height: 36px; - margin: 2px 10px 0 -5px; - float: left; - padding: 6px 0 6px 13px; } - /* line 104, site.css.sass */ - #yield_content #mainContent .innerContent .timeBar .raceSection .racePanel .raceName { - font-size: 12px; - font-family: OpenSansBold, Arial, Verdana, sans-serif; - color: white; } - /* line 109, site.css.sass */ - #yield_content #mainContent .innerContent .timeBar .raceSection .racePanel .raceLocation { - font-size: 12px; - font-family: OpenSansRegular, Arial, Verdana, sans-serif; - color: white; } - #yield_content #mainContent .innerContent .timeBar .raceSection a:hover { - text-decoration: none; } - /* line 114, site.css.sass */ - #yield_content #mainContent .innerContent .timeBar .raceDescription { - padding: 4px; - font-family: OpenSansRegular, Arial, Verdana, sans-serif; - font-size: 12px; - font-color: #222222; } - /* line 121, site.css.sass */ - #yield_content #mainContent .articleHeadline { - font-size: 18px; - font-family: OpenSansBold, Arial, Verdana, sans-serif; - color: #222222; - border-bottom: 2px solid #222222; - clear: both; - padding: 0 0 5px; - margin: 0 0 15px; } - /* line 131, site.css.sass */ - #yield_content #mainContent .articleSubheadline { - font-size: 14px; - font-family: OpenSansBold, Arial, Verdana, sans-serif; - color: #222222; - margin: 0 0 6px 0; } - /* line 138, site.css.sass */ - #yield_content #mainContent h4 { - margin: 0 0 10px; - font-size: 12px; - font-family: OpenSansBold, Arial, Verdana, sans-serif; } - /* line 144, site.css.sass */ - #yield_content #spaceBar { - height: 80px; } - -/* line 148, site.css.sass */ -#footer { - color: white; - width: 940px; - height: 20px; - margin: -40px auto 0 auto; - background: url(../images/bkg-footer1.png); - padding: 10px; - font-size: 11px; } - /* line 157, site.css.sass */ - #footer a { - color: white; - font-size: 11px; } - /* line 162, site.css.sass */ - #footer .regularNav { - margin: 0; } - /* line 164, site.css.sass */ - #footer .regularNav li { - display: inline; } +/* line 2, _reset.sass */ +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; } + +/* HTML5 display-role reset for older browsers */ +/* line 23, _reset.sass */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; } + +/* line 27, _reset.sass */ +body { + line-height: 1; } + +/* line 30, _reset.sass */ +ol, ul { + list-style: none; } + +/* line 33, _reset.sass */ +blockquote, q { + quotes: none; } + +/* line 36, _reset.sass */ +blockquote:before, blockquote:after, +q:before, q:after { + content: ""; + content: none; } + +/* line 41, _reset.sass */ +table { + border-collapse: collapse; + border-spacing: 0; } + +/* line 7, site.css.sass */ +html { + height: 100%; } + +/* line 10, site.css.sass */ +body { + height: 100%; + color: #222222; + font-size: 14px; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: normal; + background-image: url(../images/bg-image.jpg); + background-attachment: fixed; + background-color: #222222; + background-position: 50% 0%; + background-repeat: no-repeat no-repeat; + margin: 0px; + padding: 0px; + line-height: 18px; } + +/* line 27, site.css.sass */ +ul { + font-size: 12px; + padding-left: 0px; + margin-bottom: 25px; + margin-left: 30px; } + +/* line 34, site.css.sass */ +a { + text-decoration: none; + color: #0066b3; } + /* line 38, site.css.sass */ + a:hover { + text-decoration: underline; } + +/* line 42, site.css.sass */ +#yield_content { + width: 950px; + margin: 0 auto; + min-height: 100%; } + #yield_content #logoAndTitlePanel { + height: 52px; + } + #yield_content .sapLogo { + height: 52px; + float: left; + } + #yield_content .headNavigation { + float: right; + margin: 25px 0 0 0; + padding: 0; } + #yield_content .headNavigation a { + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: bold; + color: #fff; } + /* line 47, site.css.sass */ + #yield_content #pageHeadline { + color: white; + margin: 10px 0 10px 0; + font-size: 18px; } + /* line 53, site.css.sass */ + #yield_content #keyVisual { + height: 240px; + position: relative; + background: white; } + /* line 58, site.css.sass */ + #yield_content #keyVisual #infoBox { + width: 502px; + height: 100px; + background: #999999; + position: absolute; + right: 0; + bottom: 0; + padding: 10px; } + /* line 67, site.css.sass */ + #yield_content #keyVisual #infoBox p { + color: white; + font-size: 12px; } + #yield_content #keyVisual #infoBox a { + text-decoration: none; + float: right; + background: #fcb913; + color: white; + font-size: 18px; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + padding: 6px 12px 6px 12px; } + + /* line 72, site.css.sass */ + #yield_content #mainContent { + padding: 0 10px 10px 10px; + background: white; } + /* line 79, site.css.sass */ + #yield_content #mainContent .innerContent .timeBar { + background: url(../images/timeBar-bg.png) 0 0 repeat-y; } + /* line 82, site.css.sass */ + #yield_content #mainContent .innerContent .timeBar .raceSection { + margin: 0 0 20px 0; + *display: inline-block; } + /* line 3, _helpers.sass */ + #yield_content #mainContent .innerContent .timeBar .raceSection:after { + content: " "; + display: block; + height: 0; + clear: both; + visibility: hidden; } + /* line 85, site.css.sass */ + #yield_content #mainContent .innerContent .timeBar .raceSection .date { + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-size: 12px; + margin-left: 35px; } + /* line 91, site.css.sass */ + #yield_content #mainContent .innerContent .timeBar .raceSection .raceTimepoint { + background: url(../images/raceTimepoint-bg.png) left top no-repeat; + width: 29px; + height: 54px; + float: left; + margin: -16px 0 0 -5px; } + /* line 97, site.css.sass */ + #yield_content #mainContent .innerContent .timeBar .raceSection .racePanel { + background: url(../images/racePanel-bg.png) left bottom repeat-x #fcb913; + width: 169px; + min-height: 36px; + margin: 2px 10px 0 -5px; + float: left; + padding: 6px 0 6px 13px; } + /* line 104, site.css.sass */ + #yield_content #mainContent .innerContent .timeBar .raceSection .racePanel .raceName { + font-size: 12px; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: bold; + color: white; } + /* line 109, site.css.sass */ + #yield_content #mainContent .innerContent .timeBar .raceSection .racePanel .raceLocation { + font-size: 12px; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + color: white; } + #yield_content #mainContent .innerContent .timeBar .raceSection a:hover { + text-decoration: none; } + /* line 114, site.css.sass */ + #yield_content #mainContent .innerContent .timeBar .raceDescription { + padding: 4px; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-size: 12px; + font-color: #222222; } + /* line 121, site.css.sass */ + #yield_content #mainContent .articleHeadline { + font-size: 18px; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: bold; + color: #222222; + border-bottom: 2px solid #222222; + clear: both; + padding: 0 0 5px; + margin: 0 0 15px; } + /* line 131, site.css.sass */ + #yield_content #mainContent .articleSubheadline { + font-size: 14px; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: bold; + color: #222222; + margin: 0 0 6px 0; } + /* line 138, site.css.sass */ + #yield_content #mainContent h4 { + margin: 0 0 10px; + font-size: 12px; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: bold; } + /* line 144, site.css.sass */ + #yield_content #spaceBar { + height: 80px; } + +/* line 148, site.css.sass */ +#footer { + color: white; + width: 940px; + height: 20px; + margin: -40px auto 0 auto; + background: url(../images/bkg-footer1.png); + padding: 10px; + font-size: 11px; } + /* line 157, site.css.sass */ + #footer a { + color: white; + font-size: 11px; } + /* line 162, site.css.sass */ + #footer .regularNav { + margin: 0; } + /* line 164, site.css.sass */ + #footer .regularNav li { + display: inline; } diff --git a/java/com.sap.sailing.www/release_notes.css b/java/com.sap.sailing.www/release_notes.css index 130857a5cbc..139b198f944 100644 --- a/java/com.sap.sailing.www/release_notes.css +++ b/java/com.sap.sailing.www/release_notes.css @@ -4,7 +4,8 @@ body{ #yield_content #mainContent .releaseHeadline{ font-size: 24px; - font-family: OpenSansBold, Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-weight: bold; padding: 0 0 5px; margin: 0 0 10px 0; border-bottom: 2px solid #222222; @@ -14,7 +15,7 @@ body{ border-bottom: none; } #yield_content #mainContent .articleSubheadline { - font-family: OpenSansRegular, Arial, Verdana, sans-serif; + font-family: 'Open Sans', Arial, Verdana, sans-serif; } #yield_content #mainContent .releaseNavigation{ margin: 0 0 20px 0; diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/slider/SliderBar.css b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/slider/SliderBar.css index 324c623cb1f..6b8cf3144e0 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/slider/SliderBar.css +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/slider/SliderBar.css @@ -1,87 +1,90 @@ -.gwt-SliderBar-shell { - width: 100%; - height: 50px; -} - -.gwt-SliderBar-shell .gwt-SliderBar-line { - background: #333; - height: 12px; - width: 100%; - top: 18px; - overflow: hidden; -} - -.gwt-SliderBar-shell .gwt-SliderBar-line-disabled { - border: 1px solid gray; -} - -.gwt-SliderBar-shell .gwt-SliderBar-knob { - z-index: 1; - cursor: pointer; - top: 7px; -} - -.gwt-SliderBar-shell .gwt-SliderBar-tick { - top: 13px; - width: 2px; - height: 5px; - background: #333; - overflow: hidden; -} - -.gwt-SliderBar-shell:focus{ - outline: none; -} - -.gwt-SliderBar-shell .gwt-SliderBar-mark { - top: 13px; - width: 24px; - height: 24px; - background: #fcbb22; - overflow: hidden; - border-radius: 15px; -} - -.gwt-SliderBar-shell .gwt-SliderBar-mark-tooClose { - top: 12px; - width: 16px; - height: 16px; - background: #fcbb22; - overflow: hidden; - border-radius: 15px; -} - -.gwt-SliderBar-shell .gwt-SliderBar-tick-disabled { - background: gray; -} - -.gwt-SliderBar-shell .gwt-SliderBar-ticklabel { - font-size: 12px; - cursor: default; - font-family: 'OpenSansSemiBold',Arial,Verdana,sans-serif; - top: 0; -} - -.gwt-SliderBar-shell .gwt-SliderBar-markerlabel { - top: 20px; - font-size: 12px; - color: #333; - cursor: default; - font-family: 'OpenSansSemiBold',Arial,Verdana,sans-serif; -} - -.gwt-SliderBar-shell .gwt-SliderBar-markerlabel-tooClose { - top: 13px; - font-size: 8px; - color: #333; - cursor: default; - font-family: 'OpenSansSemiBold',Arial,Verdana,sans-serif; -} - -.gwt-SliderBar-shell-focused { - -} - -.gwt-SliderBar-shell .gwt-SliderBar-line-sliding { - cursor: pointer; -} +.gwt-SliderBar-shell { + width: 100%; + height: 50px; +} + +.gwt-SliderBar-shell .gwt-SliderBar-line { + background: #333; + height: 12px; + width: 100%; + top: 18px; + overflow: hidden; +} + +.gwt-SliderBar-shell .gwt-SliderBar-line-disabled { + border: 1px solid gray; +} + +.gwt-SliderBar-shell .gwt-SliderBar-knob { + z-index: 1; + cursor: pointer; + top: 7px; +} + +.gwt-SliderBar-shell .gwt-SliderBar-tick { + top: 13px; + width: 2px; + height: 5px; + background: #333; + overflow: hidden; +} + +.gwt-SliderBar-shell:focus{ + outline: none; +} + +.gwt-SliderBar-shell .gwt-SliderBar-mark { + top: 13px; + width: 24px; + height: 24px; + background: #fcbb22; + overflow: hidden; + border-radius: 15px; +} + +.gwt-SliderBar-shell .gwt-SliderBar-mark-tooClose { + top: 12px; + width: 16px; + height: 16px; + background: #fcbb22; + overflow: hidden; + border-radius: 15px; +} + +.gwt-SliderBar-shell .gwt-SliderBar-tick-disabled { + background: gray; +} + +.gwt-SliderBar-shell .gwt-SliderBar-ticklabel { + font-size: 12px; + cursor: default; + font-family: 'Open Sans',Arial,Verdana,sans-serif; + font-weight: 600; + top: 0; +} + +.gwt-SliderBar-shell .gwt-SliderBar-markerlabel { + top: 20px; + font-size: 12px; + color: #333; + cursor: default; + font-family: 'Open Sans',Arial,Verdana,sans-serif; + font-weight: 600; +} + +.gwt-SliderBar-shell .gwt-SliderBar-markerlabel-tooClose { + top: 13px; + font-size: 8px; + color: #333; + cursor: default; + font-family: 'Open Sans',Arial,Verdana,sans-serif; + font-weight: 600; +} + +.gwt-SliderBar-shell-focused { + +} + +.gwt-SliderBar-shell .gwt-SliderBar-line-sliding { + cursor: pointer; +} From d5fc40b70a7042cbb3ce12760022e8efadc72a25 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 26 May 2015 15:01:21 +0200 Subject: [PATCH 14/72] Fixed font-family to use "Open Sans" --- java/com.sap.sailing.gwt.ui/RaceBoard.css | 1 + 1 file changed, 1 insertion(+) diff --git a/java/com.sap.sailing.gwt.ui/RaceBoard.css b/java/com.sap.sailing.gwt.ui/RaceBoard.css index 66051c30350..de53a0e9b1e 100644 --- a/java/com.sap.sailing.gwt.ui/RaceBoard.css +++ b/java/com.sap.sailing.gwt.ui/RaceBoard.css @@ -589,6 +589,7 @@ img.openColumn { } .RegattaRaceInformation-Header { + font-family: 'Open Sans', Arial, Verdana, sans-serif; position: relative; left: 140px; top: 11px; From 526803ab78067945ea1597ef60a60ce1f56c52fb Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 26 May 2015 15:30:07 +0200 Subject: [PATCH 15/72] Bug 2909: Added '+' to the list of chars that are being encoded --- .../com/sap/sse/gwt/client/URLEncoder.java | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/URLEncoder.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/URLEncoder.java index 342a878a890..77219290e4c 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/URLEncoder.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/URLEncoder.java @@ -1,26 +1,26 @@ -package com.sap.sse.gwt.client; - -import com.google.gwt.http.client.URL; - -/** - * A very basic URL encoder that also works in a GWT environment where java.net.URLEncoder is not available. - * It is based on {@link URL#encode(String)} and adds encoding for the backslash (\) character. - * - * @author Axel Uhl (D043530) - * - */ -public class URLEncoder { - - private URLEncoder() { } - - private final static char[] charsToReplace = { '\'', '(', ')', '"', '[', ']', '{', '}', '<', '>', '|' }; - - public static String encode(String url) { - String nearlyEncoded = URL.encode(url); - for (char c : charsToReplace) { - nearlyEncoded = nearlyEncoded.replaceAll("\\" + Character.toString(c), "%" + Integer.toHexString(c)); - } - return nearlyEncoded; - } - -} +package com.sap.sse.gwt.client; + +import com.google.gwt.http.client.URL; + +/** + * A very basic URL encoder that also works in a GWT environment where java.net.URLEncoder is not available. + * It is based on {@link URL#encode(String)} and adds encoding for the backslash (\) character. + * + * @author Axel Uhl (D043530) + * + */ +public class URLEncoder { + + private URLEncoder() { } + + private final static char[] charsToReplace = { '\'', '(', ')', '"', '[', ']', '{', '}', '<', '>', '|', '+' }; + + public static String encode(String url) { + String nearlyEncoded = URL.encode(url); + for (char c : charsToReplace) { + nearlyEncoded = nearlyEncoded.replaceAll("\\" + Character.toString(c), "%" + Integer.toHexString(c)); + } + return nearlyEncoded; + } + +} From c76d161fde29b2de47bdf7102a52d08db0a2c42a Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 26 May 2015 16:17:05 +0200 Subject: [PATCH 16/72] Bug 2898: Adjusted styling of LeaderboardEditing to not use CommonControls anymore, as this breaks the button and dialog styling. Using new SAP header now as the old relies on CommonControls.css --- .../leaderboardedit/LeaderboardEditPage.java | 101 ++++++++++-------- .../sailing/gwt/ui/LeaderboardEditing.gwt.xml | 1 + 2 files changed, 59 insertions(+), 43 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboardedit/LeaderboardEditPage.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboardedit/LeaderboardEditPage.java index 2045cf771ea..a780595fd77 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboardedit/LeaderboardEditPage.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboardedit/LeaderboardEditPage.java @@ -1,43 +1,58 @@ -package com.sap.sailing.gwt.ui.leaderboardedit; - -import java.util.List; - -import com.google.gwt.user.client.Window; -import com.google.gwt.user.client.rpc.AsyncCallback; -import com.google.gwt.user.client.ui.Label; -import com.google.gwt.user.client.ui.RootPanel; -import com.sap.sailing.gwt.ui.client.AbstractSailingEntryPoint; -import com.sap.sailing.gwt.ui.client.LogoAndTitlePanel; -import com.sap.sse.gwt.client.async.AsyncActionsExecutor; -import com.sap.sse.gwt.client.async.MarkedAsyncCallback; - -public class LeaderboardEditPage extends AbstractSailingEntryPoint { - @Override - protected void doOnModuleLoad() { - super.doOnModuleLoad(); - - sailingService.getLeaderboardNames(new MarkedAsyncCallback>( - new AsyncCallback>() { - @Override - public void onSuccess(List leaderboardNames) { - String leaderboardName = Window.Location.getParameter("name"); - if (leaderboardNames.contains(leaderboardName)) { - LogoAndTitlePanel logoAndTitlePanel = new LogoAndTitlePanel(getStringMessages().editScores(), getStringMessages(), LeaderboardEditPage.this, getUserService()); - logoAndTitlePanel.addStyleName("LogoAndTitlePanel"); - EditableLeaderboardPanel leaderboardPanel = new EditableLeaderboardPanel(sailingService, new AsyncActionsExecutor(), leaderboardName, null, - LeaderboardEditPage.this, getStringMessages(), userAgent); - leaderboardPanel.ensureDebugId("EditableLeaderboardPanel"); - RootPanel.get().add(logoAndTitlePanel); - RootPanel.get().add(leaderboardPanel); - } else { - RootPanel.get().add(new Label(getStringMessages().noSuchLeaderboard())); - } - } - @Override - public void onFailure(Throwable t) { - reportError("Error trying to obtain list of leaderboard names: "+t.getMessage()); - } - })); - } - -} +package com.sap.sailing.gwt.ui.leaderboardedit; + +import java.util.List; + +import com.google.gwt.dom.client.Style.FontWeight; +import com.google.gwt.dom.client.Style.Position; +import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.RootPanel; +import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.gwt.ui.client.AbstractSailingEntryPoint; +import com.sap.sse.gwt.client.async.AsyncActionsExecutor; +import com.sap.sse.gwt.client.async.MarkedAsyncCallback; +import com.sap.sse.gwt.theme.client.component.sapheader2.SAPHeader2; + +public class LeaderboardEditPage extends AbstractSailingEntryPoint { + @Override + protected void doOnModuleLoad() { + super.doOnModuleLoad(); + + sailingService.getLeaderboardNames(new MarkedAsyncCallback>( + new AsyncCallback>() { + @Override + public void onSuccess(List leaderboardNames) { + String leaderboardName = Window.Location.getParameter("name"); + if (leaderboardNames.contains(leaderboardName)) { + EditableLeaderboardPanel leaderboardPanel = new EditableLeaderboardPanel(sailingService, new AsyncActionsExecutor(), leaderboardName, null, + LeaderboardEditPage.this, getStringMessages(), userAgent); + leaderboardPanel.ensureDebugId("EditableLeaderboardPanel"); + RootPanel.get().add(initHeader()); + RootPanel.get().add(leaderboardPanel); + } else { + RootPanel.get().add(new Label(getStringMessages().noSuchLeaderboard())); + } + } + @Override + public void onFailure(Throwable t) { + reportError("Error trying to obtain list of leaderboard names: "+t.getMessage()); + } + })); + } + + private Widget initHeader() { + Label title = new Label(getStringMessages().editScores()); + title.getElement().getStyle().setColor("white"); + title.getElement().getStyle().setFontSize(20, Unit.PX); + title.getElement().getStyle().setFontWeight(FontWeight.BOLD); + title.getElement().getStyle().setMarginTop(16, Unit.PX); + SAPHeader2 header = new SAPHeader2(getStringMessages().sapSailingAnalytics(), title, false); + header.getElement().getStyle().setPosition(Position.FIXED); + header.getElement().getStyle().setTop(0, Unit.PX); + header.getElement().getStyle().setWidth(100, Unit.PCT); + header.getElement().getStyle().setZIndex(1337); + return header; + } +} 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 843d73a389f..b84aa6731de 100644 --- 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 @@ -9,6 +9,7 @@ + From 2bce767cf8dfe47be07e8b66117a79b858a1b6fa Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 26 May 2015 16:50:19 +0200 Subject: [PATCH 17/72] Bug 2898: Adjusted styling of LeaderboardEditing to not use CommonControls anymore, as this breaks the button and dialog styling. Using new SAP header now as the old relies on CommonControls.css --- java/com.sap.sailing.gwt.ui/LeaderboardEditing.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/LeaderboardEditing.html b/java/com.sap.sailing.gwt.ui/LeaderboardEditing.html index 27eccd7d7e3..ea7acd3c454 100755 --- a/java/com.sap.sailing.gwt.ui/LeaderboardEditing.html +++ b/java/com.sap.sailing.gwt.ui/LeaderboardEditing.html @@ -21,7 +21,7 @@ - + From 1e0f861344c174dd2f9b0324a05f3eb320b59c74 Mon Sep 17 00:00:00 2001 From: Papick Garcia Taboada Date: Tue, 26 May 2015 17:09:52 +0200 Subject: [PATCH 18/72] Introduced fullscreen viewer for home, moved necessary media classes to sse --- .../domain/common/impl/ImageSizeImpl.java | 2 +- .../domain/common/media/MediaCategory.java | 5 -- .../domain/common/media/MediaTrack.java | 2 + .../domain/persistence/media/MediaDB.java | 2 +- .../persistence/media/impl/MediaDBImpl.java | 2 +- .../sap/sailing/domain/base/EventBase.java | 2 +- .../domain/base/impl/StrippedEventImpl.java | 2 +- .../test/CalculateImageSizeFromUrlTest.java | 2 +- .../com/sap/sailing/domain/base/Event.java | 2 +- .../sailing/domain/base/impl/EventImpl.java | 2 +- .../client/shared/mainmedia/MainMedia.java | 18 ++--- .../shared/mainmedia/MainMediaVideo.java | 6 +- .../home/client/shared/media/MediaPage.java | 12 ++-- ...ewer.java => SailingFullscreenViewer.java} | 10 +-- ...yPlayer.java => SailingGalleryPlayer.java} | 18 ++--- ...yer.ui.xml => SailingGalleryPlayer.ui.xml} | 0 .../client/RegattaOverviewEntryPoint.java | 1 - .../client/RegattaRaceStatesComponent.java | 3 +- .../sailing/gwt/server/HomeServiceImpl.java | 32 ++++----- .../sailing/gwt/server/HomeServiceUtil.java | 2 +- .../ui/client/media/GalleryImageHolder.java | 4 +- .../media/MediaPlayerManagerComponent.java | 2 +- .../media/MediaSingleSelectionControl.java | 2 +- .../gwt/ui/client/media/NewMediaDialog.java | 2 +- .../gwt/ui/client/media/VideoJSPlayer.java | 6 +- .../gwt/ui/client/media/VideoThumbnail.java | 6 +- .../sailing/gwt/ui/shared/EventBaseDTO.java | 2 +- .../event/EventOverviewVideoStageDTO.java | 2 +- .../event/GetEventOverviewStageAction.java | 2 +- .../gwt/ui/shared/media/AbstractMediaDTO.java | 72 ------------------- .../sailing/gwt/ui/shared/media/MediaDTO.java | 12 ++-- .../gwt/ui/shared/media/MediaUtils.java | 2 +- .../gwt/ui/shared/media/SailingImageDTO.java | 58 +++++++++++++++ .../gwt/ui/shared/media/SailingVideoDTO.java | 36 ++++++++++ .../gwt/ui/shared/start/StartViewDTO.java | 16 ++--- .../media/persistence/test/MediaDBTest.java | 2 +- .../impl/EventBaseJsonSerializer.java | 2 +- ...tialLoadReplicationObjectIdentityTest.java | 2 +- .../test/MediaReplicationTest.java | 2 +- .../impl/MasterDataImporterMediaTest.java | 2 +- .../sailing/server/impl/MediaLibaryTest.java | 2 +- .../impl/MediaMasterDataExportTest.java | 2 +- .../server/test/MasterDataImportTest.java | 2 +- java/com.sap.sse.common/META-INF/MANIFEST.MF | 1 + .../sse/common/media/AbstractMediaDTO.java | 46 ++++++++++++ .../sse/common}/media/ImageMetadataDTO.java | 15 ++-- .../com/sap/sse/common/media}/ImageSize.java | 2 +- .../sap/sse}/common/media/MediaSubType.java | 2 +- .../com/sap/sse}/common/media/MediaType.java | 2 +- .../com/sap/sse}/common/media/MimeType.java | 2 +- .../sse/common}/media/VideoMetadataDTO.java | 16 ++--- .../controls/carousel/ImageCarousel.java | 59 +++++++++++++-- 52 files changed, 309 insertions(+), 201 deletions(-) delete mode 100644 java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaCategory.java rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/{FullscreenViewer.java => SailingFullscreenViewer.java} (85%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/{GalleryPlayer.java => SailingGalleryPlayer.java} (85%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/{GalleryPlayer.ui.xml => SailingGalleryPlayer.ui.xml} (100%) delete mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/AbstractMediaDTO.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingImageDTO.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingVideoDTO.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDTO.java rename java/{com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared => com.sap.sse.common/src/com/sap/sse/common}/media/ImageMetadataDTO.java (71%) rename java/{com.sap.sailing.domain.common/src/com/sap/sailing/domain/common => com.sap.sse.common/src/com/sap/sse/common/media}/ImageSize.java (75%) rename java/{com.sap.sailing.domain.common/src/com/sap/sailing/domain => com.sap.sse.common/src/com/sap/sse}/common/media/MediaSubType.java (80%) rename java/{com.sap.sailing.domain.common/src/com/sap/sailing/domain => com.sap.sse.common/src/com/sap/sse}/common/media/MediaType.java (57%) rename java/{com.sap.sailing.domain.common/src/com/sap/sailing/domain => com.sap.sse.common/src/com/sap/sse}/common/media/MimeType.java (96%) rename java/{com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared => com.sap.sse.common/src/com/sap/sse/common}/media/VideoMetadataDTO.java (54%) diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/ImageSizeImpl.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/ImageSizeImpl.java index 1c6ef6246d1..fb15291dca8 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/ImageSizeImpl.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/ImageSizeImpl.java @@ -1,6 +1,6 @@ package com.sap.sailing.domain.common.impl; -import com.sap.sailing.domain.common.ImageSize; +import com.sap.sse.common.media.ImageSize; public class ImageSizeImpl implements ImageSize { private static final long serialVersionUID = 1170701774852068780L; diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaCategory.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaCategory.java deleted file mode 100644 index 1419e5bd7c4..00000000000 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaCategory.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.sap.sailing.domain.common.media; - -public enum MediaCategory { - highlight, livestream; -} \ No newline at end of file diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaTrack.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaTrack.java index f630c43596c..74c855dcba9 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaTrack.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaTrack.java @@ -8,6 +8,8 @@ import java.util.Set; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; +import com.sap.sse.common.media.MediaSubType; +import com.sap.sse.common.media.MimeType; /** * See http://my.opera.com/core/blog/2010/03/03/everything-you-need-to-know-about-html5-video-and-audio-2 diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/media/MediaDB.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/media/MediaDB.java index 284322a59d1..04dde808c98 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/media/MediaDB.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/media/MediaDB.java @@ -6,9 +6,9 @@ import java.util.Set; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; import com.sap.sailing.domain.common.media.MediaTrack; -import com.sap.sailing.domain.common.media.MimeType; import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; +import com.sap.sse.common.media.MimeType; /** * Offers CRUD methods for mongo representation of media track objects. diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/media/impl/MediaDBImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/media/impl/MediaDBImpl.java index 664c90cfbfd..21f915a64a7 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/media/impl/MediaDBImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/media/impl/MediaDBImpl.java @@ -19,12 +19,12 @@ import com.mongodb.WriteConcern; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; import com.sap.sailing.domain.common.RegattaNameAndRaceName; import com.sap.sailing.domain.common.media.MediaTrack; -import com.sap.sailing.domain.common.media.MimeType; import com.sap.sailing.domain.persistence.media.MediaDB; import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; import com.sap.sse.common.impl.MillisecondsDurationImpl; import com.sap.sse.common.impl.MillisecondsTimePoint; +import com.sap.sse.common.media.MimeType; /** * MongoDB Java API examples: http://blog.rasc.ch/?p=1096 diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java index 0e4ac88213d..ec8dd8ea3b1 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java @@ -3,11 +3,11 @@ package com.sap.sailing.domain.base; import java.net.URL; import java.util.concurrent.ExecutionException; -import com.sap.sailing.domain.common.ImageSize; import com.sap.sailing.domain.common.Renamable; import com.sap.sse.common.Named; import com.sap.sse.common.TimePoint; import com.sap.sse.common.WithID; +import com.sap.sse.common.media.ImageSize; /** * Base interface for an Event consisting of all static information, which might be shared diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/StrippedEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/StrippedEventImpl.java index 2c4332ab02c..a5b88e9b506 100755 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/StrippedEventImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/StrippedEventImpl.java @@ -9,8 +9,8 @@ import java.util.concurrent.ExecutionException; import com.sap.sailing.domain.base.EventBase; import com.sap.sailing.domain.base.LeaderboardGroupBase; import com.sap.sailing.domain.base.Venue; -import com.sap.sailing.domain.common.ImageSize; import com.sap.sse.common.TimePoint; +import com.sap.sse.common.media.ImageSize; /** * A simplified implementation of the {@link EventBase} interface which maintains an immutable collection of diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CalculateImageSizeFromUrlTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CalculateImageSizeFromUrlTest.java index 920d42c7573..0a4e994af77 100644 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CalculateImageSizeFromUrlTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CalculateImageSizeFromUrlTest.java @@ -19,8 +19,8 @@ import org.junit.Test; import com.sap.sailing.domain.base.Event; import com.sap.sailing.domain.base.impl.EventImpl; -import com.sap.sailing.domain.common.ImageSize; import com.sap.sailing.domain.common.impl.ImageSizeImpl; +import com.sap.sse.common.media.ImageSize; public class CalculateImageSizeFromUrlTest { diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/Event.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/Event.java index 1abf52edd38..fb25d1c77c3 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/Event.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/Event.java @@ -4,8 +4,8 @@ import java.net.URL; import java.util.UUID; import java.util.concurrent.ExecutionException; -import com.sap.sailing.domain.common.ImageSize; import com.sap.sailing.domain.leaderboard.LeaderboardGroup; +import com.sap.sse.common.media.ImageSize; /** * An event is a group of {@link Regatta regattas} carried out at a common venue within a common time frame. For diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/EventImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/EventImpl.java index 321fc4b5026..19d1fa73ce0 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/EventImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/EventImpl.java @@ -26,11 +26,11 @@ import javax.imageio.stream.ImageInputStream; import com.sap.sailing.domain.base.Event; import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.Venue; -import com.sap.sailing.domain.common.ImageSize; import com.sap.sailing.domain.common.impl.ImageSizeImpl; import com.sap.sailing.domain.leaderboard.LeaderboardGroup; import com.sap.sse.common.TimePoint; import com.sap.sse.common.Util; +import com.sap.sse.common.media.ImageSize; public class EventImpl extends EventBaseImpl implements Event { private static final long serialVersionUID = 855135446595485715L; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMedia.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMedia.java index 3d8160c4871..90aa89c8b12 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMedia.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMedia.java @@ -12,8 +12,9 @@ import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.gwt.home.client.app.PlaceNavigator; -import com.sap.sailing.gwt.ui.shared.media.ImageMetadataDTO; -import com.sap.sailing.gwt.ui.shared.media.VideoMetadataDTO; +import com.sap.sailing.gwt.home.client.shared.media.SailingFullscreenViewer; +import com.sap.sailing.gwt.ui.shared.media.SailingImageDTO; +import com.sap.sailing.gwt.ui.shared.media.SailingVideoDTO; import com.sap.sse.gwt.client.controls.carousel.ImageCarousel; public class MainMedia extends Composite { @@ -27,7 +28,7 @@ public class MainMedia extends Composite { DivElement videoLightBoxData; @UiField - ImageCarousel imageCarousel; + ImageCarousel imageCarousel; interface MainMediaUiBinder extends UiBinder { } @@ -37,20 +38,21 @@ public class MainMedia extends Composite { public MainMedia(PlaceNavigator navigator) { MainMediaResources.INSTANCE.css().ensureInjected(); initWidget(uiBinder.createAndBindUi(this)); + imageCarousel.registerFullscreenViewer(new SailingFullscreenViewer()); } - public void setData(Collection videos, ArrayList photos) { - Iterator videoIterator = videos.iterator(); + public void setData(Collection videos, ArrayList photos) { + Iterator videoIterator = videos.iterator(); int videoCount = 0; while(videoCount < MAX_VIDEO_COUNT && videoIterator.hasNext()) { - VideoMetadataDTO videoDTO = videoIterator.next(); + SailingVideoDTO videoDTO = videoIterator.next(); MainMediaVideo video = new MainMediaVideo(videoDTO.getTitle(), videoDTO.getSourceRef(), videoDTO.getMimeType()); videosPanel.add(video); videoCount++; } - for (ImageMetadataDTO image : photos) { - imageCarousel.addImage(image.getSourceRef(), image.getHeightInPx(), image.getWidthInPx()); + for (SailingImageDTO image : photos) { + imageCarousel.addImage(image); } } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMediaVideo.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMediaVideo.java index dd96543e435..8629f6c77d1 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMediaVideo.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMediaVideo.java @@ -9,10 +9,10 @@ import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.Widget; -import com.sap.sailing.domain.common.media.MimeType; import com.sap.sailing.gwt.home.client.shared.LongNamesUtil; import com.sap.sailing.gwt.ui.client.media.VideoJSPlayer; -import com.sap.sailing.gwt.ui.shared.media.VideoMetadataDTO; +import com.sap.sailing.gwt.ui.shared.media.SailingVideoDTO; +import com.sap.sse.common.media.MimeType; public class MainMediaVideo extends Composite { @@ -64,7 +64,7 @@ public class MainMediaVideo extends Composite { } - public void show(VideoMetadataDTO videoCandidateInfo) { + public void show(SailingVideoDTO videoCandidateInfo) { vJs.setSource(videoCandidateInfo.getSourceRef(), videoCandidateInfo.getMimeType()); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/MediaPage.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/MediaPage.java index 38d6eaafc81..cd06d42ab51 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/MediaPage.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/MediaPage.java @@ -17,9 +17,9 @@ import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.client.media.GalleryImageHolder; import com.sap.sailing.gwt.ui.client.media.VideoJSPlayer; import com.sap.sailing.gwt.ui.client.media.VideoThumbnail; -import com.sap.sailing.gwt.ui.shared.media.ImageMetadataDTO; import com.sap.sailing.gwt.ui.shared.media.MediaDTO; -import com.sap.sailing.gwt.ui.shared.media.VideoMetadataDTO; +import com.sap.sailing.gwt.ui.shared.media.SailingImageDTO; +import com.sap.sailing.gwt.ui.shared.media.SailingVideoDTO; public class MediaPage extends Composite { private static MediaPageUiBinder uiBinder = GWT.create(MediaPageUiBinder.class); @@ -85,7 +85,7 @@ public class MediaPage extends Composite { break; } - for (final ImageMetadataDTO holder : media.getPhotos()) { + for (final SailingImageDTO holder : media.getPhotos()) { if (holder.getSourceRef() != null) { GalleryImageHolder gih = new GalleryImageHolder(holder); @@ -96,7 +96,7 @@ public class MediaPage extends Composite { gih.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { - new FullscreenViewer(holder, media.getPhotos()); + new SailingFullscreenViewer().show(holder, media.getPhotos()); } }); } @@ -113,7 +113,7 @@ public class MediaPage extends Composite { videoListOuterBoxUi.addClassName(res.mediaCss().large3()); } boolean first = true; - for (final VideoMetadataDTO videoCandidateInfo : media.getVideos()) { + for (final SailingVideoDTO videoCandidateInfo : media.getVideos()) { if (first) { putVideoOnDisplay(videoCandidateInfo, false); first = false; @@ -137,7 +137,7 @@ public class MediaPage extends Composite { } } - private void putVideoOnDisplay(final VideoMetadataDTO videoCandidateInfo, boolean autoplay) { + private void putVideoOnDisplay(final SailingVideoDTO videoCandidateInfo, boolean autoplay) { videoDisplayUi = new VideoJSPlayer(true, autoplay); videoDisplayUi.setSource(videoCandidateInfo.getSourceRef(), videoCandidateInfo.getMimeType()); videoDisplayHolderUi.setWidget(videoDisplayUi); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/FullscreenViewer.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/SailingFullscreenViewer.java similarity index 85% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/FullscreenViewer.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/SailingFullscreenViewer.java index 5e40efd3637..37ab3706266 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/FullscreenViewer.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/SailingFullscreenViewer.java @@ -15,9 +15,10 @@ import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.PopupPanel.PositionCallback; import com.google.gwt.user.client.ui.RootPanel; -import com.sap.sailing.gwt.ui.shared.media.ImageMetadataDTO; +import com.sap.sailing.gwt.ui.shared.media.SailingImageDTO; +import com.sap.sse.gwt.client.controls.carousel.ImageCarousel.FullscreenViewer; -public class FullscreenViewer { +public class SailingFullscreenViewer implements FullscreenViewer { private PopupPanel popup = new PopupPanel(true) { protected void onPreviewNativeEvent(NativePreviewEvent event) { if (event.getTypeInt() == Event.ONKEYDOWN && event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ESCAPE) { @@ -26,8 +27,8 @@ public class FullscreenViewer { }; }; - public FullscreenViewer(ImageMetadataDTO selected, List images) { - final GalleryPlayer viewer = new GalleryPlayer(selected, images); + public void show(SailingImageDTO selected, List images) { + final SailingGalleryPlayer viewer = new SailingGalleryPlayer(selected, images); Window.addResizeHandler(new ResizeHandler() { @Override @@ -63,4 +64,5 @@ public class FullscreenViewer { } }); } + } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/GalleryPlayer.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/SailingGalleryPlayer.java similarity index 85% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/GalleryPlayer.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/SailingGalleryPlayer.java index ff1122da1b8..0cd1fb97cb2 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/GalleryPlayer.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/SailingGalleryPlayer.java @@ -15,14 +15,14 @@ import com.google.gwt.uibinder.client.UiHandler; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.ui.ResizeComposite; import com.google.gwt.user.client.ui.Widget; -import com.sap.sailing.gwt.ui.shared.media.ImageMetadataDTO; +import com.sap.sailing.gwt.ui.shared.media.SailingImageDTO; import com.sap.sse.gwt.client.controls.carousel.ImageCarousel; -public class GalleryPlayer extends ResizeComposite { - private static GalleryPlayerUiBinder uiBinder = GWT.create(GalleryPlayerUiBinder.class); +public class SailingGalleryPlayer extends ResizeComposite { + private static MyBinder uiBinder = GWT.create(MyBinder.class); private Command closeCommand; - interface GalleryPlayerUiBinder extends UiBinder { + interface MyBinder extends UiBinder { } @UiField @@ -30,19 +30,19 @@ public class GalleryPlayer extends ResizeComposite { @UiField DivElement subSliderUi; - ImageCarousel carousel = new ImageCarousel(); + ImageCarousel carousel = new ImageCarousel<>(); private int selectedIdx; - public GalleryPlayer(ImageMetadataDTO selected, List images) { + public SailingGalleryPlayer(SailingImageDTO selected, List images) { initWidget(uiBinder.createAndBindUi(this)); selectedIdx = Math.max(selectedIdx, images.indexOf(selected)); - for (ImageMetadataDTO i : images) { + for (SailingImageDTO i : images) { mainSliderUi.appendChild(createMainImgElement(i)); subSliderUi.appendChild(createThumbImgElement(i)); } } - private ImageElement createThumbImgElement(ImageMetadataDTO i ) { + private ImageElement createThumbImgElement(SailingImageDTO i ) { ImageElement img = Document.get().createImageElement(); img.setAttribute("src", i.getSourceRef()); img.setHeight(100); @@ -50,7 +50,7 @@ public class GalleryPlayer extends ResizeComposite { return img; } - private DivElement createMainImgElement(ImageMetadataDTO i) { + private DivElement createMainImgElement(SailingImageDTO i) { DivElement img = Document.get().createDivElement(); img.getStyle().setBackgroundImage("url(\"" + i.getSourceRef() + "\")"); img.getStyle().setProperty("backgroundSize", "contain"); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/GalleryPlayer.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/SailingGalleryPlayer.ui.xml similarity index 100% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/GalleryPlayer.ui.xml rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/SailingGalleryPlayer.ui.xml diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java index 85ea1479d34..4571c89fdd0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java @@ -32,7 +32,6 @@ public class RegattaOverviewEntryPoint extends AbstractSailingEntryPoint { private DockLayoutPanel containerPanel; private RaceDetailPanel detailPanel; private RegattaOverviewPanel regattaPanel; - private SAPHeader2 logoAndTitlePanel; private final Label eventNameLabel = new Label(); private final Label venueNameLabel = new Label(); private final Label clockLabel = new Label(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java index faaa936dd71..6aca3ff8098 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java @@ -92,7 +92,6 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component private final VerticalPanel mainPanel; private final DateTimeFormat timeFormatter = DateTimeFormat.getFormat("HH:mm:ss"); private final DateTimeFormat dateFormatter = DateTimeFormat.getFormat(PredefinedFormat.DATE_SHORT); - private final RegattaOverviewResources.LocalCss style = RegattaOverviewResources.INSTANCE.css(); private final SailingServiceAsync sailingService; private final StringMessages stringMessages; private final UUID eventId; @@ -390,7 +389,7 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component return result; } - @SuppressWarnings("unchecked") + private void createColumns() { regattaOverviewListHandler = new ListHandler(regattaOverviewDataProvider.getList()); courseAreaColumn = new TextColumn() { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java index e316f94a1da..ae169e7d3a1 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java @@ -25,9 +25,6 @@ import com.sap.sailing.domain.base.Event; import com.sap.sailing.domain.base.EventBase; import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.RemoteSailingServerReference; -import com.sap.sailing.domain.common.ImageSize; -import com.sap.sailing.domain.common.media.MediaType; -import com.sap.sailing.domain.common.media.MimeType; import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.leaderboard.LeaderboardGroup; @@ -45,10 +42,10 @@ import com.sap.sailing.gwt.ui.shared.fakeseries.EventSeriesViewDTO.EventSeriesSt import com.sap.sailing.gwt.ui.shared.general.EventMetadataDTO; import com.sap.sailing.gwt.ui.shared.general.EventReferenceDTO; import com.sap.sailing.gwt.ui.shared.general.EventState; -import com.sap.sailing.gwt.ui.shared.media.ImageMetadataDTO; import com.sap.sailing.gwt.ui.shared.media.MediaDTO; import com.sap.sailing.gwt.ui.shared.media.MediaUtils; -import com.sap.sailing.gwt.ui.shared.media.VideoMetadataDTO; +import com.sap.sailing.gwt.ui.shared.media.SailingImageDTO; +import com.sap.sailing.gwt.ui.shared.media.SailingVideoDTO; import com.sap.sailing.gwt.ui.shared.start.EventStageDTO; import com.sap.sailing.gwt.ui.shared.start.StageEventType; import com.sap.sailing.gwt.ui.shared.start.StartViewDTO; @@ -60,6 +57,9 @@ import com.sap.sse.common.Util; import com.sap.sse.common.Util.Pair; import com.sap.sse.common.impl.MillisecondsTimePoint; import com.sap.sse.common.impl.TimeRangeImpl; +import com.sap.sse.common.media.ImageSize; +import com.sap.sse.common.media.MediaType; +import com.sap.sse.common.media.MimeType; import com.sap.sse.util.ServiceTrackerFactory; /** @@ -189,7 +189,7 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home MimeType type = MediaUtils.detectMimeTypeFromUrl(youTubeRandomUrl.toString()); if (type.mediaType == MediaType.video) { - VideoMetadataDTO candidate = new VideoMetadataDTO(eventRef, youTubeRandomUrl, type, + SailingVideoDTO candidate = new SailingVideoDTO(eventRef, youTubeRandomUrl, type, holder.event.getName()); result.addVideo(candidate); } @@ -203,9 +203,9 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home } }); - final Set photoGalleryUrls = new HashSet<>(); // using a HashSet here leads to a reasonable + final Set photoGalleryUrls = new HashSet<>(); // using a HashSet here leads to a reasonable // amount of shuffling - final List videoCandidates = new ArrayList<>(); + final List videoCandidates = new ArrayList<>(); for(EventHolder holder : recentEventsOfLast12Month) { if(result.getRecentEvents().size() < MAX_RECENT_EVENTS) { @@ -220,7 +220,7 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home ImageSize imageSize = event.getImageSize(url); if(imageSize != null) { // TODO: do we habe a title? - photoGalleryUrls.add(new ImageMetadataDTO(eventRef, url, imageSize, null)); + photoGalleryUrls.add(new SailingImageDTO(eventRef, url.toString(), imageSize, null)); } } catch (Exception e) { } @@ -229,7 +229,7 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home MimeType type = MediaUtils.detectMimeTypeFromUrl(videoUrl.toString()); if (type.mediaType == MediaType.video) { - VideoMetadataDTO candidate = new VideoMetadataDTO(eventRef, videoUrl, type, holder.event.getName()); + SailingVideoDTO candidate = new SailingVideoDTO(eventRef, videoUrl, type, holder.event.getName()); videoCandidates.add(candidate); } } @@ -238,7 +238,7 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home final int numberOfCandidatesAvailable = videoCandidates.size(); if (numberOfCandidatesAvailable <= (MAX_VIDEO_COUNT - result.getVideos().size())) { // add all we have, no randomize - for (VideoMetadataDTO video : videoCandidates) { + for (SailingVideoDTO video : videoCandidates) { result.addVideo(video); } } else { @@ -246,7 +246,7 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home final Random videosRandomizer = new Random(numberOfCandidatesAvailable); randomlyPick: for (int i = 0; i < numberOfCandidatesAvailable; i++) { int nextVideoindex = videosRandomizer.nextInt(numberOfCandidatesAvailable); - final VideoMetadataDTO video = videoCandidates.get(nextVideoindex); + final SailingVideoDTO video = videoCandidates.get(nextVideoindex); result.addVideo(video); if (result.getVideos().size() == MAX_VIDEO_COUNT) { break randomlyPick; @@ -254,12 +254,12 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home } } Random random = new Random(); - List shuffledPhotoGallery = new ArrayList<>(photoGalleryUrls); + List shuffledPhotoGallery = new ArrayList<>(photoGalleryUrls); final int gallerySize = photoGalleryUrls.size(); for (int i = 0; i < gallerySize; i++) { Collections.swap(shuffledPhotoGallery, i, random.nextInt(gallerySize)); } - for (ImageMetadataDTO holder : shuffledPhotoGallery) { + for (SailingImageDTO holder : shuffledPhotoGallery) { result.addPhoto(holder); } // TODO media @@ -429,13 +429,13 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home } catch (InterruptedException | ExecutionException e) { logger.log(Level.FINE, "Was unable to obtain image size for "+url+" earlier.", e); } - ImageMetadataDTO entry = new ImageMetadataDTO(eventRef, url, imageSize, eventName); + SailingImageDTO entry = new SailingImageDTO(eventRef, url.toString(), imageSize, eventName); media.addPhoto(entry); } for(URL url : event.getVideoURLs()) { MimeType type = MediaUtils.detectMimeTypeFromUrl(url.toString()); if (type.mediaType == MediaType.video) { - VideoMetadataDTO candidate = new VideoMetadataDTO(eventRef, url, type, null); + SailingVideoDTO candidate = new SailingVideoDTO(eventRef, url, type, null); media.addVideo(candidate); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java index 496f852a088..12616c30413 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java @@ -19,7 +19,6 @@ import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.LeaderboardGroupBase; import com.sap.sailing.domain.base.RaceColumn; import com.sap.sailing.domain.base.Regatta; -import com.sap.sailing.domain.common.ImageSize; import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.leaderboard.LeaderboardGroup; import com.sap.sailing.domain.tracking.TrackedRace; @@ -27,6 +26,7 @@ import com.sap.sailing.gwt.ui.shared.eventview.HasRegattaMetadata.RegattaState; import com.sap.sailing.gwt.ui.shared.eventview.RegattaMetadataDTO; import com.sap.sailing.gwt.ui.shared.general.EventState; import com.sap.sse.common.Util; +import com.sap.sse.common.media.ImageSize; public final class HomeServiceUtil { private HomeServiceUtil() { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/GalleryImageHolder.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/GalleryImageHolder.java index 07888d05315..86e8d235299 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/GalleryImageHolder.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/GalleryImageHolder.java @@ -10,7 +10,7 @@ import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.Widget; -import com.sap.sailing.gwt.ui.shared.media.ImageMetadataDTO; +import com.sap.sailing.gwt.ui.shared.media.SailingImageDTO; public class GalleryImageHolder extends Widget implements HasClickHandlers { @@ -22,7 +22,7 @@ public class GalleryImageHolder extends Widget implements HasClickHandlers { @UiField DivElement imageHolderUi; - public GalleryImageHolder(ImageMetadataDTO video) { + public GalleryImageHolder(SailingImageDTO video) { setElement(uiBinder.createAndBindUi(this)); imageHolderUi.getStyle().setBackgroundImage("url(\"" + video.getSourceRef() + "\")"); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/MediaPlayerManagerComponent.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/MediaPlayerManagerComponent.java index bbe7417a4f7..843955e5fa2 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/MediaPlayerManagerComponent.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/MediaPlayerManagerComponent.java @@ -24,7 +24,6 @@ import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; import com.sap.sailing.domain.common.media.MediaTrack; import com.sap.sailing.domain.common.media.MediaTrack.Status; -import com.sap.sailing.domain.common.media.MediaType; import com.sap.sailing.domain.common.security.Roles; import com.sap.sailing.gwt.ui.client.MediaServiceAsync; import com.sap.sailing.gwt.ui.client.RaceTimesInfoProvider; @@ -38,6 +37,7 @@ import com.sap.sailing.gwt.ui.client.media.shared.VideoPlayer; import com.sap.sailing.gwt.ui.client.media.shared.VideoSynchPlayer; import com.sap.sse.common.TimePoint; import com.sap.sse.common.impl.MillisecondsTimePoint; +import com.sap.sse.common.media.MediaType; import com.sap.sse.common.settings.AbstractSettings; import com.sap.sse.gwt.client.ErrorReporter; import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/MediaSingleSelectionControl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/MediaSingleSelectionControl.java index 03596683ccc..4f764a42807 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/MediaSingleSelectionControl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/MediaSingleSelectionControl.java @@ -14,8 +14,8 @@ import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.UIObject; import com.google.gwt.user.client.ui.VerticalPanel; import com.sap.sailing.domain.common.media.MediaTrack; -import com.sap.sailing.domain.common.media.MediaType; import com.sap.sailing.gwt.ui.client.StringMessages; +import com.sap.sse.common.media.MediaType; public class MediaSingleSelectionControl extends AbstractMediaSelectionControl implements CloseHandler { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/NewMediaDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/NewMediaDialog.java index 074085cb40b..90185a31465 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/NewMediaDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/NewMediaDialog.java @@ -17,12 +17,12 @@ import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; import com.sap.sailing.domain.common.media.MediaTrack; -import com.sap.sailing.domain.common.media.MimeType; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.common.client.YoutubeApi; import com.sap.sse.common.TimePoint; import com.sap.sse.common.impl.MillisecondsDurationImpl; import com.sap.sse.common.impl.MillisecondsTimePoint; +import com.sap.sse.common.media.MimeType; import com.sap.sse.gwt.client.dialog.DataEntryDialog; public class NewMediaDialog extends DataEntryDialog { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/VideoJSPlayer.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/VideoJSPlayer.java index e460bf51f96..e3c3eeb5173 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/VideoJSPlayer.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/VideoJSPlayer.java @@ -9,9 +9,9 @@ import com.google.gwt.dom.client.VideoElement; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.Widget; -import com.sap.sailing.domain.common.media.MediaSubType; -import com.sap.sailing.domain.common.media.MediaType; -import com.sap.sailing.domain.common.media.MimeType; +import com.sap.sse.common.media.MediaSubType; +import com.sap.sse.common.media.MediaType; +import com.sap.sse.common.media.MimeType; public class VideoJSPlayer extends Widget { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/VideoThumbnail.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/VideoThumbnail.java index 9a31f35489a..0b4ac3b0e83 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/VideoThumbnail.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/VideoThumbnail.java @@ -11,9 +11,9 @@ import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.Widget; -import com.sap.sailing.domain.common.media.MediaSubType; import com.sap.sailing.gwt.ui.common.client.YoutubeApi; -import com.sap.sailing.gwt.ui.shared.media.VideoMetadataDTO; +import com.sap.sailing.gwt.ui.shared.media.SailingVideoDTO; +import com.sap.sse.common.media.MediaSubType; public class VideoThumbnail extends Widget implements HasClickHandlers { @@ -28,7 +28,7 @@ public class VideoThumbnail extends Widget implements HasClickHandlers { @UiField ImageElement thumbnailUi; - public VideoThumbnail(VideoMetadataDTO video) { + public VideoThumbnail(SailingVideoDTO video) { setElement(uiBinder.createAndBindUi(this)); getElement().addClassName("videoThumbnail"); captionUi.setInnerText(video.getTitle()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java index 34f2f065980..cd88ab3025c 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java @@ -8,8 +8,8 @@ import java.util.Map; import java.util.UUID; import com.google.gwt.user.client.rpc.IsSerializable; -import com.sap.sailing.domain.common.ImageSize; import com.sap.sailing.domain.common.dto.NamedDTO; +import com.sap.sse.common.media.ImageSize; public class EventBaseDTO extends NamedDTO implements IsSerializable { private static final long serialVersionUID = 818666323178097939L; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/EventOverviewVideoStageDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/EventOverviewVideoStageDTO.java index 3b44f820004..c1f607ed632 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/EventOverviewVideoStageDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/EventOverviewVideoStageDTO.java @@ -1,6 +1,6 @@ package com.sap.sailing.gwt.ui.shared.dispatch.event; -import com.sap.sailing.domain.common.media.MimeType; +import com.sap.sse.common.media.MimeType; public class EventOverviewVideoStageDTO implements EventOverviewStageContentDTO { public enum Type { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java index 8591ce2195e..1de1703ac92 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java @@ -5,7 +5,6 @@ import java.util.UUID; import com.google.gwt.core.shared.GwtIncompatible; import com.sap.sailing.domain.base.Event; -import com.sap.sailing.domain.common.media.MimeType; import com.sap.sailing.gwt.server.HomeServiceUtil; import com.sap.sailing.gwt.ui.shared.dispatch.Action; import com.sap.sailing.gwt.ui.shared.dispatch.DispatchContext; @@ -14,6 +13,7 @@ import com.sap.sailing.gwt.ui.shared.general.EventState; import com.sap.sailing.gwt.ui.shared.media.MediaUtils; import com.sap.sse.common.Util; import com.sap.sse.common.impl.MillisecondsTimePoint; +import com.sap.sse.common.media.MimeType; public class GetEventOverviewStageAction implements Action> { private UUID eventId; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/AbstractMediaDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/AbstractMediaDTO.java deleted file mode 100644 index 5123b305423..00000000000 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/AbstractMediaDTO.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.sap.sailing.gwt.ui.shared.media; - -import java.io.Serializable; -import java.net.URL; -import java.util.HashSet; - -import com.google.gwt.core.shared.GwtIncompatible; -import com.sap.sailing.domain.common.media.MediaCategory; -import com.sap.sailing.domain.common.media.MimeType; -import com.sap.sailing.gwt.ui.shared.general.EventReferenceDTO; - -public class AbstractMediaDTO implements Serializable { - private static final long serialVersionUID = 1L; - - private String title; - - private MimeType mimeType; - - private MediaCategory category; - - private HashSet tags = new HashSet(); - - private EventReferenceDTO eventRef; - - private String sourceRef; - - - protected AbstractMediaDTO() { - } - - @GwtIncompatible - public AbstractMediaDTO(EventReferenceDTO eventRef, URL url, MimeType mimeType, String title) { - this(eventRef, url.toString(), mimeType, title); - } - - @GwtIncompatible - public AbstractMediaDTO(EventReferenceDTO eventRef, String sourceRef, MimeType mimeType, String title) { - this.eventRef = eventRef; - this.title = title; - this.mimeType = mimeType; - this.sourceRef = sourceRef; - } - - public String getTitle() { - return title; - } - - public MimeType getMimeType() { - return mimeType; - } - - public MediaCategory getCategory() { - return category; - } - - public HashSet getTags() { - return tags; - } - - public String getSourceRef() { - return sourceRef; - } - - public void setCategory(MediaCategory category) { - this.category = category; - } - - public EventReferenceDTO getEventRef() { - return eventRef; - } - -} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaDTO.java index 702a0985ecc..cb4b30dac40 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaDTO.java @@ -6,22 +6,22 @@ import java.util.ArrayList; public class MediaDTO implements Serializable { private static final long serialVersionUID = 4932700214423641309L; - private ArrayList photos = new ArrayList<>(); - private ArrayList videos = new ArrayList<>(); + private ArrayList photos = new ArrayList<>(); + private ArrayList videos = new ArrayList<>(); - public ArrayList getPhotos() { + public ArrayList getPhotos() { return photos; } - public void addPhoto(ImageMetadataDTO photo) { + public void addPhoto(SailingImageDTO photo) { photos.add(photo); } - public ArrayList getVideos() { + public ArrayList getVideos() { return videos; } - public void addVideo(VideoMetadataDTO video) { + public void addVideo(SailingVideoDTO video) { videos.add(video); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaUtils.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaUtils.java index d017473629d..e61f0c0eb93 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaUtils.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaUtils.java @@ -3,7 +3,7 @@ package com.sap.sailing.gwt.ui.shared.media; import java.util.regex.Pattern; import com.google.gwt.core.shared.GwtIncompatible; -import com.sap.sailing.domain.common.media.MimeType; +import com.sap.sse.common.media.MimeType; /** * Temporary solution for mimetype detection for current videos. diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingImageDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingImageDTO.java new file mode 100644 index 00000000000..2a59453ef87 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingImageDTO.java @@ -0,0 +1,58 @@ +package com.sap.sailing.gwt.ui.shared.media; + +import java.util.Date; + +import com.sap.sailing.gwt.ui.shared.general.EventReferenceDTO; +import com.sap.sse.common.media.ImageMetadataDTO; +import com.sap.sse.common.media.ImageSize; + +public class SailingImageDTO extends ImageMetadataDTO { + + private static final long serialVersionUID = 1L; + + private String subtitle; + private Date createdAtDate; + private String author; + + private EventReferenceDTO eventRef; + + protected SailingImageDTO() { + } + + + public SailingImageDTO(EventReferenceDTO eventRef, String imageURL, ImageSize size, String title) { + super(imageURL, size, title); + this.eventRef = eventRef; + + } + + public String getSubtitle() { + return subtitle; + } + + public void setSubtitle(String subtitle) { + this.subtitle = subtitle; + } + + public Date getCreatedAtDate() { + return createdAtDate; + } + + public void setCreatedAtDate(Date createdAtDate) { + this.createdAtDate = createdAtDate; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + + + public EventReferenceDTO getEventRef() { + return eventRef; + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingVideoDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingVideoDTO.java new file mode 100644 index 00000000000..45913aa656a --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingVideoDTO.java @@ -0,0 +1,36 @@ +package com.sap.sailing.gwt.ui.shared.media; + +import java.net.URL; + +import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.gwt.ui.shared.general.EventReferenceDTO; +import com.sap.sse.common.media.MimeType; +import com.sap.sse.common.media.VideoMetadataDTO; + +public class SailingVideoDTO extends VideoMetadataDTO { + + private static final long serialVersionUID = 1L; + + private EventReferenceDTO eventRef; + + @SuppressWarnings("unused") + private SailingVideoDTO() { + } + + @GwtIncompatible + public SailingVideoDTO(EventReferenceDTO eventRef, URL url, MimeType mimeType, String title) { + this(eventRef, url.toString(), mimeType, title); + this.eventRef = eventRef; + } + + @GwtIncompatible + public SailingVideoDTO(EventReferenceDTO eventRef, String url, MimeType mimeType, String title) { + super(url, mimeType, title); + this.eventRef = eventRef; + } + + public EventReferenceDTO getEventRef() { + return eventRef; + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/start/StartViewDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/start/StartViewDTO.java index bf20c850c26..fb2d448a9ae 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/start/StartViewDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/start/StartViewDTO.java @@ -7,8 +7,8 @@ import java.util.List; import com.google.gwt.user.client.rpc.IsSerializable; import com.sap.sailing.gwt.ui.shared.eventlist.EventListEventDTO; -import com.sap.sailing.gwt.ui.shared.media.ImageMetadataDTO; -import com.sap.sailing.gwt.ui.shared.media.VideoMetadataDTO; +import com.sap.sailing.gwt.ui.shared.media.SailingImageDTO; +import com.sap.sailing.gwt.ui.shared.media.SailingVideoDTO; public class StartViewDTO implements IsSerializable { @@ -16,8 +16,8 @@ public class StartViewDTO implements IsSerializable { private ArrayList recentEvents = new ArrayList(); - private ArrayList photos = new ArrayList<>(); - private HashSet videos = new HashSet<>(); + private ArrayList photos = new ArrayList<>(); + private HashSet videos = new HashSet<>(); public List getStageEvents() { return stageEvents; @@ -35,19 +35,19 @@ public class StartViewDTO implements IsSerializable { this.recentEvents.add(event); } - public ArrayList getPhotos() { + public ArrayList getPhotos() { return photos; } - public void addPhoto(ImageMetadataDTO photo) { + public void addPhoto(SailingImageDTO photo) { photos.add(photo); } - public Collection getVideos() { + public Collection getVideos() { return videos; } - public void addVideo(VideoMetadataDTO video) { + public void addVideo(SailingVideoDTO video) { videos.add(video); } } diff --git a/java/com.sap.sailing.media.persistence.test/src/com/sap/sailing/media/persistence/test/MediaDBTest.java b/java/com.sap.sailing.media.persistence.test/src/com/sap/sailing/media/persistence/test/MediaDBTest.java index fbb932a9baa..2bf60fa11ab 100644 --- a/java/com.sap.sailing.media.persistence.test/src/com/sap/sailing/media/persistence/test/MediaDBTest.java +++ b/java/com.sap.sailing.media.persistence.test/src/com/sap/sailing/media/persistence/test/MediaDBTest.java @@ -13,13 +13,13 @@ import com.mongodb.MongoException; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; import com.sap.sailing.domain.common.RegattaNameAndRaceName; import com.sap.sailing.domain.common.media.MediaTrack; -import com.sap.sailing.domain.common.media.MimeType; import com.sap.sailing.domain.persistence.media.MediaDB; import com.sap.sailing.domain.persistence.media.MediaDBFactory; import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; import com.sap.sse.common.impl.MillisecondsDurationImpl; import com.sap.sse.common.impl.MillisecondsTimePoint; +import com.sap.sse.common.media.MimeType; import static org.junit.Assert.*; import static org.hamcrest.Matchers.*; diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/EventBaseJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/EventBaseJsonSerializer.java index d5d682ce31e..82c729f0025 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/EventBaseJsonSerializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/EventBaseJsonSerializer.java @@ -11,8 +11,8 @@ import org.json.simple.JSONObject; import com.sap.sailing.domain.base.EventBase; import com.sap.sailing.domain.base.LeaderboardGroupBase; import com.sap.sailing.domain.base.Venue; -import com.sap.sailing.domain.common.ImageSize; import com.sap.sailing.server.gateway.serialization.JsonSerializer; +import com.sap.sse.common.media.ImageSize; public class EventBaseJsonSerializer implements JsonSerializer { private static final Logger logger = Logger.getLogger(EventBaseJsonSerializer.class.getName()); diff --git a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/InitialLoadReplicationObjectIdentityTest.java b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/InitialLoadReplicationObjectIdentityTest.java index 7b1746d2314..94aebc604b2 100755 --- a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/InitialLoadReplicationObjectIdentityTest.java +++ b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/InitialLoadReplicationObjectIdentityTest.java @@ -49,7 +49,6 @@ import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl; import com.sap.sailing.domain.common.impl.WindImpl; import com.sap.sailing.domain.common.impl.WindSourceImpl; import com.sap.sailing.domain.common.media.MediaTrack; -import com.sap.sailing.domain.common.media.MimeType; import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.leaderboard.LeaderboardGroup; @@ -71,6 +70,7 @@ import com.sap.sse.common.TimePoint; import com.sap.sse.common.Util.Pair; import com.sap.sse.common.impl.MillisecondsDurationImpl; import com.sap.sse.common.impl.MillisecondsTimePoint; +import com.sap.sse.common.media.MimeType; import com.sap.sse.replication.ReplicationMasterDescriptor; import com.sap.sse.replication.impl.ReplicationReceiver; import com.sap.sse.replication.testsupport.AbstractServerReplicationTestSetUp.ReplicationServiceTestImpl; diff --git a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/MediaReplicationTest.java b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/MediaReplicationTest.java index 78740e6641d..ac9529085c3 100644 --- a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/MediaReplicationTest.java +++ b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/MediaReplicationTest.java @@ -13,11 +13,11 @@ import org.junit.Test; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; import com.sap.sailing.domain.common.RegattaNameAndRaceName; import com.sap.sailing.domain.common.media.MediaTrack; -import com.sap.sailing.domain.common.media.MimeType; import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; import com.sap.sse.common.impl.MillisecondsDurationImpl; import com.sap.sse.common.impl.MillisecondsTimePoint; +import com.sap.sse.common.media.MimeType; public class MediaReplicationTest extends AbstractServerReplicationTest { diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/impl/MasterDataImporterMediaTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/impl/MasterDataImporterMediaTest.java index ece6b4602e6..65ac05d2262 100644 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/impl/MasterDataImporterMediaTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/impl/MasterDataImporterMediaTest.java @@ -27,7 +27,6 @@ import org.mockito.Mockito; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; import com.sap.sailing.domain.common.RegattaNameAndRaceName; import com.sap.sailing.domain.common.media.MediaTrack; -import com.sap.sailing.domain.common.media.MimeType; import com.sap.sailing.domain.persistence.DomainObjectFactory; import com.sap.sailing.domain.persistence.MongoObjectFactory; import com.sap.sailing.domain.persistence.impl.MongoObjectFactoryImpl; @@ -37,6 +36,7 @@ import com.sap.sailing.domain.tracking.WindStore; import com.sap.sailing.server.RacingEventService; import com.sap.sse.common.impl.MillisecondsDurationImpl; import com.sap.sse.common.impl.MillisecondsTimePoint; +import com.sap.sse.common.media.MimeType; public class MasterDataImporterMediaTest { diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/impl/MediaLibaryTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/impl/MediaLibaryTest.java index 06eeaeed184..c2f1770f50c 100644 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/impl/MediaLibaryTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/impl/MediaLibaryTest.java @@ -12,13 +12,13 @@ import org.junit.Test; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; import com.sap.sailing.domain.common.RegattaNameAndRaceName; import com.sap.sailing.domain.common.media.MediaTrack; -import com.sap.sailing.domain.common.media.MimeType; import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; import com.sap.sse.common.TimeRange; import com.sap.sse.common.impl.MillisecondsDurationImpl; import com.sap.sse.common.impl.MillisecondsTimePoint; import com.sap.sse.common.impl.TimeRangeImpl; +import com.sap.sse.common.media.MimeType; import static org.junit.Assert.*; import static org.hamcrest.Matchers.*; diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/impl/MediaMasterDataExportTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/impl/MediaMasterDataExportTest.java index bf052d616b7..3f3dca1378b 100644 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/impl/MediaMasterDataExportTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/impl/MediaMasterDataExportTest.java @@ -33,7 +33,6 @@ import com.sap.sailing.domain.common.RaceIdentifier; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; import com.sap.sailing.domain.common.RegattaNameAndRaceName; import com.sap.sailing.domain.common.media.MediaTrack; -import com.sap.sailing.domain.common.media.MimeType; import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.leaderboard.LeaderboardGroup; @@ -52,6 +51,7 @@ import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; import com.sap.sse.common.impl.MillisecondsDurationImpl; import com.sap.sse.common.impl.MillisecondsTimePoint; +import com.sap.sse.common.media.MimeType; public class MediaMasterDataExportTest { diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java index a5d3093260f..b0d8e9ccb1a 100755 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java @@ -93,7 +93,6 @@ import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl; import com.sap.sailing.domain.common.impl.WindImpl; import com.sap.sailing.domain.common.impl.WindSourceWithAdditionalID; import com.sap.sailing.domain.common.media.MediaTrack; -import com.sap.sailing.domain.common.media.MimeType; import com.sap.sailing.domain.common.tracking.GPSFix; import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl; import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; @@ -127,6 +126,7 @@ import com.sap.sse.common.TimePoint; import com.sap.sse.common.Util; import com.sap.sse.common.impl.MillisecondsDurationImpl; import com.sap.sse.common.impl.MillisecondsTimePoint; +import com.sap.sse.common.media.MimeType; import com.sap.sse.mongodb.MongoDBConfiguration; import com.sap.sse.mongodb.MongoDBService; diff --git a/java/com.sap.sse.common/META-INF/MANIFEST.MF b/java/com.sap.sse.common/META-INF/MANIFEST.MF index cd2f6d8761e..1086559f24a 100644 --- a/java/com.sap.sse.common/META-INF/MANIFEST.MF +++ b/java/com.sap.sse.common/META-INF/MANIFEST.MF @@ -9,6 +9,7 @@ Export-Package: com.sap.sse.common, com.sap.sse.common.filter, com.sap.sse.common.impl, com.sap.sse.common.mail, + com.sap.sse.common.media, com.sap.sse.common.scalablevalue, com.sap.sse.common.search, com.sap.sse.common.settings, diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDTO.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDTO.java new file mode 100644 index 00000000000..b7177bdcc2f --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDTO.java @@ -0,0 +1,46 @@ +package com.sap.sse.common.media; + +import java.io.Serializable; +import java.util.HashSet; + +public class AbstractMediaDTO implements Serializable { + private static final long serialVersionUID = 1L; + + private String title; + + private MimeType mimeType; + + private HashSet tags = new HashSet(); + + private String sourceRef; + + protected AbstractMediaDTO() { + } + + + public AbstractMediaDTO(String sourceRef, MimeType mimeType, String title) { + this.title = title; + this.mimeType = mimeType; + this.sourceRef = sourceRef; + } + + public String getTitle() { + return title; + } + + public MimeType getMimeType() { + return mimeType; + } + + + public HashSet getTags() { + return tags; + } + + public String getSourceRef() { + return sourceRef; + } + + + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/ImageMetadataDTO.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageMetadataDTO.java similarity index 71% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/ImageMetadataDTO.java rename to java/com.sap.sse.common/src/com/sap/sse/common/media/ImageMetadataDTO.java index cd1ae3a5071..88010ba308c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/ImageMetadataDTO.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageMetadataDTO.java @@ -1,13 +1,7 @@ -package com.sap.sailing.gwt.ui.shared.media; +package com.sap.sse.common.media; -import java.net.URL; import java.util.Date; -import com.google.gwt.core.shared.GwtIncompatible; -import com.sap.sailing.domain.common.ImageSize; -import com.sap.sailing.domain.common.media.MimeType; -import com.sap.sailing.gwt.ui.shared.general.EventReferenceDTO; - public class ImageMetadataDTO extends AbstractMediaDTO { private static final long serialVersionUID = 1L; @@ -19,12 +13,12 @@ public class ImageMetadataDTO extends AbstractMediaDTO { private Date createdAtDate; private String author; + protected ImageMetadataDTO() { } - @GwtIncompatible - public ImageMetadataDTO(EventReferenceDTO eventRef, URL imageURL, ImageSize size, String title) { - super(eventRef, imageURL.toString(), MimeType.image, title); + public ImageMetadataDTO(String imageURL, ImageSize size, String title) { + super(imageURL, MimeType.image, title); this.widthInPx = size.getWidth(); this.heightInPx = size.getHeight(); } @@ -69,4 +63,5 @@ public class ImageMetadataDTO extends AbstractMediaDTO { this.heightInPx = heightInPx; } + } diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/ImageSize.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageSize.java similarity index 75% rename from java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/ImageSize.java rename to java/com.sap.sse.common/src/com/sap/sse/common/media/ImageSize.java index fb1182e2ec9..2ceb6d5b911 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/ImageSize.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageSize.java @@ -1,4 +1,4 @@ -package com.sap.sailing.domain.common; +package com.sap.sse.common.media; import java.io.Serializable; diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaSubType.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaSubType.java similarity index 80% rename from java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaSubType.java rename to java/com.sap.sse.common/src/com/sap/sse/common/media/MediaSubType.java index 45a7b5eeb0a..14d44d96de3 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaSubType.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaSubType.java @@ -1,4 +1,4 @@ -package com.sap.sailing.domain.common.media; +package com.sap.sse.common.media; public enum MediaSubType { ogg, mp4, mpeg, x_aiff, quicktime, aac, webm, youtube, vimeo, unknown; diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaType.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaType.java similarity index 57% rename from java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaType.java rename to java/com.sap.sse.common/src/com/sap/sse/common/media/MediaType.java index 308f8d99e15..f4cd39fc14a 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaType.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaType.java @@ -1,4 +1,4 @@ -package com.sap.sailing.domain.common.media; +package com.sap.sse.common.media; public enum MediaType { audio, video, image, unknown; diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MimeType.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/MimeType.java similarity index 96% rename from java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MimeType.java rename to java/com.sap.sse.common/src/com/sap/sse/common/media/MimeType.java index 377b9f20b9e..ce1bc2ec070 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MimeType.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/MimeType.java @@ -1,4 +1,4 @@ -package com.sap.sailing.domain.common.media; +package com.sap.sse.common.media; public enum MimeType { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/VideoMetadataDTO.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadataDTO.java similarity index 54% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/VideoMetadataDTO.java rename to java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadataDTO.java index 7545cfb79e8..0030136d649 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/VideoMetadataDTO.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadataDTO.java @@ -1,10 +1,8 @@ -package com.sap.sailing.gwt.ui.shared.media; +package com.sap.sse.common.media; import java.net.URL; import com.google.gwt.core.shared.GwtIncompatible; -import com.sap.sailing.domain.common.media.MimeType; -import com.sap.sailing.gwt.ui.shared.general.EventReferenceDTO; public class VideoMetadataDTO extends AbstractMediaDTO { @@ -13,18 +11,18 @@ public class VideoMetadataDTO extends AbstractMediaDTO { private int length; private String thumbnailRef; - @SuppressWarnings("unused") - private VideoMetadataDTO() { + + protected VideoMetadataDTO() { } @GwtIncompatible - public VideoMetadataDTO(EventReferenceDTO eventRef, URL url, MimeType mimeType, String title) { - this(eventRef, url.toString(), mimeType, title); + public VideoMetadataDTO(URL url, MimeType mimeType, String title) { + this(url.toString(), mimeType, title); } @GwtIncompatible - public VideoMetadataDTO(EventReferenceDTO eventRef, String url, MimeType mimeType, String title) { - super(eventRef, url, mimeType, title); + public VideoMetadataDTO(String url, MimeType mimeType, String title) { + super(url, mimeType, title); } public void setLength(int length) { diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/carousel/ImageCarousel.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/carousel/ImageCarousel.java index b6b1b7cab02..09c87896b97 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/carousel/ImageCarousel.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/carousel/ImageCarousel.java @@ -1,5 +1,8 @@ package com.sap.sse.gwt.client.controls.carousel; +import java.util.LinkedList; +import java.util.List; + import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.Scheduler; import com.google.gwt.dom.client.DivElement; @@ -11,6 +14,7 @@ import com.google.gwt.safehtml.shared.UriUtils; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.ui.Widget; +import com.sap.sse.common.media.ImageMetadataDTO; /** * Image carousel that uses the open source "slick carousel". @@ -48,10 +52,11 @@ import com.google.gwt.user.client.ui.Widget; * * Created by pgtaboada on 10.11.14. */ -public class ImageCarousel extends Widget { +public class ImageCarousel extends Widget { private static SlickSliderUiBinder ourUiBinder = GWT.create(SlickSliderUiBinder.class); + private LinkedList currentImages = new LinkedList<>(); /** * slick slider property: dots */ @@ -81,9 +86,12 @@ public class ImageCarousel extends Widget { * The height of the images */ private int imagesHeight = 300; + private int currentSlideIndex = 0; private final String uniqueId; + private FullscreenViewer fsViewer; + /** * Widget constructor */ @@ -95,12 +103,38 @@ public class ImageCarousel extends Widget { init(); } + public void onClick() { + GWT.log("Current slide: " + currentSlideIndex); + if (fsViewer != null) { + fsViewer.show(currentImages.get(currentSlideIndex), currentImages); + } + } + /** * JSNI wrapper that does setup the slider * * @param uniqueId */ - native void setupSlider(ImageCarousel sliderReference) /*-{ + native void setupSlider(ImageCarousel sliderReference) /*-{ + + var slider = $wnd + .$('.' + + (sliderReference.@com.sap.sse.gwt.client.controls.carousel.ImageCarousel::uniqueId)); + + slider + .on( + 'click', + '.slick-slide', + function() { + sliderReference.@com.sap.sse.gwt.client.controls.carousel.ImageCarousel::onClick()(); + }); + + slider + .on( + 'afterChange', + function(event, index) { + sliderReference.@com.sap.sse.gwt.client.controls.carousel.ImageCarousel::currentSlideIndex = index.currentSlide; + }); $wnd .$( @@ -136,8 +170,12 @@ public class ImageCarousel extends Widget { * * @param url */ - public void addImage(String url, int height, int width) { - + public void addImage(TYPE image) { + currentImages.add(image); + String url = image.getSourceRef(); + int height = image.getHeightInPx(); + int width = image.getWidthInPx(); + DivElement imageHolder = Document.get().createDivElement(); ImageElement imageElement = Document.get().createImageElement(); imageElement.setAttribute("data-lazy", UriUtils.fromString(url).asString()); @@ -209,7 +247,7 @@ public class ImageCarousel extends Widget { /** * UiBinder interface */ - interface SlickSliderUiBinder extends UiBinder { + interface SlickSliderUiBinder extends UiBinder> { } /** @@ -242,7 +280,7 @@ public class ImageCarousel extends Widget { * Apply slick js to constructed dom tree. */ private void init() { - final ImageCarousel reference = this; + final ImageCarousel reference = this; Scheduler.get().scheduleDeferred(new Command() { @@ -265,4 +303,13 @@ public class ImageCarousel extends Widget { }); } + public void registerFullscreenViewer(FullscreenViewer fsViewer) { + this.fsViewer = fsViewer; + } + + public interface FullscreenViewer { + + public void show(TYPE selectedImage, List imageList); + } + } \ No newline at end of file From a1a505df54a8f0505811c9827cb809696da414f7 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 26 May 2015 17:10:27 +0200 Subject: [PATCH 19/72] Bug 2816: Adapted current version of fontface declarations to fix "Light" and add condensed variant --- java/com.sap.sailing.gwt.ui/Leaderboard.css | 3 ++- .../LeaderboardNewHome.css | 3 ++- .../open-sans-condensed-bold-webfont.eot | Bin 0 -> 20220 bytes .../open-sans-condensed-bold-webfont.svg | 1 + .../open-sans-condensed-bold-webfont.ttf | Bin 0 -> 40244 bytes .../open-sans-condensed-bold-webfont.woff | Bin 0 -> 23036 bytes ...en-sans-condensed-light-italic-webfont.eot | Bin 0 -> 19808 bytes ...en-sans-condensed-light-italic-webfont.svg | 1 + ...en-sans-condensed-light-italic-webfont.ttf | Bin 0 -> 37960 bytes ...n-sans-condensed-light-italic-webfont.woff | Bin 0 -> 22604 bytes .../open-sans-condensed-light-webfont.eot | Bin 0 -> 19063 bytes .../open-sans-condensed-light-webfont.svg | 1 + .../open-sans-condensed-light-webfont.ttf | Bin 0 -> 36420 bytes .../open-sans-condensed-light-webfont.woff | Bin 0 -> 21760 bytes ...webfont.eot => opensans-light-webfont.eot} | Bin ...webfont.svg => opensans-light-webfont.svg} | 0 ...webfont.ttf => opensans-light-webfont.ttf} | Bin ...bfont.woff => opensans-light-webfont.woff} | Bin .../sailing-fontface-1.0.cache.css | 21 ++++++++++++++++++ 19 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 java/com.sap.sailing.www/fonts/open-sans-condensed-bold-webfont.eot create mode 100644 java/com.sap.sailing.www/fonts/open-sans-condensed-bold-webfont.svg create mode 100644 java/com.sap.sailing.www/fonts/open-sans-condensed-bold-webfont.ttf create mode 100644 java/com.sap.sailing.www/fonts/open-sans-condensed-bold-webfont.woff create mode 100644 java/com.sap.sailing.www/fonts/open-sans-condensed-light-italic-webfont.eot create mode 100644 java/com.sap.sailing.www/fonts/open-sans-condensed-light-italic-webfont.svg create mode 100644 java/com.sap.sailing.www/fonts/open-sans-condensed-light-italic-webfont.ttf create mode 100644 java/com.sap.sailing.www/fonts/open-sans-condensed-light-italic-webfont.woff create mode 100644 java/com.sap.sailing.www/fonts/open-sans-condensed-light-webfont.eot create mode 100644 java/com.sap.sailing.www/fonts/open-sans-condensed-light-webfont.svg create mode 100644 java/com.sap.sailing.www/fonts/open-sans-condensed-light-webfont.ttf create mode 100644 java/com.sap.sailing.www/fonts/open-sans-condensed-light-webfont.woff rename java/com.sap.sailing.www/fonts/{OpenSans-Light-webfont.eot => opensans-light-webfont.eot} (100%) rename java/com.sap.sailing.www/fonts/{OpenSans-Light-webfont.svg => opensans-light-webfont.svg} (100%) rename java/com.sap.sailing.www/fonts/{OpenSans-Light-webfont.ttf => opensans-light-webfont.ttf} (100%) rename java/com.sap.sailing.www/fonts/{OpenSans-Light-webfont.woff => opensans-light-webfont.woff} (100%) diff --git a/java/com.sap.sailing.gwt.ui/Leaderboard.css b/java/com.sap.sailing.gwt.ui/Leaderboard.css index d879341d76d..7cb4a5fe4c3 100755 --- a/java/com.sap.sailing.gwt.ui/Leaderboard.css +++ b/java/com.sap.sailing.gwt.ui/Leaderboard.css @@ -124,7 +124,8 @@ body, table td, select, button { } .bold { - font-family: "OpenSansCondensedBold", sans-serif; + font-family: 'Open Sans Condensed', sans-serif; + font-weight: bold; } .trackingQuality-circle { diff --git a/java/com.sap.sailing.gwt.ui/LeaderboardNewHome.css b/java/com.sap.sailing.gwt.ui/LeaderboardNewHome.css index fdff2cf102d..92284e0e13c 100644 --- a/java/com.sap.sailing.gwt.ui/LeaderboardNewHome.css +++ b/java/com.sap.sailing.gwt.ui/LeaderboardNewHome.css @@ -79,7 +79,8 @@ body, table td, select, button { } .bold { - font-family: "OpenSansCondensedBold", sans-serif; + font-family: 'Open Sans Condensed', sans-serif; + font-weight: bold; } .trackingQuality-circle { diff --git a/java/com.sap.sailing.www/fonts/open-sans-condensed-bold-webfont.eot b/java/com.sap.sailing.www/fonts/open-sans-condensed-bold-webfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..fd9cd07f21466e143b9cecf292f55e00ffb3cb2f GIT binary patch literal 20220 zcma%iQ**19 z#|G^P5dV+;e}x*L3~&Kh0-XLMsRK;^v+n~x_+K9n zp!FZ>_8-^wf0<+eHURT~%Jv_R_5U*>+5Z&}01#7`R{4KV1^_?-+!g^`%>Z#J0D}$2 z+-2;fkDm6FjlQc~kPpbb*NxGdQSy!Y4Mse4mjL`D_VwjYI$V=T61#(j2~vH$LFkE6 zor;}24(GBWgi(~1ikyNqiLJS$O>o<4U5b4w|;J~ zExrZ&J3sf&((h9`+Ov#41L;P+$()X#xo6n~e?p;IYEVnjR(&}#sTsLMOAn;5H1OUYK@&9a`l<4>?+lKY3=m&2EG{S`^b!HmT@(^Q@ z_gxkQ*rx+Rk+Iz0COqC$pO4Dg=G)!};K*jG$xGE_-605Di zsU%z@m_?DE3bHSTiorxWaI6d=8OfQ|vQfxjY3_JcyUcnLDkI%sbA|hic*T}^#)q}L z=q;Uid>_B$G5wp3@B@}<0O^DYOV>lvXQU~<3tP@w_7f&qU^L9a;7Ity@=)sEspNJD z5{^Bo&c+NbeHK1G*?8z1^%v zYtUH+f6QCbaU*__Qg%-UUtFXVvlFu!VVI2##=Qa80~L#QZDm$6N>2hm5Dg?&_^SO? zH*gtf*Dg3kQcSM;nfo#n@;F*%=Ov#ZYY&N3^8dO9Q`|aHzx_)L9?W$$Cd8>GsV%XK z(?~Ebw92eCuIU?lOO1r}TW2gG&E1{ss%yJB1cbat*H+gjP5eMX> zT3outv{vzlx#W3#FLOpwu!;GuxmXISzT(<7FD_1xl>zrvt0+(z)@z<7HJe$16{Ins z=(9)E9pWYhtsT$kvI*s@7`cB&vn8wRVTXS)pe8RB&bDpuLI9~BPn8a^8`e0% z^Oa#$UwV6CJ+ZyhT+eTkmj3*;qQkMlLY}GFh&waZawpT!Uc$30a+TrM^{YY~c`c1Q znj%~at+}48(tm5oFEmdI-fItRMfnTO6&IsdAXd=*ZRn5kLmPxTgnk?rJn69LB(dnC zRtC&jrl3fqt@>!j_qNjm){m??H~w2nKB~3d^pDd=?fBfE=QKau6W^czaX{S?fxT75 zEU7g#WelZSI8w_Mg4L$j@!ewx;b`DovUX9?{n3eJ$i=A85JJ_Hnf=^%iikchU_%3G zP6DNc1C8mHpPR&9>Iov)ib*z8ayuXbkPT=bOE{*MA>WJ<(Yk5L?9MGcfp}5AD4!(2 z&@7~QYRDcFFhpLpUq0OwNX~;(Y6w3J9a>sZ{MFbKj#g4EcDhBelgS)Q;Y2ZX!^j@V z^YNU_35el9kE*6M`mHAxB->)u@ojJoja4O7=J!lFHn&%F%B_PiJ6dWB1~1!WBwZXH zZCjO;5Zfd+0(U;{GZrsKT`K@DRrH~c3Qwv%g~;bTrh1pbV@f4H1r6-cPl94^Jgr4Q zC3?EAGQhB%)JS!s_iM)~5X6tI?vBV}1wxX*aVZ!3iOUgXjm|vuG(lh4rU-^i9@COLwl2&T<>%>`V~I#^RMTis$}$OhTA5o@swqGR8@TGXe^W+ zoZVIeDtG?lp&TXa{%sqBekuVy1y%`Fbg~9#g4W~TXbucbo?m$Al5~b`6FS>(cmVC= z5P-pejA znifl(o#-w@9$2%HPL#1o=cYu|SsgJ0n+17U{46^2OIi+}$lAkvvLRYVDOeTV#OY?{ zA;1?zJ0$CezM`$G>TwjKoaoft+k=Guq=X{vpi8=SZ%n}z92JC&AEK5SpqL+O1BH~l z&q`%68r`adc}C*NBu+zvL5{aE%>!D=_j@E}^3QaBcy$-uU%>NG(tJi6-KJP7fonJB z)AFsK!)3!R19Q0m%5LD2Y!SX+5+$ z9fQ@A+{?W~5MPuIKaqn-FOD2&rPe!?jGcQllu1uqw*D%CDe(D$ zY1f=O17Z>6+DmxYbHi#C<5tx#LpuiXY*_?q31AfGBXZ!66PM?UwO$=e63OXTpF%iu zwM&`orW*@PXc4vIYr^O`Ry-&!{kZsBc%C(}Ib*c(x_1ZkU5wWwX)oG0DF6{LY8Pau zdQEb^9lYDaiJq29eLWu)$r)uKFmH!+Bdo#1j9^3UIu&LooIc%&L;eG|*uAMFUiF95 zN?w?>vS?!u1?#Iq_>&6V(23k@`!hb;6G$Yn%LiFJ8k>P4@p^0!M&!?CSS zu|qefI7hYIc%MZUeCUXNN1o6lyyQFNJ4^Daz=}<&2k(jrJ>Eivmjd?eFcS!n3XF># zfT^CRBwLzLQn6A!1d{^3C~&1*iMLJ1o2i~e($Lb;BULOdeOlK7YD+Bu(kwUyY1*71 zeP6J>k8GcBVcjIAkYq%LI{TPKl;Us(!SmauNh==@<#bYj^jeIeok>AFy3ZcGKnC&Y zTaENw^WeO$kX%qk^p;|DOVpxl&zLT}&tcPu3?ubd{f&-&vP|>qqpNN&Jp&>#KIb%k z7!<;0HgfPnmYNL(3EY6qYz0#jlRETjX&y{J9=-#KuPGUjF~=`i(a0podtAv2;q^S> zucg5B<;2w)yMKPmcagAr<&ri6cBGDwW%){znpkO~6GrI0AGIVQowk`SPmcHFjQSzfJn3^}i24%BwXsa_C= ziDuYG9HSQSiVs~y*TC#i_jTEO!PJXjN`d=gyEuAsH>EF6@ zIhFhTM?}>8M}~iH70Mse=`8sn3g1tr2+yHqgLpB#p+lLtI84ixX2Y9#68&&mkIAGA z(9s4`CA@P|Fj^AU$0vHGSkpysB|tQoJaU|b3^ttLMF^eU;d#XnD1TjSZWrXd~j8ggkQ!hJ6ES8lm?V-R{5y z_ZiAG8n?ey_F`NdK48^h~X@`(+FHUyq?j?v35E3J7ab7nj5%F`eN)|Oxe6OKnA7a&+fo0g% zrdrP9G+@a3ee?D>N72%xO;!yq!ew(dIV!|uI0vh+`{JY!-7mh9W3SnB+Vk8;flYViZbPlfec}V7 zCASTV>2e^viY!%hXpt8OLdsd|MBD`^HT z;wG{Gu7yeN_~UNR3*1jjlgYCV(cmPh!-sPlS6eu0AnRwpf4yV@G~w-e1Ew zmSi;B4EoAw&|m`BEyRf*Cg8eS(AJsw%4`b8>H}FAS~io%m4y5MJ#5o)?J#y;N8#uS zZjXCfXh=lRP$s-Tg(?Gfd1rxp8;)q)=v?7M{H@C!$!lnNK}0#~bl3f2Dx}vTaRDdg z+pCD7Y!q?nXZmDI)B!;&QMql33duSJqx1ie<@8X8 z?}~GD_ZP@rvm@h(_=i#z`wJq@?rqaJ7P`%=#7rOjBB7=KZHtA!WIU`zceS`M_7IcZyi;GRWJMo!%|9dRG5irm*D0nGWjNUA{NBpj=j-;r`y|>|LMOgjGs%XxGeO~< z0*vkoI+`t8nwLFi_9Vtzd-2<<;xzvBsS_aa{~~0^%k3}WIZT0T0OeuyTaJ1r9_w@0 znKk^oQ9^GYlELoGixj}qRcmUohDONph++4MOuvy5g2eVlvojmE7JXtu0BKv4qf!k( z=s>hA+waKeu1I5LEny)~%XLsp8Ih58*rvgz< z@_4j^JL#gspB{mP>t_xX&D!~Xg-hg4ihfe_o{o5G=%}=I={IlYwjK!J>Fwwu$LvI16In`hrjZvzi_* zg0aAgM7#H2BHs(mND7ec_QUt}tOI_G&Et47=-dbC@Y8IF<|vG482uPK1Y=2tnd1E= z6$iMox;;C9*qFrtHwZ4m6ZO(ML)6XldycQS0bDuKcf^FwmxctfDz9H=5mJ>UCLOnl zGZ<#6?~MV|NOK6n#$P|BW>+y8r^AwzL6<=&XoMBWf2jRVSL4tv3Glot*mN)sGm9T( zN=NINTGd7)V|ZPj-xJyhZ*nS2aAE%jT7!otme>(X1m-%UIV?0e#1MH%sN*IkI?5&3 z3l$HqEpl2?lstzJmSwBwUSugBM0H!NR7OlYgDifP6zDE_6#IiD|hZb8ipX=;xz zf@Torb|w9Ma%I4QJ3F+5>cd7BXqayf^E-(p-oZ>s9S5Lv)12B287}?7VIuPKjs-ia zjd8b8wTFeDtX(~jV?K1WaP>C)f!$zK=o4WZjL!rVh(j7xfb9U zhqe-PFVc4ziGj{2eTi1{=yS-XI0Eerb(mcKONQf^~(F-_=pLTIeXBCr-uq zGMd3hJDlENe=~g8l6p>d1XJxDSfV*g4_m@!ZuTPc8Ekl1Aa%led~Xh$3Sq)XuL)5w z?iBf3XxWcyD*G;(AQd*K(sw+@5q)h{!Ee*Z&`Q01q5j0#WaF-?4t3+Nac38O1qiFn z_*2^%vn)lGg9F&~rz0$1*%zbHFZQqKIMM>rjA(KU)IXW8$1gSsV|ob8vL@{b69X_$eB?c;Twkg&O!l(*<`3zsC5iT5;i#%^ThoOpTZ z7B{0SS`vIz%aZOGd?tgT(3A%mP;&DoH;3(}nJ8E$t)yRrRR|c@+nJV+c?{rjHfsj$ z*n~q}Mijxe71-K{(e5qvXevDQcl`=|6%T`WORA|d#$|Q|P{bo+2moHso+DYw^rt)x$~TCwwP_@E zX+2EpDWa(h)=wfYf3`=xLJ1w)Y)SYOfl`Z#-&QRrsc!A410O{Xi#r(e{tnVHM!Oh@ zr}`*!D)KofZbEI|S>b?bs;(GS8h)DT1x1%qoO$uR4W%#T)77>w>ge`+#bN}d7SJ$o;u#no}v5%iHYQY%@Nxgm+diCYsXy}i#UuD@Q(9Z|Du$0 zIHEp=r^Cq+99NhRl0C0}G9aKAHil3~&9j3wT;Xy`a4a$ORR$j$Qq~0U1P8F?w{=t? zqw_bIVlBHc1v`GuUlC7_Rn1=J6E?$_QF=9>_*mJ7uvi`|Mb{!!r*dG1Q#?NL3QAWv zGo19*i)DRh<+Rp=M#V+$ohzf>Hv$(JB6<*gEc){^IAV#nLik33l9R43M(<6dJNjbX@oln`kgz&K~M8 z0vN}^27&bcoYLsX_I<)H-Ub1KbVsv=hdmeThz$!uM8mhUcGN&iWYm9Um=xPh4#XSs zHg4ZO%w1!(c>g#A*R{dJnfd6}W@@FzD=F1G-uzF6unRrT# z*A<>DOTFy3n%wDH#(lw|@?% zFOK?;1Db5Xj&sb*0avpeQbBO{F7Mw8&s z;~XR6h?!3C2cCB`p&FhVVy4$f<1raJnvixv%n|r5`BZOsG7_(AMB5isl#>(9`1Xa? zHF}_vsMGb?BY(l}XDNyW_wU+!FE#!r|7Y?7eC9Nk%(UIfd@vc3=Ur}}tiZDsL^LZb z9FFs8&-wJr82?GqKELvQ5GMeyn=l2}I-XlVI#2hbc=HHug&NN_MS)~`c;@gji$-b+ zwzXPTv>l1b5qIXJ{(1ExR$pKlO$~rPTVz0Hl=ruzg@Z1&%+V#|Em}+dOWdM{V3FK; zdKUuoT_YAhq!ycZ$(*#~X*-jgY9%7Qsq~RUT*N)Nm_hYIA)(^agmh+_ascW~rx$|s zcRi6^Xg*BIcf`9#{Og%u6*6v=Bfhv&aE z|L4@8Yxm!fB5TA3y_BiLjcnKzDx)>e#P1K(!Z5-;Hu=dwVV-mmv8RVbqaua#?NmDCA5}v}?OKMkOx#W|JZsobceJ z-Kkr;B8T1$QTDg*`@09ZF(w`scNYWF>XbmtmWX2^2W${BW@xK%+EHob+Mk30{$(ej zGdg>vQRgeHu9#i~Z_cBrVdGWCaB;sRtkqwT7+_`d#t1GT8gFO_@GM3d5%2Von}o#B zW8D%j>QO;5j%Z5yV@l~NIOytnR&u&48EB*xhr0yBRH#rR6bXi1#~jFTlicuqe8LeAnsPPmERalzPpE;d@rZ=}cS8 zVzF^Nw#Bn|Z>rwp=p^bGMk3}4QckupRe5v_rD0-QEaEAPI1rv2BJOX|;g_7L?ST|= zkgbi<2xY@u9i!e-7$aswf`q6OIN=z@MDV;EDV#)r2n{V$mUmwRa|R2_>85m0(jXfX zOmN91(MI+soQ}sT8%yO3j}#uar2pT4z~TCk*T?isT|IM@_7nWx@)xSa5zCg<+za@+ zDCV2#TG7EVpXCS#99(STKIAQw>9E3mc#HodWDx3@doeVn%wr_>GRs75d3hYR!b(|B zf|r8kHw+By8&`Yi*>9GXT_m&ZqZA`DtMI{!C7S+_jec-DHJkbOvwMZr{iHr3whC1!1f){NSr zH5y##6G@muuH@8Z{suzx_HZuX&^xt@d@6bdrqYX$H^wP*noUF?%%n6;uFZ>!5!t!; z{V~b@Ac$#>g%d4Qhz*nT+6JrAC1f^A6GV|v%ZV*B*$Ul;t6;9>N=lQ2OJKWbcDT{g zLg@@YF8`LYgYisdH;a*J9f#OAh+?)j!J`1CVRV3Kt(8h2^~ik4`~Zt0x$m!8tR6-w z@eU0;F3r>E0!s=q6=Sl3y+2||sDCXHeofl&);rSjL@5X8EN|GNC5n>!lM%)KrKOi@ zgkk(lI_%H)&|&aaWz5ND(!5g6)@kh6W|fa|u0J`$W9d9V>Ksos5*FELXxg4MTO(&e z@!@S_)<{ORWNw~HRtPL^oX0w7SKK~cRRc9mD11xE@>6)Ugr#-6vTxEB&L4K&th1eW2%LU7|ZODU!}PlB;3|gRs~Ij(^A-lGtO5~=4~#2b=%wi zi2(Yz(-xE1Yy0xvwu6wp8Nng3Cw_lJb?y`*x3LcviAG9;FR=x+4DsYriVo`o#ik{HnnYbAUU zn^={UCPLe8oAC>~fmZ+`$ZM19!s(=Jh{XDrJLbl425heZlnCO?H7_&MzqhVzKlc;0y4t}~O3giu82SS5Z zD=~Ip29-CUIDts+rj=AyT3;ZBr}Cw1-Y3`e*3P;xxHWBXL`XO#0rY$ruA!)5D(aae zzC-YHrC)AhrjY#XNtX?g)oUqX9_1+(Sy*yy?U9Y#jo>3)!Sz2dAS@8qsHC!`ysFg4 z{P!>SWr>AB2gBmnlXB-H#N40;K42RQFEKsJH9N6+FysIgI$;ADRRj5`LjK$p#vTYj z8u;*P+(7FBJL|2q8ze(WYjo>1gSI&_He(`CNnAM8i?&%x~>j*?|4d#~5ij02Uh zffv8XH3_oM8hN%U5iwI4bm(ar#$S@jW_%Mw|EImUUgvkg0p((FhHojhHcbL4CzJ0n zvk7XqM;0u}4_9$w-#G#gh5DrNoN!|(j^8GMeal~5P(sUHoiC0{Dw}V*7iJvI4oI<0Uz<>4ZyQxP z6CxBdu?s`#hvW2BT?^>rdcS>qf;Q|AWyV55GV9X}_bpF#aawMngD=wX)FaY#xEOLE zq?X{}obv*W#~PY#S~t7!S_Z;EBBtxDrhRx9stepTv#W9i1UuX8dspLNVzQ-2Q7%IM zBi?Y~S9hV$JLfZ<7_jWBkD3E8d3LEX4oHhl;q$iQGNXlw^JCv4|%gjTZ64*vW$$ z9q6$`7JP#%F~b9{eY^PUB!|@)gnhj7bXTsIkh@dd^XAnq`GSgcz z*d4zFS`+WWtMH6-`(}s(38N+l0bnX|f0bl^k)!Hn7R1)k6MnIgp8k7>edpeHWq@D#e#r7OPlGNQ zi?DvkqULV&x3a9<50uQlB2Q+Dv+(?h#GkUeS$D)ju z335c0jwA@UHdXUl&%0E_c7~n5#}hf$_bh{RUukeps$CED%Hv_E{tc+HSPf&AnYH4v zBiUp-RjNo3@&9AXvjc~b1`Eb-dMb>NvF!v-;YWo@<6jP6X(keHp}}-cc(Ig zwq3y3-DSfCB0|ncQm}E(H$#TlX#m~apd%YGJ+ZQy8j}|@hojH0%Z=BK>5Q$87Frkj z{!x`|dqoW}mP!et=<%M=mCm72-Jf6CN;fE6EtnW^0|d19O5;>GCFYwZT62x%^i zeo7M5)|-LE*Oe_H`!013y*=y@)ie&3(W{T3kooX0pd%Q-6HJ-U?t-dmM}-j+^0kZh z@XZ&2V<_;me=c_=XGX}_%^EAA?b~+MZz#-ZsVzFfE0@USIq${SFaoovWp{i#E=r^f zpib4e)~ForE$<5QSPteuEUp1wM}VS=3zn3tHM-t_Rl6cF1R6U13@I3ePwL;MjG&i2UCm_+ux8cXM`7v-$^DKr0d*m50@rs{>~)j% zDd}JxPdY5I4uW?urZ8-rK^8&zQZzKsG=Xp^7DQa=_qC!sX)DY%uRd^AjJ+d{&%_`5 zPG}>XRP5CANc{k%SFEq4MR4IKCYZlN|Ll^q!q~RemyY4oglHxp(mLCTe)0D8&Kp~^ zuR>X*J?Uiem)ObeH>9D?n~^pQd|_ntPmNpAa1w&K+x-0bddbL9mDxbJ+pMc*-E!QA zOhZfgAB(b%|LAoCS6#({6K;$x46uTd&N^$4Oa^NtMkk;(fD`n=?8kDM+MSnM5Y5F=p zQut#JW+6;AO(L@6!*L+R0&ApYt8QDTY7>ioxBqv=ypj{6YEuN)bk<=TCkiIBLKcN`Bd&1pbptG`-l@rv(JkB|R5;7c0 z<`$zXC`qNjnH-Cy^7>D_7kUUs(A}}xxFEx440$|sww&D0L~f8~*oH(Gu(Q0N`GX=x zm z^qcy@44vV54Dq$-oA090=e@d~9d;VaJ>K7N0>?t{>5W_%E(Sth{4ik~vSUuPgH7|; zFzwbRF4yWKbggt}%&tQ^;QcrS8%or1mr-Fn08n7X9 zlhh{VWic05o_hkN&_a&Aw+3!5QmO^HI90Gz{BqmrZ&r_iK4lj-*VfSu+7gpckyPIg zk`4aZlqEhDeuRM$t#!pi_JdnEhx&1~xnQwBX3P$R(yB>r$&-NTV~!E=MmHM7&Z;3z zM}=~eNPI8}9`wlK&9uRyRR%rT7kt$!Pb?S1U^O$&3B47OT4o&fRyJ+(7J0b`P6c}+ zk~UXIEA%SJ)Mipqbjg8NMs4JYotx~QN&l)eLw-G7=Pq#s3U6XqNT5B?ilda3h%5RV zBq6|~SwITir5OCfy%FT^Ms)w-@9KsYRKULeY*azyI~30W_1)lS`Vd6`#vB`WSa^4(hMk%c2~QmeS_CDM z9r{}dtC)-cbMrqwH6ijwq+DVVPNFX6Cz4`_a5|r%jNi%@IRmgkR0O!9Ow|H!414Q= zP#%4@ltb{7h=C)Jq3;Q?4AMZ=S}{yI2ly{|lL_l8dl+#YeOU%GPPJ=n2E6`+;8jIa0)6^64 z8;dsD`|WXLFjBcljyp&@Fb7OYPucA+&vCjz+UYh#%|8p@C~bu#AZtNYHKHFZ9&Qo0 zD1fD}a2y!l;FDbPuQ`ubC?g$t>iy6zv4?(>t~*{1Bb#L$)i@0a8*Q61@O@`x&d$Y>21bJoZ_+-RJdR+ohfF-PgO$=0bBy3Z ziOak(m-(TJ03gt7`4OG0p_Qo=qYF3eIva(^8c=co={8$TuRx(n$e%6YjX*XblV9)t zvAIq6X*0IFOC5FR3d0%d>lMcQkDDV~wo*m>oaY!fxp<_GF?emN?}N};7UB>NT72k* zAK3`VFFeU$=7=Y#;IAovZoW)rv2LD; zm9?iLB-QIXny8>clBJoFyON0^gLJ39Uu@*P{hfD@by#IvpCt)A>x z3f+e*V@(aYdR+&`7a_5$_0KKq`omB?_DvE8oA(BaZKoSO$FPNmX(|9m^5oB@WRRep z)a4662GDsfuVzghvi)U$6Vp-s&rU|?EXYVgd<^S}ji(E-qD_wfXd#oH1Xi*Vj!hA5 z3Mo?^PsRkMSOON~mu&A;jhS4K>{@~6Cl)#%UYj=XZTZ@a7k=)0{Y?>Yma?E#BL552 z*tiLbfuSdKxdYd6r8Fg{wQw=ZX>nq;eDA_j^GSHN@A^yFfrOC_me^a)=mz7B!w2$_ zUvVgZ%PqvNnxeNcF~clBad>PawF-&tVF@Q@>WH||2*xL@jS7MV&dDJ8^NWzt%LylF zg!5C?Bt6M0>%*p+*wS~MmZw-F52XuC8Qg(tauC=mHx!l>WdeR*NAt>9%Mw+ znHY%CA*nZ2E+waEo0CNs@3XD;Qs~i5eRa}*h+{!mFPr!I&b0|Y65OcRFY*gCz$7I> z&PT*f(I%fQ%L%I=1r1K_4n3xi!bMEXx8O7#Sk>_Za8&xK*mX7h*0$O6zY|?FI-QK{ zM^~u!CDskuO=h8XEaaQXFKkj0XBcuYBIH$`8~J%c!LxUy-bPU~S2d%3^HcYT4w9?f zeZ6ihj8MXO(OSeQxquEA-S9aTu_}+;777h-AUlBDbJ;8fR&y7L-6XR|VixJcN| z)0@y?kLHG?BYc7j*2_OVDJ-rI9?s5%R)X^WuSahG$WxFhg+>y~ySYen4IrPV}PSWk(-AzJNd?tud z{rXL+xn_f8?Tc3iEK%$Ik{y0h{|3gEH=tydK*#?B)+1T%JvT;!AqFUXjbfq)728UZ z(a8&#z)snH^DB_GI|7>Djht+)ag}OKyu**^)-2qIGoHsHKLTm6Ulw8Ak8Un!^L=c{6w^C&V1WEruyH z9Gq~d)GXe+4O%q=DDOPBQV|6QNpMx?!jW%w5nuh4h#PSiVZX~&Lwo&k;FqIOy?!eH z!U2>C+{8p-m`%6?RJLh!4ItZav|o);irw&shr7*MQ)6u$;&5f0#&nidiF)q5gL=+T zac~N>r3B>q_+&{NCIJ`)s;%$p&Tw;OriL;L#eQJ*eGR#&QLO;=avVrW$7))F`(x;% zF`r0|7!+>FXp839JakKeMJe>^0jxhI>rC?HuCQuac{A?FfL2Hi3j%7JbcNxLqH*$& zudiVhAnZX4SBm0ixh6SRjIL`pV>j?PFQuG9ya*%RPxgiXeqCVm-+1*$eoU-2e`oz6Q%U^IAdWW*QTU^W zUwh~o%K`2|=!7op2M-FLH^zkrPhURSA+*Dgj%k2fk-#DB7vuD9LjYnu;z=D&ze*=l z7~;r!7ot{{yxT8Au#-|D`#gp8qn-kVNdP|bv8^|Q`^WT^ze792n1Y)G0aS|#Q6ja& zE*?bmblg~Vvt^9*pa1IVp}cr#aLw0nNuNz7YR9B8`m_8-3C;~14i+t!NGJo2DZ^Tx z(5MT3jj75B9z@^pC`$jdG`0jo2R+=QV?B3zIxnLl z0OUeMxT@@TEhUC7gh_YspJWZHoC0TUEe70((2<<(jZk`WW%LU96t(R95+mri?@F%7 zdNLNW-^eR*Q>fJREyZ%DBh`LKIejz6jeS#!csgu2gZRv5tTFU}-J{2tF71NjJ3^}G z1SQCsfxBBIo;QY{@}^(SnrcQ>=_3P1qUsgVEqy zI(~fks4Y%RSwUj)%8HATm|{M24?rb0r-c#P?#y$JQ?i*N+J>_<{pM6=aC^_*3;%_| z!d{eJ?i}#O@)YJunLP|JR}N7mWhFC5B70n1P1&+lC*c@l1@QF#8pUUKs969&!kmG; zV9Vn0;?RYplJT2OlCg5oN2d{=K+r!$PF3ntV!sYLP^?FTU;aU|iX;agMbVy2Tg?|? z3VMI5)=W1%(ll9>uBJVmfF?_O+ZW@E{Vt=i(OX$pRmCBRbv%aVBagIhuSHiO;(KO` zL@jbtWWG@Ng6Q+t!Cv*|gomI#%)^(GW%r>cC(iJ$7Bgpy094FlPmrl0c;vypw1pKN zNnto>V(-8v2fB%;==0#%Hanm0%3^~_X6|TK-agkH+-|?Im78BVYt9i2Uj~nyUg#>) zRrRi=ZEt!y5xWY=QZwAU95f(c^92(5b`R`S)eE?4P@emAq946Q@b zw;7+GDFzAewV$1eNImNdScllo=)=h#ADb33V^obe%jr&*mAf2C z4~KpD<}cA~_eLWn6vNFgKR9+6H?>@b$nqDU{Dt`hc{w$#=p}f{4H&Rh6$5CQgKK+73^KHaD*5}X)vlh4(SApiM>aaoVg>C$Pyh!|H;+zIFu(Y$+!+z#E)d zk`PPRe#0cpTnY{@J;&Z~CT4787y%Ll@CW=ZJ?r+yeLt9i8fdcJ<6?`P=wi*{^pRow zqNxD*zuKQv=AJ2V{^3p%IFhrp?@YRTGP-5t9E+*u$t@cMPY@y|r&BPd5kf--)|W}< z&3M3glTup~taznzAF^Fq(#tRreqFEHrQM!t#Vb_Fv>GF5tFfST#)bCs$O>E`6qJ-W z_4THic>HPP>|-~pA5@04<9{9DDULSFksqRRsF}(p@-_H;)hv8PR=Z;xAKx>j&VanY zWkfo$5iezjlb79UdR^Sj>OYY?jr@`fe2F$15*bTdddOEuH{b%hO%e2*nyC=wL(r3@#S`;KvKS?zsr5E_tWC>0O>A zwr{_4K4zT)cS1TV6AU4|8GEoV)W8eT`I(`=?-R75)kgO;XcnbtW_}N&`r4;D@5i)9 z{($jaH{#sK2IB)VE7J?HgBV>g@nC?oRF=-r-Mymy!zf%2ibUB^}@j0T!fE)fjvVof$p9 z0b>~@7tvVX$*uU#zmz4tyY~Q5aI3PrXOo0ftkmdB4G}U1ffCIam6UEb%5^6+dX9{* z_aX!kP(+J+wDT>AeenN`wgusnDzvi%Ma+>cl$0W>O*)sc@gUnmg7JR2!5G~$Fl&@| zFyHYM2Vi-k1zEzDjD>pa{bR*>i#Qrl+?YpgqB?y7k87lz~&`QL}ouO9K)Y2(n9 zRZ&d-#erIsZ4n}r$TzYxx)$mAtXjCzW$|=)5dh*HK{J5K^f7O5t#M%cb^X7#N4zP9 z?qnH#&UQ@|2qf)Felm|DFVZG+eoLvf;SEj1j_^0;C;q>~?Z33DftUSa6rOm@>NA}N z*at9V(>BWBzRT!|M#tIIpJZU;+*sve=)MXRu&hy4J*GdW&J=s%ww)Q&RIX0l2I{|M zKp5?q?w=I^%}%1yx9VY6Q!FX(cQghtNn8`+x6|ufTi2B2Yyj*sXMAKysh~>vI-KooppOFWG7}onEDOn))u^+D`=s1xXB>B@yH)WAt zq`4)-I>p;9>9u5w886|zU@@CH;V)q7tnHkLTEo9uja+^s)+X>P#DvLL5<9Lb3_aug zVmKj$QR^C(9@b@7sKU)U;h-94y<8*5FMco?K~aS^K$Z^kD^2MV6fk;cbGG6}wVUjT z%KtwBY7Uk08)*oj$U|8o&=CF>QzQsJCD0^-NhXg%I}U=V?W|oZZ)h@5(4n7YtS=Hf zBj!rZUas01`w|ivu&K&2pHMBLkxlB17R=+qkW9i zkj9(EWCOT?oz>R}O`@nc1Q9g{*~@h&USM!$7U<57G`kd7BX|I(x`mLdf%l8UN!Gyh zfQ0<^_i;Tdelm$77OyBjA#-RWJV|DYBESmW6zQJNGWS?MF&0lDl3!k`6-s*z^L#7u z11{EZ3Nt~3w95-J=6A(IOjxw3oGjzwK;3^-u77Mcu1jg~pB%Pa(ghTfmZ0qhNHGtx z4w*rTY@ntx7TG2)w0I{QwFK?f1!o1$u~}8NF|hqu99^d)~21g-whOFa9AE5 zhikrxHeB*j{E?bLuIqjn7ZArl2LfU|x0KhdzJef0^;3f1|1nsF))Qhzgh{Bg}woT+z38|=VHQUxZnY; z2&$>JjoM>%fo!bI^Lj{^s>}9%(L#EpzI}Rp@O_sy5Yc#xG*-X_#7ue*{X~csR-&CSv>#z-f9Qudu)%P%FXoT2U>q>6?yRHe^?RIsbCae>5{bJ|P96nlgR>yPIR za1a0u(=9XZn-+}Wh2728a5&6@p-gB9to;!k8AK7Ph;bkzgzN$qBql`qr){z$+!>7m z$mwlSSX~ZPR>vo0ahQfJo5KbOj2SPA&=9+F^_dWwvtg@{J85~ILGc1QRx`zDm$=+E zJ{Tubrr_h88|d!Fb`e4_Ze&j?F|b@M3RA3DwBxL+xGW%YOlX0JmDnSt-yRxlZA1Q| z%Va(wka|59?bf94ueUq>yTi%40Nw7bpRilUx`PIe$QKokMD09tXM>HZTZ@`%k?8sA zfaFKewf80{;_vG%dseMw^yn{7P(JTzoY^+btz`*-7N92i=WIg>v~XsDUFAxLC_CTZ zy4tqHInbNw#lC zXVQ7qgq=C76Fgz2KvN6}3c6o|rKG7rL@B33ifIF(R13oa^~`(4idL0~dnAz&GCKZn z2uU9dM_hB;)$vor|~{4#S-Cg zl7!rWUG=FE3kbVF?_bnJ#YU-w-!;GmwHsHGiEK;=De?t9Bu5N^4rH9k(_qnHL)1o& zeF*}6ESV6dDrB)^eleB5!)V1R>d}YMf;s3(60~jvBeggs zg%9!wYCB2G`mZuTb{O)GLK+*J=iV1o5FqP?&o5=C!xrXQ`3|QTd%wKBX9bZpi$uJpay}*xxuarH z4{g#NiQ=pTXU5HLxtA>ythr)s3BpU8wq+rfdB<8|62_x5B$n7QOCJ+RPO&gD6C$Gk z2}pheTF$*fp2Sg$gw?=|K$l>uI^>2`AvTxsr431F`R4%5WoDMUV+iqc80VTntEv8WWWr37b7(!%&zsDuatU^Gv*rsfW=MK`@BY_8t zhHM$_d~Dyi+TbjZnQAksOmOQeOOL6ig{MyADV5zyfbES zgA@}t+wHXwR0wm^e`;9E5;)V}~YCYzn9IqoptCc0-&}naEwh5x92+07mpl0M{Ahl*U!d z<-b$Ij~+D~y-F>gg@FB0-jztchIcOTl9R=T#s64tKjc^h`6KJ}0`>Qkro0@~17kB^ z5tg+sbM3i`GiaV%In7E|rEG}c%CFL5@WdvzLJ`FzaXL{jMi`(7Cv^8zr~TZ%I>&D? z%rMib9}88H8bmz&Vy6SLj9E3bMn{kciI!VCGDAhr?#6tsAOU$2ic+vp@{5u){s01) z`as*3obsP33bK3teL}1rk-kv0GEUH56M9OXQgQxF#J;kQnUDd`0P492~+oMekB(X*@e*sbrE)(V6OY&jy{1t-t6x<2q*h`eHgprCxp_ zyAET4Rh)2%(3^?r=c8AB)z$_B*e{l?_;&h_G3noft~si)%IedGNc&m_*YzoiAu#N> z*TMs4C$_w52t_rAT?h5}N`WF0XFyk~@e-`V5ws`=5ArPr0HiZ5G~uidJQQ5mEH&8Q ztROK3D3^WZ^}b!=pr2O*a#EMc1ml;8Pf~mZKP#UF8!}Otk?>J=K9o3hi2GRrferTx zB!=bE?Wjfl9@;z9E zkWVSmYtSptuxI5laL+9+A~H_Zb9mxYy?o`O?lWqSQ4*xHSr;YlE)Jp$OUvbM*Ope~ zke-6FKmqYkaMG$BC2J+pPW04u06<|8I+bS>f`VK`kd7bC+#BTRO>or(?Da-6Tx19n0!$Z`RR;aoqrn7D_S}K4uRv*(@G6Y`LI-sSi2>4Wji5 ziNF_ab7_{~EwTuORPw|<=`ey53}zW`$kP$%7xtEpAio1PLo}HK-|`(F@#NBKcN)u; zlJtbcf_lnH7=F!5EU7OkY-yBXOo=j-IpbIrarxDURm|OzvY@annEV#2khYOcx~)fw zs|sW8ki|cIKiE zF5ZNP8~k{bH6gD)QH<4WHV5;1gZV9qtUfDHjsi+uM`CAPA5-BKcV%7w1?AaEp$gEF z79$*?gHuWjK5lAP>ve3Fv#nRQ;LIIeAjq~Cg>8)hGAJ^qo#19F7Zq-Z1e;nYzU}7A+kKBA3A79)h~JhKsl4EmL`Ukqs6b}t_uuyB50?O^2eos6S|#gbh4iT0%NpGhpmnTw{UIIgWI#?T}R<{tG@* z8Q2+yO}=Jp8703dvk;U4?<1kHMSjzGnorEhpc@z}1|(kUM;yiH0uzFwT`&5V{_in3 zxo@{Z=hVyTK`3w%*j9?w>rRo&a9$M-GnJf1<9A-PSp} zkgU*bom-E(ln13K2e$5Txv~wjqyO0Fw};JnYOVUXx1bwQ=Sr_6WNIg$+e}JftOp-p z??4X9Mt*-j#HCuR+cE=VO9_n`#ihd?%A#n@lC>5p5&Xhr%_98NYc@oTLljm($qDR^ z^75`M^*|}wp^!tY32#9HBN-thxq3qsB>hC8HEyvP;UK5qgbPIm1VDRGCe4KIH!0D; J$bxe$9!lUQ8F&By literal 0 HcmV?d00001 diff --git a/java/com.sap.sailing.www/fonts/open-sans-condensed-bold-webfont.svg b/java/com.sap.sailing.www/fonts/open-sans-condensed-bold-webfont.svg new file mode 100644 index 00000000000..96687610c5c --- /dev/null +++ b/java/com.sap.sailing.www/fonts/open-sans-condensed-bold-webfont.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/java/com.sap.sailing.www/fonts/open-sans-condensed-bold-webfont.ttf b/java/com.sap.sailing.www/fonts/open-sans-condensed-bold-webfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f5a171c3ba1ee5d0b9eaeb3643d680e9d5387d2f GIT binary patch literal 40244 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 K!P{*WME?P|l|l*t literal 0 HcmV?d00001 diff --git a/java/com.sap.sailing.www/fonts/open-sans-condensed-bold-webfont.woff b/java/com.sap.sailing.www/fonts/open-sans-condensed-bold-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..6bd7654c3fc1e5f265f3a3d5de83f214bf04911c GIT binary patch literal 23036 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 literal 0 HcmV?d00001 diff --git a/java/com.sap.sailing.www/fonts/open-sans-condensed-light-italic-webfont.eot b/java/com.sap.sailing.www/fonts/open-sans-condensed-light-italic-webfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..56f04c01e5f2689c0704a7879786363b38f66242 GIT binary patch literal 19808 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

8p(b7m@lFi{514p9Oc+E%{p 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 literal 0 HcmV?d00001 diff --git a/java/com.sap.sailing.www/fonts/open-sans-condensed-light-italic-webfont.svg b/java/com.sap.sailing.www/fonts/open-sans-condensed-light-italic-webfont.svg new file mode 100644 index 00000000000..117a67e1be2 --- /dev/null +++ b/java/com.sap.sailing.www/fonts/open-sans-condensed-light-italic-webfont.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/java/com.sap.sailing.www/fonts/open-sans-condensed-light-italic-webfont.ttf b/java/com.sap.sailing.www/fonts/open-sans-condensed-light-italic-webfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..2b2cbb254d3c5575f375cf76c104845e9f4b3786 GIT binary patch literal 37960 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 literal 0 HcmV?d00001 diff --git a/java/com.sap.sailing.www/fonts/open-sans-condensed-light-italic-webfont.woff b/java/com.sap.sailing.www/fonts/open-sans-condensed-light-italic-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..2409ef16f61fa667a18ebf71070bfb21728410a0 GIT binary patch literal 22604 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 c-rlsI{T`3F?4>- \ No newline at end of file diff --git a/java/com.sap.sailing.www/fonts/open-sans-condensed-light-webfont.ttf b/java/com.sap.sailing.www/fonts/open-sans-condensed-light-webfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..044dc1f957dbd2edd8526d55f297644a1917840c GIT binary patch literal 36420 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 literal 0 HcmV?d00001 diff --git a/java/com.sap.sailing.www/fonts/open-sans-condensed-light-webfont.woff b/java/com.sap.sailing.www/fonts/open-sans-condensed-light-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..7564c66421149aab24f62a3314b73a462e010aff GIT binary patch literal 21760 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

5oG|qr5H3l8Y4)2d>$7cwDI_177AIIQ8M8cj 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 Date: Tue, 26 May 2015 17:25:13 +0200 Subject: [PATCH 20/72] Bug 2816: Fixed fonts after adapting the new @font-face declarations --- java/com.sap.sailing.gwt.ui/Leaderboard.css | 1 - java/com.sap.sailing.gwt.ui/LeaderboardNewHome.css | 1 - 2 files changed, 2 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/Leaderboard.css b/java/com.sap.sailing.gwt.ui/Leaderboard.css index 7cb4a5fe4c3..8ab68acf9b9 100755 --- a/java/com.sap.sailing.gwt.ui/Leaderboard.css +++ b/java/com.sap.sailing.gwt.ui/Leaderboard.css @@ -82,7 +82,6 @@ input.magnifier{ body, table td, select, button { font-family: 'Open Sans', Arial, Verdana, sans-serif; - font-weight: 300; font-size: 14px; } diff --git a/java/com.sap.sailing.gwt.ui/LeaderboardNewHome.css b/java/com.sap.sailing.gwt.ui/LeaderboardNewHome.css index 92284e0e13c..4aa2705763b 100644 --- a/java/com.sap.sailing.gwt.ui/LeaderboardNewHome.css +++ b/java/com.sap.sailing.gwt.ui/LeaderboardNewHome.css @@ -37,7 +37,6 @@ input.magnifier{ body, table td, select, button { font-family: 'Open Sans', Arial, Verdana, sans-serif; - font-weight: 300; font-size: 14px; } From 6a958da022590db2608440533e61db59323fcc78 Mon Sep 17 00:00:00 2001 From: Papick Garcia Taboada Date: Wed, 27 May 2015 10:19:23 +0200 Subject: [PATCH 21/72] Media DTOs initial proposal for backend implementation --- .../sailing/gwt/server/HomeServiceImpl.java | 18 ++-- .../gwt/ui/shared/media/SailingImageDTO.java | 38 +-------- .../gwt/ui/shared/media/SailingVideoDTO.java | 13 +-- .../sse/common/media/AbstractMediaDTO.java | 84 ++++++++++++++++--- .../sse/common/media/ImageMetadataDTO.java | 51 +++-------- .../sse/common/media/VideoMetadataDTO.java | 32 +++---- 6 files changed, 124 insertions(+), 112 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java index ae169e7d3a1..2b471316693 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceImpl.java @@ -189,8 +189,10 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home MimeType type = MediaUtils.detectMimeTypeFromUrl(youTubeRandomUrl.toString()); if (type.mediaType == MediaType.video) { - SailingVideoDTO candidate = new SailingVideoDTO(eventRef, youTubeRandomUrl, type, - holder.event.getName()); + SailingVideoDTO candidate = new SailingVideoDTO(eventRef, youTubeRandomUrl.toString(), type, // + holder.event.getEndDate().asDate() // FIXME: using event enddate for now + ); + candidate.setTitle(holder.event.getName()); result.addVideo(candidate); } } @@ -229,7 +231,10 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home MimeType type = MediaUtils.detectMimeTypeFromUrl(videoUrl.toString()); if (type.mediaType == MediaType.video) { - SailingVideoDTO candidate = new SailingVideoDTO(eventRef, videoUrl, type, holder.event.getName()); + SailingVideoDTO candidate = new SailingVideoDTO(eventRef, videoUrl.toString(), type, // + holder.event.getEndDate().asDate() // FIXME: using event enddate for now + ); + candidate.setTitle(holder.event.getName()); videoCandidates.add(candidate); } } @@ -429,13 +434,16 @@ public class HomeServiceImpl extends ProxiedRemoteServiceServlet implements Home } catch (InterruptedException | ExecutionException e) { logger.log(Level.FINE, "Was unable to obtain image size for "+url+" earlier.", e); } - SailingImageDTO entry = new SailingImageDTO(eventRef, url.toString(), imageSize, eventName); + SailingImageDTO entry = new SailingImageDTO(eventRef, url.toString(), imageSize, // + event.getEndDate().asDate() // FIXME: using the event end date for now, we need a better solution for migration + ); + entry.setTitle(eventName); media.addPhoto(entry); } for(URL url : event.getVideoURLs()) { MimeType type = MediaUtils.detectMimeTypeFromUrl(url.toString()); if (type.mediaType == MediaType.video) { - SailingVideoDTO candidate = new SailingVideoDTO(eventRef, url, type, null); + SailingVideoDTO candidate = new SailingVideoDTO(eventRef, url.toString(), type, null); media.addVideo(candidate); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingImageDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingImageDTO.java index 2a59453ef87..02da494bb86 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingImageDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingImageDTO.java @@ -10,48 +10,18 @@ public class SailingImageDTO extends ImageMetadataDTO { private static final long serialVersionUID = 1L; - private String subtitle; - private Date createdAtDate; - private String author; - private EventReferenceDTO eventRef; - protected SailingImageDTO() { + @SuppressWarnings("unused") + private SailingImageDTO() { } - - public SailingImageDTO(EventReferenceDTO eventRef, String imageURL, ImageSize size, String title) { - super(imageURL, size, title); + public SailingImageDTO(EventReferenceDTO eventRef, String imageURL, ImageSize size, Date createdAtDate) { + super(imageURL, size, createdAtDate); this.eventRef = eventRef; } - public String getSubtitle() { - return subtitle; - } - - public void setSubtitle(String subtitle) { - this.subtitle = subtitle; - } - - public Date getCreatedAtDate() { - return createdAtDate; - } - - public void setCreatedAtDate(Date createdAtDate) { - this.createdAtDate = createdAtDate; - } - - public String getAuthor() { - return author; - } - - public void setAuthor(String author) { - this.author = author; - } - - - public EventReferenceDTO getEventRef() { return eventRef; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingVideoDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingVideoDTO.java index 45913aa656a..bbfc2ebe186 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingVideoDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/SailingVideoDTO.java @@ -1,8 +1,7 @@ package com.sap.sailing.gwt.ui.shared.media; -import java.net.URL; +import java.util.Date; -import com.google.gwt.core.shared.GwtIncompatible; import com.sap.sailing.gwt.ui.shared.general.EventReferenceDTO; import com.sap.sse.common.media.MimeType; import com.sap.sse.common.media.VideoMetadataDTO; @@ -17,17 +16,11 @@ public class SailingVideoDTO extends VideoMetadataDTO { private SailingVideoDTO() { } - @GwtIncompatible - public SailingVideoDTO(EventReferenceDTO eventRef, URL url, MimeType mimeType, String title) { - this(eventRef, url.toString(), mimeType, title); + public SailingVideoDTO(EventReferenceDTO eventRef, String srcReference, MimeType mimeType, Date createdAtDate) { + super(srcReference, mimeType, createdAtDate); this.eventRef = eventRef; } - @GwtIncompatible - public SailingVideoDTO(EventReferenceDTO eventRef, String url, MimeType mimeType, String title) { - super(url, mimeType, title); - this.eventRef = eventRef; - } public EventReferenceDTO getEventRef() { return eventRef; diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDTO.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDTO.java index b7177bdcc2f..933a025426c 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDTO.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDTO.java @@ -1,46 +1,110 @@ package com.sap.sse.common.media; import java.io.Serializable; +import java.util.Date; import java.util.HashSet; -public class AbstractMediaDTO implements Serializable { +/** + * Common media data for media items + * + * @author pgtaboada + * + */ +public class AbstractMediaDTO implements Serializable, Comparable { private static final long serialVersionUID = 1L; + /** + * TODO: would "caption" be a better name? + */ private String title; + /** + * TODO: should we provide a subtitle? + */ + protected String subtitle; + + /** + * This information should be used for chronological ordering + * TODO: Must not be null. We need to find a way to + * migrate data! + */ + protected Date createdAtDate; + + /** + * TODO: initially I though of "author", but I am not sure if we need the author name. But we probably will need + * some place to store copyright information... + */ + protected String copyright; + private MimeType mimeType; + /** + * TODO: tags will give us some way to categorize medias. If we pass this information to the frontend, we need some + * nice idea to show display this data. for now it should be something restricted to the backend domain modell + */ private HashSet tags = new HashSet(); + /** + * URL pointing to the media data. + */ private String sourceRef; + /** + * Default constructor required for GWT serialization. + */ protected AbstractMediaDTO() { } - - public AbstractMediaDTO(String sourceRef, MimeType mimeType, String title) { - this.title = title; + /** + * Media item with minimal set of information + * + * @param sourceRef + * @param mimeType + */ + public AbstractMediaDTO(String sourceRef, MimeType mimeType, Date createdAtDate) { this.mimeType = mimeType; this.sourceRef = sourceRef; - } - - public String getTitle() { - return title; + this.createdAtDate = createdAtDate; } public MimeType getMimeType() { return mimeType; } + public String getSourceRef() { + return sourceRef; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } public HashSet getTags() { return tags; } - public String getSourceRef() { - return sourceRef; + public String getSubtitle() { + return subtitle; } + public void setSubtitle(String subtitle) { + this.subtitle = subtitle; + } + public Date getCreatedAtDate() { + return createdAtDate; + } + public void setCreatedAtDate(Date createdAtDate) { + this.createdAtDate = createdAtDate; + } + + @Override + public int compareTo(AbstractMediaDTO o) { + return createdAtDate.compareTo(o.createdAtDate); + } } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageMetadataDTO.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageMetadataDTO.java index 88010ba308c..ee72871c032 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageMetadataDTO.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageMetadataDTO.java @@ -2,6 +2,7 @@ package com.sap.sse.common.media; import java.util.Date; + public class ImageMetadataDTO extends AbstractMediaDTO { private static final long serialVersionUID = 1L; @@ -9,59 +10,33 @@ public class ImageMetadataDTO extends AbstractMediaDTO { private int widthInPx; private int heightInPx; - private String subtitle; - private Date createdAtDate; - private String author; - - protected ImageMetadataDTO() { } - public ImageMetadataDTO(String imageURL, ImageSize size, String title) { - super(imageURL, MimeType.image, title); + /** + * TODO: should we use imagesize, or should we store height and width? For now, this is a convenience method... + * + * @param imageURL + * @param size + */ + public ImageMetadataDTO(String imageURL, ImageSize size, Date createdAtDate) { + super(imageURL, MimeType.image, createdAtDate); this.widthInPx = size.getWidth(); this.heightInPx = size.getHeight(); } - public String getSubtitle() { - return subtitle; - } - - public void setSubtitle(String subtitle) { - this.subtitle = subtitle; - } - - public Date getCreatedAtDate() { - return createdAtDate; - } - - public void setCreatedAtDate(Date createdAtDate) { - this.createdAtDate = createdAtDate; - } - - public String getAuthor() { - return author; - } - - public void setAuthor(String author) { - this.author = author; + public ImageMetadataDTO(String imageURL, int heightInPx, int widthInPx, Date createdAtDate) { + super(imageURL, MimeType.image, createdAtDate); + this.widthInPx = widthInPx; + this.heightInPx = heightInPx; } public int getWidthInPx() { return widthInPx; } - public void setWidthInPx(int widthInPx) { - this.widthInPx = widthInPx; - } - public int getHeightInPx() { return heightInPx; } - public void setHeightInPx(int heightInPx) { - this.heightInPx = heightInPx; - } - - } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadataDTO.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadataDTO.java index 0030136d649..72207aefd00 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadataDTO.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/VideoMetadataDTO.java @@ -1,36 +1,38 @@ package com.sap.sse.common.media; -import java.net.URL; - -import com.google.gwt.core.shared.GwtIncompatible; +import java.util.Date; public class VideoMetadataDTO extends AbstractMediaDTO { private static final long serialVersionUID = 1L; - private int length; + /** + * TODO: Do we really need video length? Should it be mandatory? + */ + private int lengthInSeconds; + + /** + * URL Reference to thumbnail image. This information works as override for youtube videos or as missing thumbnail + * information for other formats. It can be either a link to thumbnail or even be a data/url contaning the base64 + * encoded image. + */ private String thumbnailRef; protected VideoMetadataDTO() { } - @GwtIncompatible - public VideoMetadataDTO(URL url, MimeType mimeType, String title) { - this(url.toString(), mimeType, title); - } - @GwtIncompatible - public VideoMetadataDTO(String url, MimeType mimeType, String title) { - super(url, mimeType, title); + public VideoMetadataDTO(String url, MimeType mimeType, Date createdAtDate) { + super(url, mimeType, createdAtDate); } - public void setLength(int length) { - this.length = length; + public int getLengthInSeconds() { + return lengthInSeconds; } - public int getLength() { - return length; + public void setLengthInSeconds(int lengthInSeconds) { + this.lengthInSeconds = lengthInSeconds; } public void setThumbnailRef(String thumbnailRef) { From d8411aedcec4427bcc36a6158c709117ac02c53a Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 27 May 2015 10:36:43 +0200 Subject: [PATCH 22/72] Bug 2795: Added language chooser as select box if there are > 2 locales available --- .../gwt/home/client/shared/footer/Footer.java | 95 ++++++++++++++----- .../home/client/shared/footer/Footer.ui.xml | 25 +++++ 2 files changed, 97 insertions(+), 23 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/footer/Footer.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/footer/Footer.java index 8e5f8ea33e1..be8dadc061a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/footer/Footer.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/footer/Footer.java @@ -1,14 +1,17 @@ package com.sap.sailing.gwt.home.client.shared.footer; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.DivElement; import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.http.client.UrlBuilder; import com.google.gwt.i18n.client.LocaleInfo; +import com.google.gwt.text.shared.Renderer; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; @@ -16,11 +19,13 @@ import com.google.gwt.user.client.Window; import com.google.gwt.user.client.Window.Location; import com.google.gwt.user.client.ui.Anchor; import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.ValueListBox; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.gwt.home.client.app.HomePlacesNavigator; import com.sap.sailing.gwt.home.client.app.PlaceNavigation; import com.sap.sailing.gwt.home.client.place.whatsnew.WhatsNewPlace; import com.sap.sailing.gwt.home.client.place.whatsnew.WhatsNewPlace.WhatsNewNavigationTabs; +import com.sap.sse.common.Util.Pair; public class Footer extends Composite { private static FooterPanelUiBinder uiBinder = GWT.create(FooterPanelUiBinder.class); @@ -30,17 +35,32 @@ public class Footer extends Composite { @UiField Anchor changeLanguageLink; @UiField DivElement languageSelectionDiv; + @UiField(provided = true) ValueListBox> changeLanguageList = new ValueListBox>(new Renderer>() { + @Override + public String render(Pair object) { + if(object == null) { + return ""; + } + if(object.getB() != null) { + return object.getB(); + } + return object.getA(); + } + + @Override + public void render(Pair object, Appendable appendable) throws IOException { + appendable.append(render(object)); + } + }); + + private String otherLanguage; + private final LocaleInfo currentLocale = LocaleInfo.getCurrentLocale(); - private final Map localeAndLanguages; @UiField(provided = true) final PlaceNavigation releaseNotesNavigation; public Footer(final HomePlacesNavigator navigator) { - localeAndLanguages = new HashMap(); - localeAndLanguages.put("en", "English"); - localeAndLanguages.put("de", "Deutsch"); - FooterResources.INSTANCE.css().ensureInjected(); releaseNotesNavigation = navigator.getWhatsNewNavigation(WhatsNewNavigationTabs.SailingAnalytics); @@ -51,26 +71,55 @@ public class Footer extends Composite { @UiHandler("changeLanguageLink") public void changeLanguage(ClickEvent e) { - String selectedLanguage = changeLanguageLink.getText(); - String selectedLocale = null; - for (Entry entry: localeAndLanguages.entrySet()) { - if (entry.getValue().equals(selectedLanguage)) { - selectedLocale = entry.getKey(); - } + if(otherLanguage != null) { + UrlBuilder builder = Location.createUrlBuilder().setParameter("locale", otherLanguage); + Window.Location.replace(builder.buildString()); } - if(selectedLocale != null) { - UrlBuilder builder = Location.createUrlBuilder().setParameter("locale", selectedLocale); - Window.Location.replace(builder.buildString()); + } + + @UiHandler("changeLanguageList") + void onListSelection(ValueChangeEvent> event) { + String selectedLocaleName = event.getValue().getA(); + if(!currentLocale.getLocaleName().equals(selectedLocaleName)) { + UrlBuilder builder = Location.createUrlBuilder().setParameter("locale", selectedLocaleName); + Window.Location.replace(builder.buildString()); } } private void updateUI() { - LocaleInfo currentLocale = LocaleInfo.getCurrentLocale(); - HashMap languagesToSelectFrom = new HashMap(localeAndLanguages); - languagesToSelectFrom.remove(currentLocale.getLocaleName()); - - if(languagesToSelectFrom.size() == 1) { - changeLanguageLink.setText(languagesToSelectFrom.values().iterator().next()); + Set availableLocales = new HashSet(Arrays.asList(LocaleInfo.getAvailableLocaleNames())); + availableLocales.remove("default"); + + if(availableLocales.size() <= 1) { + // only current language (or removed default) available + changeLanguageLink.removeFromParent(); + changeLanguageList.removeFromParent(); + languageSelectionDiv.removeFromParent(); + return; } + if(availableLocales.size() == 2) { + changeLanguageList.removeFromParent(); + // current language + one we can switch to + for(String localeName : availableLocales) { + if(!currentLocale.getLocaleName().equals(localeName)) { + otherLanguage = localeName; + changeLanguageLink.setText(LocaleInfo.getLocaleNativeDisplayName(otherLanguage)); + return; + } + } + return; + } + changeLanguageLink.removeFromParent(); + Set> values = new HashSet<>(); + Pair selectedValue = null; + for(String localeName : availableLocales) { + Pair value = new Pair(localeName, LocaleInfo.getLocaleNativeDisplayName(localeName)); + values.add(value); + if(currentLocale.getLocaleName().equals(localeName)) { + selectedValue = value; + } + } + changeLanguageList.setValue(selectedValue); + changeLanguageList.setAcceptableValues(values); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/footer/Footer.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/footer/Footer.ui.xml index bfae282ac73..e4ff325fece 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/footer/Footer.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/footer/Footer.ui.xml @@ -5,6 +5,30 @@ + + .languageSelect { + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + + margin-top: 25px; + color: #efaa00; + line-height: 1.5em; + height: 1.5em; + display: inline-block; + border: transparent; + cursor: pointer; + padding-right: 1.2em; + background: #333; + cursor: pointer; + + background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZlcnNpb249JzEuMScgaGVpZ2h0PScxOHB4JyB3aWR0aD0nMTZweCc+PHRleHQgeD0nMCcgeT0nMTUnIGZpbGw9JyNlZmFhMDAnIGZvbnQtc2l6ZT0nMTYnPiYjOTY2MDs8L3RleHQ+PC9zdmc+"); + background-position: right center; + background-repeat: no-repeat; + + } +

From 6e24e9c8df8a7542ff2e9e8da96a612eb81f240e Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 27 May 2015 11:21:10 +0200 Subject: [PATCH 23/72] Bug 2795: Fix for IE --- .../sap/sailing/gwt/home/client/shared/footer/Footer.ui.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/footer/Footer.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/footer/Footer.ui.xml index e4ff325fece..93ad10b02e6 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/footer/Footer.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/footer/Footer.ui.xml @@ -6,6 +6,9 @@ + .languageSelect::-ms-expand { + display: none; + } .languageSelect { -webkit-appearance: none; -moz-appearance: none; From 4124ed802f486f769e42d02683824d7fe7e26dd8 Mon Sep 17 00:00:00 2001 From: Papick Garcia Taboada Date: Wed, 27 May 2015 12:02:53 +0200 Subject: [PATCH 24/72] Added missing getter/ setter for copyright information --- .../src/com/sap/sse/common/media/AbstractMediaDTO.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDTO.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDTO.java index 933a025426c..6e0ff8ba07b 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDTO.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDTO.java @@ -103,6 +103,14 @@ public class AbstractMediaDTO implements Serializable, Comparable Date: Wed, 27 May 2015 13:40:16 +0200 Subject: [PATCH 25/72] New icons for fullscreen player --- .../images/home/autoplay.svg | 13 +++++++++++++ java/com.sap.sailing.gwt.ui/images/home/close.svg | 9 +++++++++ .../shared/media/SailingGalleryPlayer.ui.xml | 14 +++++++------- 3 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 java/com.sap.sailing.gwt.ui/images/home/autoplay.svg create mode 100644 java/com.sap.sailing.gwt.ui/images/home/close.svg diff --git a/java/com.sap.sailing.gwt.ui/images/home/autoplay.svg b/java/com.sap.sailing.gwt.ui/images/home/autoplay.svg new file mode 100644 index 00000000000..2ef3036f68d --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/images/home/autoplay.svg @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/java/com.sap.sailing.gwt.ui/images/home/close.svg b/java/com.sap.sailing.gwt.ui/images/home/close.svg new file mode 100644 index 00000000000..0c13dd0797e --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/images/home/close.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/SailingGalleryPlayer.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/SailingGalleryPlayer.ui.xml index 53f8f6d4e34..a56c4917dff 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/SailingGalleryPlayer.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/media/SailingGalleryPlayer.ui.xml @@ -31,26 +31,26 @@ } .toolbar { text-align: right; - padding: 10px; + padding: 10px 20px 10px 10px; } .content { width: 100%; height: 100%; - + } + .close { + height: 30px; + width: 30px; } .subcontent { border-top: 1px solid #ebebeb; - - - } - CLOSE + @@ -63,7 +63,7 @@
- +
From 329ce626e827662e8c593a9325a9b9ad8d5d00fa Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 27 May 2015 14:21:45 +0200 Subject: [PATCH 26/72] Adapted current version of main.css --- .../gwt/common/client/SharedResources.java | 7 ++++ .../com/sap/sailing/gwt/home/main.gss | 33 +++++++++++++++-- .../client/resources/ThemeResources.java | 7 ++++ .../sse/gwt/theme/client/resources/main.gss | 35 +++++++++++++++++-- 4 files changed, 77 insertions(+), 5 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/SharedResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/SharedResources.java index 086fa1a8429..ebc7a3526a9 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/SharedResources.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/SharedResources.java @@ -20,6 +20,7 @@ public interface SharedResources extends ClientBundle { String navbar_buttonhidden(); String navbar_buttonactive(); String button(); + String buttontextonly(); String buttonsmall(); String buttonstrong(); String buttoninactive(); @@ -41,6 +42,12 @@ public interface SharedResources extends ClientBundle { String lightbox_overlay(); String lightbox_content(); String lightbox_close(); + String spacer(); + String spacersmall(); + String spacermediumsmall(); + String spacermedium(); + String spacermediumbig(); + String spacerbig(); String stickyheader(); String slideto(); String slidetonav(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/main.gss b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/main.gss index 076037ca0cb..c4676e7abbf 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/main.gss +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/main.gss @@ -129,6 +129,14 @@ figcaption { outline: none; text-decoration: none; } +.buttontextonly { + color: #333; + background: none; + -webkit-transition: none; + -moz-transition: none; + transition: none; + font-weight: normal; +} .buttonsmall { visibility: inherit; } @@ -338,8 +346,7 @@ figcaption { transform: translate(-50%, -50%); } .mainsection { - padding-top: 5.333333333333333em; - padding-bottom: 5.333333333333333em; + padding: 5.333333333333333em 0; } .mainsection_header { text-align: center; @@ -400,6 +407,28 @@ figcaption { cursor: pointer; z-index: 2; } +.spacer { + width: 100%; + border: 0; + margin: 0; + padding: 0; + display: block; +} +.spacersmall { + height: 1em; +} +.spacermediumsmall { + height: 1.333333333333333em; +} +.spacermedium { + height: 2em; +} +.spacermediumbig { + height: 4em; +} +.spacerbig { + height: 5.333333333333333em; +} .stickyheader { background: inherit; } diff --git a/java/com.sap.sse.gwt.theme/src/main/java/com/sap/sse/gwt/theme/client/resources/ThemeResources.java b/java/com.sap.sse.gwt.theme/src/main/java/com/sap/sse/gwt/theme/client/resources/ThemeResources.java index d6026a3ab87..d31ec3e9c54 100644 --- a/java/com.sap.sse.gwt.theme/src/main/java/com/sap/sse/gwt/theme/client/resources/ThemeResources.java +++ b/java/com.sap.sse.gwt.theme/src/main/java/com/sap/sse/gwt/theme/client/resources/ThemeResources.java @@ -20,6 +20,7 @@ public interface ThemeResources extends ClientBundle { String navbar_buttonhidden(); String navbar_buttonactive(); String button(); + String buttontextonly(); String buttonsmall(); String buttonstrong(); String buttoninactive(); @@ -41,6 +42,12 @@ public interface ThemeResources extends ClientBundle { String lightbox_overlay(); String lightbox_content(); String lightbox_close(); + String spacer(); + String spacersmall(); + String spacermediumsmall(); + String spacermedium(); + String spacermediumbig(); + String spacerbig(); String stickyheader(); String slideto(); String slidetonav(); diff --git a/java/com.sap.sse.gwt.theme/src/main/java/com/sap/sse/gwt/theme/client/resources/main.gss b/java/com.sap.sse.gwt.theme/src/main/java/com/sap/sse/gwt/theme/client/resources/main.gss index 076037ca0cb..8e7fe2b07bf 100644 --- a/java/com.sap.sse.gwt.theme/src/main/java/com/sap/sse/gwt/theme/client/resources/main.gss +++ b/java/com.sap.sse.gwt.theme/src/main/java/com/sap/sse/gwt/theme/client/resources/main.gss @@ -44,7 +44,7 @@ h2 { font-size: 1.466666666666667em; font-weight: bold; color: #008fcc; - margin-top: 0.7em; + margin-top: 0; margin-bottom: 0.7em; } h3 { @@ -129,6 +129,14 @@ figcaption { outline: none; text-decoration: none; } +.buttontextonly { + color: #333; + background: none; + -webkit-transition: none; + -moz-transition: none; + transition: none; + font-weight: normal; +} .buttonsmall { visibility: inherit; } @@ -338,8 +346,7 @@ figcaption { transform: translate(-50%, -50%); } .mainsection { - padding-top: 5.333333333333333em; - padding-bottom: 5.333333333333333em; + padding: 5.333333333333333em 0; } .mainsection_header { text-align: center; @@ -400,6 +407,28 @@ figcaption { cursor: pointer; z-index: 2; } +.spacer { + width: 100%; + border: 0; + margin: 0; + padding: 0; + display: block; +} +.spacersmall { + height: 1em; +} +.spacermediumsmall { + height: 1.333333333333333em; +} +.spacermedium { + height: 2em; +} +.spacermediumbig { + height: 4em; +} +.spacerbig { + height: 5.333333333333333em; +} .stickyheader { background: inherit; } From 3c9428734706a137dca5a989fbb6ca83d6e2c242 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 27 May 2015 15:01:09 +0200 Subject: [PATCH 27/72] Updated Stage and Video styling to the newest design --- .../home/client/place/event/overview/EventOverviewStage.ui.xml | 1 + .../gwt/home/client/place/event/partials/message/Message.gss | 2 +- .../gwt/home/client/place/event/partials/video/Video.gss | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.ui.xml index 1e1cfa4ae8c..20710c7bc91 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewStage.ui.xml @@ -4,6 +4,7 @@ +
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/message/Message.gss b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/message/Message.gss index c43f38e1c89..3da23839c0e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/message/Message.gss +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/message/Message.gss @@ -1,11 +1,11 @@ .message { font-size: 1rem; - margin-top: 2em; line-height: 1.733333333333333em; background: #f2f2f2; border: 1px solid #dedede; border-radius: 0.333333333333333em; padding: 1.066666666666667em 2.533333333333333em 1.066666666666667em 2.733333333333333em; + margin-bottom: 1.333333333333333em; } .message img { display: inline-block; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/video/Video.gss b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/video/Video.gss index a78f9e1f373..d889bf2bbb7 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/video/Video.gss +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/video/Video.gss @@ -36,7 +36,6 @@ font-size: 1rem; height: 28.333333333333332em; position: relative; - margin-top: 1.333333333333333em; } @media (max-width: 976px) { .video { From 6830d2657111ef808aade1af624fd95bf3ebcb59 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Wed, 27 May 2015 16:52:44 +0200 Subject: [PATCH 28/72] use NamedReentrantReadWriteLock for accessing LeaderboardGroup.leaderboards collection; works towards solving bug 2897 --- .../domain/leaderboard/LeaderboardGroup.java | 5 ++ .../impl/LeaderboardGroupImpl.java | 62 +++++++++++++++---- 2 files changed, 56 insertions(+), 11 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/LeaderboardGroup.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/LeaderboardGroup.java index 502a3c78437..5d030461e04 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/LeaderboardGroup.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/LeaderboardGroup.java @@ -28,7 +28,12 @@ public interface LeaderboardGroup extends LeaderboardGroupBase { void addLeaderboardGroupListener(LeaderboardGroupListener listener); void removeLeaderboardGroupListener(LeaderboardGroupListener listener); boolean isDisplayGroupsInReverseOrder(); + + /** + * @return a non-live copy of the leaderboard list as it looked when the method was called + */ Iterable getLeaderboards(); + int getIndexOf(Leaderboard leaderboard); void addLeaderboard(Leaderboard leaderboard); void addLeaderboardAt(Leaderboard leaderboard, int index); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/LeaderboardGroupImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/LeaderboardGroupImpl.java index 6cc07c35d9e..c94449d7b9d 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/LeaderboardGroupImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/LeaderboardGroupImpl.java @@ -13,12 +13,25 @@ import com.sap.sailing.domain.base.impl.LeaderboardGroupBaseImpl; import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.leaderboard.LeaderboardGroup; import com.sap.sailing.domain.leaderboard.LeaderboardGroupListener; +import com.sap.sse.concurrent.LockUtil; +import com.sap.sse.concurrent.NamedReentrantReadWriteLock; public class LeaderboardGroupImpl extends LeaderboardGroupBaseImpl implements LeaderboardGroup { private static final long serialVersionUID = 2035927369446736934L; private boolean displayGroupsInReverseOrder; + + /** + * The lock that guards access to the {@link #leaderboards} list. + */ + private final NamedReentrantReadWriteLock leaderboardsLock; + + /** + * The list of leaderboards grouped in this leaderboard group. Access to this list is guarded by + * {@link #leaderboardsLock}. All access has to acquire the corresponding read or write lock. + */ private final List leaderboards; + private final Set listeners; /** @@ -36,8 +49,13 @@ public class LeaderboardGroupImpl extends LeaderboardGroupBaseImpl implements Le this(UUID.randomUUID(), name, description, displayName, displayGroupsInReverseOrder, leaderboards); } - private synchronized void writeObject(ObjectOutputStream oos) throws IOException { - oos.defaultWriteObject(); + private void writeObject(ObjectOutputStream oos) throws IOException { + LockUtil.lockForRead(leaderboardsLock); + try { + oos.defaultWriteObject(); + } finally { + LockUtil.unlockAfterRead(leaderboardsLock); + } } /** @@ -46,9 +64,10 @@ public class LeaderboardGroupImpl extends LeaderboardGroupBaseImpl implements Le public LeaderboardGroupImpl(UUID id, String name, String description, String displayName, boolean displayGroupsInReverseOrder, List leaderboards) { super(id, name, description, displayName); + this.leaderboardsLock = new NamedReentrantReadWriteLock("leaderboards lock fo rleaderboard group "+name, /* fair */ false); this.displayGroupsInReverseOrder = displayGroupsInReverseOrder; - this.leaderboards = new ArrayList(leaderboards); - this.listeners = new HashSet(); + this.leaderboards = new ArrayList<>(leaderboards); + this.listeners = new HashSet<>(); } @Override @@ -99,24 +118,42 @@ public class LeaderboardGroupImpl extends LeaderboardGroupBaseImpl implements Le } @Override - public synchronized Iterable getLeaderboards() { - return new ArrayList(leaderboards); + public Iterable getLeaderboards() { + LockUtil.lockForRead(leaderboardsLock); + try { + return new ArrayList(leaderboards); + } finally { + LockUtil.unlockAfterRead(leaderboardsLock); + } } @Override - public synchronized int getIndexOf(Leaderboard leaderboard) { - return leaderboards.indexOf(leaderboard); + public int getIndexOf(Leaderboard leaderboard) { + LockUtil.lockForRead(leaderboardsLock); + try { + return leaderboards.indexOf(leaderboard); + } finally { + LockUtil.unlockAfterRead(leaderboardsLock); + } } @Override public void addLeaderboard(Leaderboard leaderboard) { - addLeaderboardAt(leaderboard, leaderboards.size()); + LockUtil.lockForWrite(leaderboardsLock); + try { + addLeaderboardAt(leaderboard, leaderboards.size()); + } finally { + LockUtil.unlockAfterWrite(leaderboardsLock); + } } @Override public void addLeaderboardAt(Leaderboard leaderboard, int index) { - synchronized (this) { + LockUtil.lockForWrite(leaderboardsLock); + try { leaderboards.add(index, leaderboard); + } finally { + LockUtil.unlockAfterWrite(leaderboardsLock); } notifyLeaderboardGroupListenersAboutLeaderboardAdded(leaderboard); } @@ -130,8 +167,11 @@ public class LeaderboardGroupImpl extends LeaderboardGroupBaseImpl implements Le @Override public void removeLeaderboard(Leaderboard leaderboard) { - synchronized (this) { + LockUtil.lockForWrite(leaderboardsLock); + try { leaderboards.remove(leaderboard); + } finally { + LockUtil.unlockAfterWrite(leaderboardsLock); } notifyLeaderboardGroupListenersAboutLeaderboardRemoved(leaderboard); } From 4ece8e45416d2ef50b5c9442a42ebcb4e2798082 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 27 May 2015 18:20:59 +0200 Subject: [PATCH 29/72] Excluding stageteaser image from media page --- .../main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java index 12616c30413..b5c9696e94b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java @@ -315,6 +315,9 @@ public final class HomeServiceUtil { boolean first = true; for (Iterator iter = imageURLs.iterator(); iter.hasNext(); ) { URL imageUrl = iter.next(); + if(imageUrl.toString().toLowerCase().contains(THUMBNAIL_IMAGE_URL_SUBSTRING_INDICATOR_CASE_INSENSITIVE)) { + continue; + } if ((first && !iter.hasNext()) || !Util.equalsWithNull(imageUrl, stageImageURL)) { result.add(imageUrl); } From 00b4a76f1ceaf89e01904de1406830a7f7486a22 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Wed, 27 May 2015 18:24:49 +0200 Subject: [PATCH 30/72] working on a solution for bug 2897: introduced NamedReentrantReadWriteLock for TrackedRegattaImpl.trackedRaces and notify listeners outside of locked area --- .../domain/test/mock/MockedTrackedRace.java | 16 +++ .../impl/DomainFactoryImpl.java | 14 ++- .../domain/tracking/TrackedRegatta.java | 25 +++- .../tracking/impl/TrackedRegattaImpl.java | 110 ++++++++++++++---- .../gwt/ui/test/MockedTrackedRace.java | 16 +++ .../gwt/ui/server/SailingServiceImpl.java | 11 +- .../server/test/RaceTrackerStartStopTest.java | 22 +++- .../LeaderboardSearchResultBaseRanker.java | 11 +- .../server/impl/RacingEventServiceImpl.java | 42 +++++-- .../ImportMasterDataOperation.java | 9 +- 10 files changed, 227 insertions(+), 49 deletions(-) diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java index aa2a2d12451..b25a333f45f 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java @@ -489,6 +489,22 @@ public class MockedTrackedRace implements DynamicTrackedRace { DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useMarkPassingcalculator) { return null; } + + @Override + public void lockTrackedRacesForRead() { + } + + @Override + public void unlockTrackedRacesAfterRead() { + } + + @Override + public void lockTrackedRacesForWrite() { + } + + @Override + public void unlockTrackedRacesAfterWrite() { + } }; } 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 556272dc7c9..90a015d3e9b 100755 --- 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 @@ -489,9 +489,17 @@ public class DomainFactoryImpl implements DomainFactory { TrackedRegatta trackedRegatta = trackedRegattaRegistry.getTrackedRegatta(regatta); if (trackedRegatta != null) { // see above; only remove tracked regatta if it *became* empty because of the tracked race removal here - int oldSizeOfTrackedRaces = Util.size(trackedRegatta.getTrackedRaces()); - trackedRegatta.removeTrackedRace(raceDefinition); - if (oldSizeOfTrackedRaces > 0 && Util.size(trackedRegatta.getTrackedRaces()) == 0) { + final int oldSizeOfTrackedRaces; + final int newSizeOfTrackedRaces; + trackedRegatta.lockTrackedRacesForWrite(); + try { + oldSizeOfTrackedRaces = Util.size(trackedRegatta.getTrackedRaces()); + trackedRegatta.removeTrackedRace(raceDefinition); + newSizeOfTrackedRaces = Util.size(trackedRegatta.getTrackedRaces()); + } finally { + trackedRegatta.unlockTrackedRacesAfterWrite(); + } + if (oldSizeOfTrackedRaces > 0 && newSizeOfTrackedRaces == 0) { trackedRegattaRegistry.removeTrackedRegatta(regatta); } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRegatta.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRegatta.java index 227a8a216f5..e998afc4a5e 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRegatta.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRegatta.java @@ -29,8 +29,31 @@ import com.sap.sse.common.TimePoint; public interface TrackedRegatta extends Serializable { Regatta getRegatta(); + /** + * Callers must {@link #lockTrackedRacesForRead() acquire the read lock} before calling this method and hold on to the lock + * while iterating over the data structure returned. Example: + *
+     *     trackedRegatta.lockTrackedRacesForRead();
+     *     try {
+     *         for (TrackedRace trackedRace : trackedRegatta.getTrackedRaces()) {
+     *             // do something
+     *         }
+     *     } finally {
+     *         trackedRegatta.unlockTrackedRacesAfterRead();
+     *     }
+     * 
+ * The method will throw an {@link IllegalArgumentException} if the caller fails to do so. + */ Iterable getTrackedRaces(); + void lockTrackedRacesForRead(); + + void unlockTrackedRacesAfterRead(); + + void lockTrackedRacesForWrite(); + + void unlockTrackedRacesAfterWrite(); + Iterable getTrackedRaces(BoatClass boatClass); /** @@ -72,5 +95,5 @@ public interface TrackedRegatta extends Serializable { int getNetPoints(Competitor competitor, TimePoint timePoint) throws NoWindException; void removeTrackedRace(RaceDefinition raceDefinition); - + } \ No newline at end of file diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java index 32532ee476e..4b2db02b1c4 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Level; @@ -26,6 +27,9 @@ import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.domain.tracking.TrackedRegatta; import com.sap.sailing.domain.tracking.WindStore; import com.sap.sse.common.TimePoint; +import com.sap.sse.common.Util; +import com.sap.sse.concurrent.LockUtil; +import com.sap.sse.concurrent.NamedReentrantReadWriteLock; public class TrackedRegattaImpl implements TrackedRegatta { private static final long serialVersionUID = 6480508193567014285L; @@ -33,12 +37,24 @@ public class TrackedRegattaImpl implements TrackedRegatta { private static final Logger logger = Logger.getLogger(TrackedRegattaImpl.class.getName()); private final Regatta regatta; + + /** + * Guards access to {@link #trackedRaces}. Callers of {@link #getTrackedRaces()} need to acquire the + * read lock before iterating. + */ + private final NamedReentrantReadWriteLock trackedRacesLock; + + /** + * Guarded by {@link #trackedRacesLock} + */ private final Map trackedRaces; + private final Map> trackedRacesByBoatClass; private transient Set raceListeners; public TrackedRegattaImpl(Regatta regatta) { super(); + trackedRacesLock = new NamedReentrantReadWriteLock("trackeRaces lock for tracked regatta "+regatta.getName(), /* fair */ false); this.regatta = regatta; this.trackedRaces = new HashMap(); this.trackedRacesByBoatClass = new HashMap>(); @@ -49,10 +65,33 @@ public class TrackedRegattaImpl implements TrackedRegatta { ois.defaultReadObject(); this.raceListeners = new HashSet(); } + + @Override + public void lockTrackedRacesForRead() { + LockUtil.lockForRead(trackedRacesLock); + } + + @Override + public void unlockTrackedRacesAfterRead() { + LockUtil.unlockAfterRead(trackedRacesLock); + } + + @Override + public void lockTrackedRacesForWrite() { + LockUtil.lockForWrite(trackedRacesLock); + } + + @Override + public void unlockTrackedRacesAfterWrite() { + LockUtil.unlockAfterWrite(trackedRacesLock); + } private void writeObject(ObjectOutputStream oos) throws IOException { - synchronized (trackedRaces) { + lockTrackedRacesForRead(); + try { oos.defaultWriteObject(); + } finally { + unlockTrackedRacesAfterRead(); } } /** @@ -68,10 +107,12 @@ public class TrackedRegattaImpl implements TrackedRegatta { @Override public void addTrackedRace(TrackedRace trackedRace) { - synchronized (trackedRaces) { + final TrackedRace oldTrackedRace; + LockUtil.lockForWrite(trackedRacesLock); + try { logger.info("adding tracked race for "+trackedRace.getRace()+" to tracked regatta "+getRegatta().getName()+ " with regatta hash code "+getRegatta().hashCode()); - TrackedRace oldTrackedRace = trackedRaces.put(trackedRace.getRace(), trackedRace); + oldTrackedRace = trackedRaces.put(trackedRace.getRace(), trackedRace); if (oldTrackedRace != trackedRace) { Collection coll = trackedRacesByBoatClass.get(trackedRace.getRace().getBoatClass()); if (coll == null) { @@ -79,24 +120,31 @@ public class TrackedRegattaImpl implements TrackedRegatta { trackedRacesByBoatClass.put(trackedRace.getRace().getBoatClass(), coll); } coll.add(trackedRace); - for (RaceListener listener : raceListeners) { - listener.raceAdded(trackedRace); - } - trackedRaces.notifyAll(); + } + } finally { + LockUtil.unlockAfterWrite(trackedRacesLock); + } + if (oldTrackedRace != trackedRace) { + for (RaceListener listener : raceListeners) { + listener.raceAdded(trackedRace); } } } @Override public void removeTrackedRace(RaceDefinition raceDefinition) { - synchronized (trackedRaces) { + LockUtil.lockForWrite(trackedRacesLock); + try { trackedRaces.remove(raceDefinition); + } finally { + LockUtil.unlockAfterWrite(trackedRacesLock); } } @Override public void removeTrackedRace(TrackedRace trackedRace) { - synchronized (trackedRaces) { + LockUtil.lockForWrite(trackedRacesLock); + try { trackedRaces.remove(trackedRace.getRace()); Collection trbbc = trackedRacesByBoatClass.get(trackedRace.getRace().getBoatClass()); if (trbbc != null) { @@ -108,7 +156,8 @@ public class TrackedRegattaImpl implements TrackedRegatta { for (RaceListener listener : raceListeners) { listener.raceRemoved(trackedRace); } - trackedRaces.notifyAll(); + } finally { + LockUtil.unlockAfterWrite(trackedRacesLock); } } @@ -119,6 +168,9 @@ public class TrackedRegattaImpl implements TrackedRegatta { @Override public Iterable getTrackedRaces() { + if (trackedRacesLock.getReadHoldCount() <= 0) { + throw new IllegalStateException("Callers of TrackedRegatta.getTrackedRaces() must hold the read lock; see TrackedRegatta.lockTrackedRacesForRead()"); + } return trackedRaces.values(); } @@ -130,7 +182,8 @@ public class TrackedRegattaImpl implements TrackedRegatta { @Override public TrackedRace getTrackedRace(RaceDefinition race) { boolean interrupted = false; - synchronized (trackedRaces) { + lockTrackedRacesForRead(); + try { TrackedRace result = trackedRaces.get(race); while (!interrupted && result == null) { try { @@ -141,31 +194,48 @@ public class TrackedRegattaImpl implements TrackedRegatta { } } return result; + } finally { + unlockTrackedRacesAfterRead(); } } @Override public TrackedRace getExistingTrackedRace(RaceDefinition race) { - return trackedRaces.get(race); + lockTrackedRacesForRead(); + try { + return trackedRaces.get(race); + } finally { + unlockTrackedRacesAfterRead(); + } } @Override public void addRaceListener(RaceListener listener) { - raceListeners.add(listener); - synchronized (trackedRaces) { - for (TrackedRace trackedRace : getTrackedRaces()) { - listener.raceAdded(trackedRace); - } + final List trackedRacesCopy = new ArrayList<>(); + lockTrackedRacesForRead(); + try { + raceListeners.add(listener); + Util.addAll(getTrackedRaces(), trackedRacesCopy); + } finally { + unlockTrackedRacesAfterRead(); + } + for (TrackedRace trackedRace : trackedRacesCopy) { + listener.raceAdded(trackedRace); } } @Override public int getNetPoints(Competitor competitor, TimePoint timePoint) throws NoWindException { int result = 0; - for (TrackedRace trackedRace : getTrackedRaces()) { - result += trackedRace.getRank(competitor, timePoint); + lockTrackedRacesForRead(); + try { + for (TrackedRace trackedRace : getTrackedRaces()) { + result += trackedRace.getRank(competitor, timePoint); + } + return result; + } finally { + unlockTrackedRacesAfterRead(); } - return result; } @Override diff --git a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java index 026e4ff0ac0..ea90e6aa7eb 100755 --- a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java +++ b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java @@ -485,6 +485,22 @@ public class MockedTrackedRace implements DynamicTrackedRace { boolean useMarkPassingCalculator) { return null; } + + @Override + public void lockTrackedRacesForRead() { + } + + @Override + public void unlockTrackedRacesAfterRead() { + } + + @Override + public void lockTrackedRacesForWrite() { + } + + @Override + public void unlockTrackedRacesAfterWrite() { + } }; } 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 bc6ef529152..5fa3465395f 100755 --- 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 @@ -4752,9 +4752,14 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S for (Regatta regatta : allRegattas) { DynamicTrackedRegatta trackedRegatta = getService().getTrackedRegatta(regatta); if (trackedRegatta != null) { - Iterable trackedRaces = trackedRegatta.getTrackedRaces(); - for (TrackedRace trackedRace : trackedRaces) { - result.add((DynamicTrackedRace) trackedRace); + trackedRegatta.lockTrackedRacesForRead(); + try { + Iterable trackedRaces = trackedRegatta.getTrackedRaces(); + for (TrackedRace trackedRace : trackedRaces) { + result.add((DynamicTrackedRace) trackedRace); + } + } finally { + trackedRegatta.unlockTrackedRacesAfterRead(); } } } diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RaceTrackerStartStopTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RaceTrackerStartStopTest.java index 6d857720fb3..b74ea269f82 100644 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RaceTrackerStartStopTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RaceTrackerStartStopTest.java @@ -123,10 +123,15 @@ public class RaceTrackerStartStopTest { // of the tracked event assertNotNull(regatta.getRaceByName(RACENAME2)); boolean foundTrackedRaceForRaceDef2 = false; - for (TrackedRace trackedRace : trackedRegatta.getTrackedRaces()) { - if (trackedRace.getRace().getName().equals(RACENAME2)) { - foundTrackedRaceForRaceDef2 = true; + trackedRegatta.lockTrackedRacesForRead(); + try { + for (TrackedRace trackedRace : trackedRegatta.getTrackedRaces()) { + if (trackedRace.getRace().getName().equals(RACENAME2)) { + foundTrackedRaceForRaceDef2 = true; + } } + } finally { + trackedRegatta.unlockTrackedRacesAfterRead(); } assertTrue(foundTrackedRaceForRaceDef2); // The raceTracker2 and raceTracker3 should currently not be in track mode. @@ -161,10 +166,15 @@ public class RaceTrackerStartStopTest { // from the tracked event assertNull(regatta.getRaceByName(RACENAME2)); boolean foundTrackedRaceForRaceDef2 = false; - for (TrackedRace trackedRace : trackedRegatta.getTrackedRaces()) { - if (trackedRace.getRace().getName().equals(RACENAME2)) { - foundTrackedRaceForRaceDef2 = true; + trackedRegatta.lockTrackedRacesForRead(); + try { + for (TrackedRace trackedRace : trackedRegatta.getTrackedRaces()) { + if (trackedRace.getRace().getName().equals(RACENAME2)) { + foundTrackedRaceForRaceDef2 = true; + } } + } finally { + trackedRegatta.unlockTrackedRacesAfterRead(); } assertFalse(foundTrackedRaceForRaceDef2); // The trackers map should still contain the raceTrackers diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/LeaderboardSearchResultBaseRanker.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/LeaderboardSearchResultBaseRanker.java index a891fc249fe..d1121fb3bd4 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/LeaderboardSearchResultBaseRanker.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/LeaderboardSearchResultBaseRanker.java @@ -37,10 +37,15 @@ public class LeaderboardSearchResultBaseRanker startOfTrackingTimes = new ArrayList<>(); - for (TrackedRace trackedRace : trackedRegatta.getTrackedRaces()) { - if (trackedRace.getStartOfTracking() != null) { - startOfTrackingTimes.add(trackedRace.getStartOfTracking()); + trackedRegatta.lockTrackedRacesForRead(); + try { + for (TrackedRace trackedRace : trackedRegatta.getTrackedRaces()) { + if (trackedRace.getStartOfTracking() != null) { + startOfTrackingTimes.add(trackedRace.getStartOfTracking()); + } } + } finally { + trackedRegatta.unlockTrackedRacesAfterRead(); } final TimePoint result; if (startOfTrackingTimes.isEmpty()) { diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java index 26625d2a944..37fe02bdb39 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java @@ -1891,11 +1891,17 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes regatta.setEndDate(endDate); if (regatta.useStartTimeInference() != useStartTimeInference) { regatta.setUseStartTimeInference(useStartTimeInference); - if (getTrackedRegatta(regatta) != null) { - for (DynamicTrackedRace trackedRace : getTrackedRegatta(regatta).getTrackedRaces()) { - // the start times of the regatta's tracked races now have to be re-evaluated the next time they are - // queried - trackedRace.invalidateStartTime(); + final DynamicTrackedRegatta trackedRegatta = getTrackedRegatta(regatta); + if (trackedRegatta != null) { + trackedRegatta.lockTrackedRacesForRead(); + try { + for (DynamicTrackedRace trackedRace : trackedRegatta.getTrackedRaces()) { + // the start times of the regatta's tracked races now have to be re-evaluated the next time they + // are queried + trackedRace.invalidateStartTime(); + } + } finally { + trackedRegatta.unlockTrackedRacesAfterRead(); } } } @@ -1921,10 +1927,19 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes TrackedRace trackedRace = getExistingTrackedRace(regatta, race); if (trackedRace != null) { TrackedRegatta trackedRegatta = getTrackedRegatta(regatta); + final boolean isTrackedRacesEmpty; if (trackedRegatta != null) { - trackedRegatta.removeTrackedRace(trackedRace); + trackedRegatta.lockTrackedRacesForWrite(); + try { + trackedRegatta.removeTrackedRace(trackedRace); + isTrackedRacesEmpty = Util.isEmpty(trackedRegatta.getTrackedRaces()); + } finally { + trackedRegatta.unlockTrackedRacesAfterWrite(); + } + } else { + isTrackedRacesEmpty = false; } - if (Util.isEmpty(trackedRegatta.getTrackedRaces())) { + if (isTrackedRacesEmpty) { removeTrackedRegatta(regatta); } // remove tracked race from RaceColumns of regatta @@ -3142,10 +3157,15 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes for (Regatta regatta : allRegattas) { DynamicTrackedRegatta trackedRegatta = getTrackedRegatta(regatta); if (trackedRegatta != null) { - Iterable trackedRaces = trackedRegatta.getTrackedRaces(); - for (TrackedRace trackedRace : trackedRaces) { - trackedRace.setPolarDataService(service); - service.insertExistingFixes(trackedRace); + trackedRegatta.lockTrackedRacesForRead(); + try { + Iterable trackedRaces = trackedRegatta.getTrackedRaces(); + for (TrackedRace trackedRace : trackedRaces) { + trackedRace.setPolarDataService(service); + service.insertExistingFixes(trackedRace); + } + } finally { + trackedRegatta.unlockTrackedRacesAfterRead(); } } } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java index 919354bbdfc..4308830717e 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java @@ -406,8 +406,13 @@ public class ImportMasterDataOperation extends TrackedRegatta trackedRegatta = toState.getTrackedRegatta(existingRegatta); List toRemove = new ArrayList(); if (trackedRegatta != null) { - for (TrackedRace race : trackedRegatta.getTrackedRaces()) { - toRemove.add(race); + trackedRegatta.lockTrackedRacesForRead(); + try { + for (TrackedRace race : trackedRegatta.getTrackedRaces()) { + toRemove.add(race); + } + } finally { + trackedRegatta.unlockTrackedRacesAfterRead(); } for (TrackedRace raceToRemove : toRemove) { trackedRegatta.removeTrackedRace(raceToRemove); From 11fd9f907d1cda2c6a680fbf72368ca3162ae319 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 28 May 2015 00:23:02 +0200 Subject: [PATCH 31/72] getTrackedRaces() now also checks for write lock count --- .../sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java index 4b2db02b1c4..3589579b9c6 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java @@ -168,7 +168,7 @@ public class TrackedRegattaImpl implements TrackedRegatta { @Override public Iterable getTrackedRaces() { - if (trackedRacesLock.getReadHoldCount() <= 0) { + if (trackedRacesLock.getReadHoldCount() <= 0 && trackedRacesLock.getWriteHoldCount() <= 0) { throw new IllegalStateException("Callers of TrackedRegatta.getTrackedRaces() must hold the read lock; see TrackedRegatta.lockTrackedRacesForRead()"); } return trackedRaces.values(); From 82757a685c92416341cbf6cace7c90f63260eb16 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 28 May 2015 10:54:39 +0200 Subject: [PATCH 32/72] pass RankingInfo through to getLegGapToLegLeaderInOwnTime as a preparation for a performance fix --- ...ationVersusOneDesignRankingMetricTest.java | 6 +- .../impl/AbstractSimpleLeaderboardImpl.java | 8 +- .../ORCPerformanceCurveRankingMetric.java | 2 +- .../ranking/OneDesignRankingMetric.java | 4 +- .../sailing/domain/ranking/RankingMetric.java | 8 +- .../TimeOnTimeAndDistanceRankingMetric.java | 11 ++- .../tracking/TrackedLegOfCompetitor.java | 19 +++-- .../impl/TrackedLegOfCompetitorImpl.java | 21 ++--- .../SailingGWT sdm.launch | 5 +- .../RegattaAndRaceDataJsonGetServlet.java | 4 +- .../gateway/jaxrs/api/RegattasResource.java | 9 ++- .../SailingServer (No Proxy).launch | 76 +++++++++---------- .../sailing/xmlexport/LeaderboardData.java | 10 ++- 13 files changed, 104 insertions(+), 79 deletions(-) diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/DirectGapCalculationVersusOneDesignRankingMetricTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/DirectGapCalculationVersusOneDesignRankingMetricTest.java index f19e05fef5e..c3e6b4adfab 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/DirectGapCalculationVersusOneDesignRankingMetricTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/DirectGapCalculationVersusOneDesignRankingMetricTest.java @@ -23,6 +23,7 @@ import com.sap.sailing.domain.common.impl.WindImpl; import com.sap.sailing.domain.common.impl.WindSourceImpl; import com.sap.sailing.domain.leaderboard.caching.LeaderboardDTOCalculationReuseCache; import com.sap.sailing.domain.ranking.OneDesignRankingMetric; +import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo; import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; import com.sap.sailing.domain.tracking.WindPositionMode; import com.sap.sailing.domain.tractracadapter.ReceiverType; @@ -65,7 +66,7 @@ public class DirectGapCalculationVersusOneDesignRankingMetricTest extends Abstra /** * Asserts that Philipp Buhl is having equal gap value, regardless whether calculated using the traditional - * {@link TrackedLegOfCompetitor#getGapToLeader(TimePoint, WindPositionMode)} method or the + * {@link TrackedLegOfCompetitor#getGapToLeader(TimePoint, RankingInfo, WindPositionMode)} method or the * {@link OneDesignRankingMetric#getGapToLeaderInOwnTime(Competitor, TimePoint)} method. */ @Test @@ -74,7 +75,8 @@ public class DirectGapCalculationVersusOneDesignRankingMetricTest extends Abstra TimePoint timePoint = getTrackedRace().getStartOfRace(); for (int i=1; i<10; i++) { timePoint = timePoint.plus(Duration.ONE_MINUTE); - Duration classicGap = getTrackedRace().getTrackedLeg(buhli, timePoint).getGapToLeader(timePoint, WindPositionMode.LEG_MIDDLE); + Duration classicGap = getTrackedRace().getTrackedLeg(buhli, timePoint).getGapToLeader(timePoint, + getTrackedRace().getRankingMetric().getRankingInfo(timePoint), WindPositionMode.LEG_MIDDLE); Duration rankingMetricGap = getTrackedRace().getRankingMetric().getGapToLeaderInOwnTime(buhli, timePoint); assertEquals("At "+i+" minutes into the race ("+timePoint+"): ", classicGap.asSeconds(), rankingMetricGap.asSeconds(), 0.000001); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java index 9a97fcb5f33..863d98cfcb2 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java @@ -1678,10 +1678,10 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race trackedLeg.hasFinishedLeg(timePoint) ? trackedLeg.getFinishTime() : timePoint, cache) : null; // fetch the leg gap in own corrected time from the ranking metric final Duration gapToLeaderInOwnTime = trackedLeg.getTrackedLeg().getTrackedRace().getRankingMetric(). - getLegGapToLegLeaderInOwnTime(trackedLeg, timePoint, cache); + getLegGapToLegLeaderInOwnTime(trackedLeg, timePoint, rankingInfo, cache); result.gapToLeaderInSeconds = gapToLeaderInOwnTime == null ? null : gapToLeaderInOwnTime.asSeconds(); if (result.gapToLeaderInSeconds != null) { - final Duration gapAtEndOfPreviousLeg = getGapAtEndOfPreviousLeg(trackedLeg, cache); + final Duration gapAtEndOfPreviousLeg = getGapAtEndOfPreviousLeg(trackedLeg, rankingInfo, cache); if (gapAtEndOfPreviousLeg != null) { result.gapChangeSinceLegStartInSeconds = result.gapToLeaderInSeconds - gapAtEndOfPreviousLeg.asSeconds(); } @@ -1766,7 +1766,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race return result; } - private Duration getGapAtEndOfPreviousLeg(TrackedLegOfCompetitor trackedLeg, WindLegTypeAndLegBearingCache cache) { + private Duration getGapAtEndOfPreviousLeg(TrackedLegOfCompetitor trackedLeg, final RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) { final Duration result; final Course course = trackedLeg.getTrackedLeg().getTrackedRace().getRace().getCourse(); // if trackedLeg is the first leg, compute the gap at the start of this leg; otherwise, compute gap @@ -1779,7 +1779,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race tloc = trackedLeg.getTrackedLeg().getTrackedRace().getTrackedLegFinishingAt(trackedLeg.getLeg().getFrom()) .getTrackedLeg(trackedLeg.getCompetitor()); } - result = trackedLeg.getTrackedLeg().getTrackedRace().getRankingMetric().getLegGapToLegLeaderInOwnTime(tloc, timePoint, cache); + result = trackedLeg.getTrackedLeg().getTrackedRace().getRankingMetric().getLegGapToLegLeaderInOwnTime(tloc, timePoint, rankingInfo, cache); return result; } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/ORCPerformanceCurveRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/ORCPerformanceCurveRankingMetric.java index 751d71e029b..6f06916ceba 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/ORCPerformanceCurveRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/ORCPerformanceCurveRankingMetric.java @@ -66,7 +66,7 @@ public class ORCPerformanceCurveRankingMetric extends AbstractRankingMetric { @Override public Duration getLegGapToLegLeaderInOwnTime(TrackedLegOfCompetitor trackedLegOfCompetitor, TimePoint timePoint, - WindLegTypeAndLegBearingCache cache) { + RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) { // TODO Auto-generated method stub return null; } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/OneDesignRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/OneDesignRankingMetric.java index 77acfc206e8..90bab4b643d 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/OneDesignRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/OneDesignRankingMetric.java @@ -69,8 +69,8 @@ public class OneDesignRankingMetric extends AbstractRankingMetric { @Override public Duration getLegGapToLegLeaderInOwnTime(TrackedLegOfCompetitor trackedLegOfCompetitor, TimePoint timePoint, - WindLegTypeAndLegBearingCache cache) { - return trackedLegOfCompetitor.getGapToLeader(timePoint, WindPositionMode.LEG_MIDDLE, cache); + final RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) { + return trackedLegOfCompetitor.getGapToLeader(timePoint, WindPositionMode.LEG_MIDDLE, rankingInfo, cache); } @Override diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/RankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/RankingMetric.java index e3299b5be69..f011e15bf36 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/RankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/RankingMetric.java @@ -178,7 +178,7 @@ public interface RankingMetric extends Serializable { * @param competitor * the competitor for which to tell the gap to the leader in competitor's own time * - * @see #getLegGapToLegLeaderInOwnTime(TrackedLegOfCompetitor, TimePoint, WindLegTypeAndLegBearingCache) + * @see #getLegGapToLegLeaderInOwnTime(TrackedLegOfCompetitor, TimePoint, com.sap.sailing.domain.ranking.RankingMetric.CompetitorRankingInfo.RankingInfo, WindLegTypeAndLegBearingCache) */ default Duration getGapToLeaderInOwnTime(RankingInfo rankingInfo, Competitor competitor) { return getGapToLeaderInOwnTime(rankingInfo, competitor, new LeaderboardDTOCalculationReuseCache(rankingInfo.getTimePoint())); @@ -205,6 +205,10 @@ public interface RankingMetric extends Serializable { * handicap ranking is in effect) of the leg that the competitor is in at timePoint (or * the last leg if timePoint is after competitor has finished the race). Returns * null if timePoint is before competitor has started. + * + * @param rankingInfo + * tells about leader (by calculated time) and boat farthest ahead */ - Duration getLegGapToLegLeaderInOwnTime(TrackedLegOfCompetitor trackedLegOfCompetitor, TimePoint timePoint, WindLegTypeAndLegBearingCache cache); + Duration getLegGapToLegLeaderInOwnTime(TrackedLegOfCompetitor trackedLegOfCompetitor, TimePoint timePoint, + RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java index 5178f0de435..f1af3d5cc29 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java @@ -376,12 +376,12 @@ public class TimeOnTimeAndDistanceRankingMetric extends AbstractRankingMetric { } @Override - public Duration getLegGapToLegLeaderInOwnTime(TrackedLegOfCompetitor trackedLegOfCompetitor, TimePoint timePoint, WindLegTypeAndLegBearingCache cache) { + public Duration getLegGapToLegLeaderInOwnTime(TrackedLegOfCompetitor trackedLegOfCompetitor, TimePoint timePoint, + RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) { final Duration result; if (getTrackedRace().getStartOfRace() == null || !trackedLegOfCompetitor.hasStartedLeg(timePoint)) { result = null; } else { - // FIXME need to calculate the ranking stuff only once for requests for all competitors to this method, or else we'll end up with n^2 effort final Duration raceDurationAtTimePoint = getTrackedRace().getStartOfRace().until(timePoint); final Competitor farthestAheadOrEarliestLegFinisher = getCompetitorFarthestAheadInLeg(trackedLegOfCompetitor.getTrackedLeg(), timePoint, cache); final TrackedLegOfCompetitor tlocOfFarthestAhead = trackedLegOfCompetitor.getTrackedLeg().getTrackedLeg(farthestAheadOrEarliestLegFinisher); @@ -393,6 +393,9 @@ public class TimeOnTimeAndDistanceRankingMetric extends AbstractRankingMetric { // Consider all competitors, regardless of whether they have started the leg or not; a competitor in a previous // leg may well be the race leader. However, if a competitor has finished the leg already, use the finishing time // point for that competitor. + // FIXME need to calculate the ranking stuff only once for requests for all competitors to this method, or else we'll end up with n^2 effort + // FIXME The competitor iteration is only necessary here because we need to know the "leader"; other than that, computing things for the leader and the trackedLegOfCompetitor's competitor is sufficient here + // FIXME Grab the leader information from RankingInfo; CAUTION: leg leader is not necessarily identical to race leader! RankingInfo may need another field for each leg leader for (Competitor c : getTrackedRace().getRace().getCompetitors()) { final TrackedLegOfCompetitor tloc = trackedLegOfCompetitor.getTrackedLeg().getTrackedLeg(c); if (tloc.hasStartedLeg(timePoint)) { @@ -410,9 +413,9 @@ public class TimeOnTimeAndDistanceRankingMetric extends AbstractRankingMetric { } } // leader in the leg is now the competitor with the least corrected time to reach the competitor farthest ahead in the leg - Comparator durationComparatorNUllsLast = Comparator.nullsLast(Comparator.naturalOrder()); + Comparator durationComparatorNullsLast = Comparator.nullsLast(Comparator.naturalOrder()); final Competitor leader = correctedTimeToReachFarthestAheadInLeg.entrySet().stream() - .sorted((e1, e2) -> durationComparatorNUllsLast.compare(e1.getValue(), e2.getValue())).findFirst().get().getKey(); + .sorted((e1, e2) -> durationComparatorNullsLast.compare(e1.getValue(), e2.getValue())).findFirst().get().getKey(); result = getGapToCompetitorInOwnTime(trackedLegOfCompetitor.getCompetitor(), leader, actualTimeFromRaceStartToReachFarthestAheadInLeg.get(trackedLegOfCompetitor.getCompetitor()), actualTimeFromRaceStartToReachFarthestAheadInLeg.get(leader), diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedLegOfCompetitor.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedLegOfCompetitor.java index d804bf4733d..b95e5b704b2 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedLegOfCompetitor.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedLegOfCompetitor.java @@ -13,6 +13,7 @@ import com.sap.sailing.domain.common.Speed; import com.sap.sailing.domain.common.SpeedWithBearing; import com.sap.sailing.domain.common.Wind; import com.sap.sailing.domain.common.tracking.GPSFixMoving; +import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo; import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; import com.sap.sse.common.Util; @@ -151,27 +152,31 @@ public interface TrackedLegOfCompetitor extends Serializable { /** * Computes the gap in seconds to the leader / winner of this leg. Returns null in case this leg's * competitor hasn't started the leg yet. + * @param rankingInfo TODO */ - Duration getGapToLeader(TimePoint timePoint, WindPositionMode windPositionMode); + Duration getGapToLeader(TimePoint timePoint, RankingInfo rankingInfo, WindPositionMode windPositionMode); /** - * Same as {@link #getGapToLeader(TimePoint, WindPositionMode)}, only that a cache for wind and leg type data is used. + * Same as {@link #getGapToLeader(TimePoint, RankingInfo, WindPositionMode)}, only that a cache for wind and leg type data is used. + * @param rankingInfo TODO */ - Duration getGapToLeader(TimePoint timePoint, WindPositionMode windPositionMode, WindLegTypeAndLegBearingCache cache); + Duration getGapToLeader(TimePoint timePoint, WindPositionMode windPositionMode, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache); /** * If a caller already went through the effort of computing the leg's leader at timePoint, it - * can share this knowledge to speed up computation as compared to {@link #getGapToLeader(TimePoint, WindPositionMode)}. + * can share this knowledge to speed up computation as compared to {@link #getGapToLeader(TimePoint, RankingInfo, WindPositionMode)}. + * @param rankingInfo TODO */ - Duration getGapToLeader(TimePoint timePoint, Competitor leaderInLegAtTimePoint, WindPositionMode windPositionMode) throws NoWindException; + Duration getGapToLeader(TimePoint timePoint, Competitor leaderInLegAtTimePoint, RankingInfo rankingInfo, WindPositionMode windPositionMode) throws NoWindException; /** - * Same as {@link #getGapToLeader(TimePoint, Competitor, WindPositionMode)}, only that an additional cache is used + * Same as {@link #getGapToLeader(TimePoint, Competitor, RankingInfo, WindPositionMode)}, only that an additional cache is used * to avoid redundant evaluations of leg types and wind field information across various calculations that * all can use the same basic information. + * @param rankingInfo TODO */ Duration getGapToLeader(TimePoint timePoint, Competitor leaderInLegAtTimePoint, - WindPositionMode windPositionMode, WindLegTypeAndLegBearingCache cache); + WindPositionMode windPositionMode, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache); boolean hasStartedLeg(TimePoint timePoint); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedLegOfCompetitorImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedLegOfCompetitorImpl.java index 5f84ac200b6..59617c611ef 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedLegOfCompetitorImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedLegOfCompetitorImpl.java @@ -25,6 +25,7 @@ import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl; import com.sap.sailing.domain.common.impl.MeterDistance; import com.sap.sailing.domain.common.tracking.GPSFixMoving; import com.sap.sailing.domain.leaderboard.caching.LeaderboardDTOCalculationReuseCache; +import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo; import com.sap.sailing.domain.tracking.GPSFixTrack; import com.sap.sailing.domain.tracking.Maneuver; import com.sap.sailing.domain.tracking.MarkPassing; @@ -486,15 +487,15 @@ public class TrackedLegOfCompetitorImpl implements TrackedLegOfCompetitor { } @Override - public Duration getGapToLeader(TimePoint timePoint, final Competitor leaderInLegAtTimePoint, WindPositionMode windPositionMode) - throws NoWindException { - return getGapToLeader(timePoint, leaderInLegAtTimePoint, windPositionMode, new LeaderboardDTOCalculationReuseCache(timePoint)); + public Duration getGapToLeader(TimePoint timePoint, final Competitor leaderInLegAtTimePoint, + final RankingInfo rankingInfo, WindPositionMode windPositionMode) throws NoWindException { + return getGapToLeader(timePoint, leaderInLegAtTimePoint, windPositionMode, rankingInfo, new LeaderboardDTOCalculationReuseCache(timePoint)); } @Override public Duration getGapToLeader(TimePoint timePoint, final Competitor leaderInLegAtTimePoint, - WindPositionMode windPositionMode, WindLegTypeAndLegBearingCache cache) { - return getGapToLeader(timePoint, ()->leaderInLegAtTimePoint, windPositionMode, cache); + WindPositionMode windPositionMode, final RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) { + return getGapToLeader(timePoint, ()->leaderInLegAtTimePoint, windPositionMode, rankingInfo, cache); } @FunctionalInterface @@ -503,17 +504,17 @@ public class TrackedLegOfCompetitorImpl implements TrackedLegOfCompetitor { } @Override - public Duration getGapToLeader(final TimePoint timePoint, WindPositionMode windPositionMode) { - return getGapToLeader(timePoint, windPositionMode, new LeaderboardDTOCalculationReuseCache(timePoint)); + public Duration getGapToLeader(final TimePoint timePoint, final RankingInfo rankingInfo, WindPositionMode windPositionMode) { + return getGapToLeader(timePoint, windPositionMode, rankingInfo, new LeaderboardDTOCalculationReuseCache(timePoint)); } @Override - public Duration getGapToLeader(final TimePoint timePoint, WindPositionMode windPositionMode, WindLegTypeAndLegBearingCache cache) { + public Duration getGapToLeader(final TimePoint timePoint, WindPositionMode windPositionMode, final RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) { return getGapToLeader(timePoint, ()->getTrackedLeg().getLeader(hasFinishedLeg(timePoint) ? getFinishTime() : timePoint), - windPositionMode, new LeaderboardDTOCalculationReuseCache(timePoint)); + windPositionMode, rankingInfo, new LeaderboardDTOCalculationReuseCache(timePoint)); } - private Duration getGapToLeader(TimePoint timePoint, LeaderGetter leaderGetter, WindPositionMode windPositionMode, WindLegTypeAndLegBearingCache cache) { + private Duration getGapToLeader(TimePoint timePoint, LeaderGetter leaderGetter, WindPositionMode windPositionMode, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) { // If a competitor already completed this leg, compute the estimated arrival time at the // end of this leg and compare to the first mark passing for the end of this leg; if this leg's competitor also already // finished the leg, return the difference between this competitor's leg completion time point and the leader's completion diff --git a/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch b/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch index 2f7207cca0f..92a6a72d15c 100755 --- a/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch +++ b/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch @@ -4,6 +4,9 @@ + + + @@ -56,7 +59,7 @@ - + diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/RegattaAndRaceDataJsonGetServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/RegattaAndRaceDataJsonGetServlet.java index ab154994dbd..50709bc5dc8 100755 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/RegattaAndRaceDataJsonGetServlet.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/RegattaAndRaceDataJsonGetServlet.java @@ -28,6 +28,7 @@ import com.sap.sailing.domain.common.Tack; import com.sap.sailing.domain.common.Wind; import com.sap.sailing.domain.common.tracking.GPSFix; import com.sap.sailing.domain.common.tracking.GPSFixMoving; +import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo; import com.sap.sailing.domain.tracking.GPSFixTrack; import com.sap.sailing.domain.tracking.TrackedLeg; import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; @@ -208,6 +209,7 @@ public class RegattaAndRaceDataJsonGetServlet extends AbstractJsonHttpServlet { System.out.println("Blocking at "+trackedRace.getUpdateCount()+" waiting for "+sinceUpdate); trackedRace.waitForNextUpdate(sinceUpdate); } + final RankingInfo rankingInfo = trackedRace.getRankingMetric().getRankingInfo(timePoint); JSONObject jsonRace = new JSONObject(); jsonRace.put("name", trackedRace.getRace().getName()); jsonRace.put("startoftracking", trackedRace.getStartOfTracking() == null ? 0l : trackedRace @@ -316,7 +318,7 @@ public class RegattaAndRaceDataJsonGetServlet extends AbstractJsonHttpServlet { } } jsonCompetitorInLeg.put("gapToLeaderInSeconds", - trackedLegOfCompetitor.getGapToLeader(timePoint, WindPositionMode.LEG_MIDDLE)); + trackedLegOfCompetitor.getGapToLeader(timePoint, rankingInfo, WindPositionMode.LEG_MIDDLE)); final Duration estimatedTimeToNextMarkInSeconds = trackedLegOfCompetitor .getEstimatedTimeToNextMark(timePoint, WindPositionMode.EXACT); jsonCompetitorInLeg.put("estimatedTimeToNextMarkInSeconds", diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java index 5668f8b5530..dd4905cfc63 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java @@ -38,6 +38,7 @@ import com.sap.sailing.domain.common.WindSource; import com.sap.sailing.domain.common.tracking.GPSFix; import com.sap.sailing.domain.common.tracking.GPSFixMoving; import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException; +import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo; import com.sap.sailing.domain.tracking.DynamicTrackedRace; import com.sap.sailing.domain.tracking.GPSFixTrack; import com.sap.sailing.domain.tracking.TrackedLeg; @@ -783,7 +784,7 @@ public class RegattasResource extends AbstractSailingServerResource { TrackedRace trackedRace = findTrackedRace(regattaName, raceName); TimePoint timePoint = trackedRace.getTimePointOfNewestEvent() == null ? MillisecondsTimePoint.now() : trackedRace.getTimePointOfNewestEvent(); - + final RankingInfo rankingInfo = trackedRace.getRankingMetric().getRankingInfo(timePoint); JSONObject jsonRaceResults = new JSONObject(); jsonRaceResults.put("name", trackedRace.getRace().getName()); jsonRaceResults.put("regatta", regatta.getName()); @@ -889,7 +890,7 @@ public class RegattasResource extends AbstractSailingServerResource { } } jsonCompetitorInLeg.put("gapToLeader-s", - trackedLegOfCompetitor.getGapToLeader(timePoint, WindPositionMode.LEG_MIDDLE)); + trackedLegOfCompetitor.getGapToLeader(timePoint, rankingInfo, WindPositionMode.LEG_MIDDLE)); jsonCompetitorInLeg.put("started", trackedLegOfCompetitor.hasStartedLeg(timePoint)); jsonCompetitorInLeg.put("finished", trackedLegOfCompetitor.hasFinishedLeg(timePoint)); jsonCompetitors.add(jsonCompetitorInLeg); @@ -935,7 +936,7 @@ public class RegattasResource extends AbstractSailingServerResource { TimePoint timePoint = trackedRace.getTimePointOfNewestEvent() == null ? MillisecondsTimePoint.now() : trackedRace.getTimePointOfNewestEvent(); // if(trackedRace.isLive(timePoint)) { - + final RankingInfo rankingInfo = trackedRace.getRankingMetric().getRankingInfo(timePoint); JSONObject jsonLiveData = new JSONObject(); jsonLiveData.put("name", trackedRace.getRace().getName()); jsonLiveData.put("regatta", regatta.getName()); @@ -990,7 +991,7 @@ public class RegattasResource extends AbstractSailingServerResource { } Duration gapToLeader = currentLegOfCompetitor.getGapToLeader(timePoint, - WindPositionMode.LEG_MIDDLE); + rankingInfo, WindPositionMode.LEG_MIDDLE); if (gapToLeader != null) { jsonCompetitorInLeg.put("gapToLeader-s", roundDouble(gapToLeader.asSeconds(), 2)); } diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy).launch b/java/com.sap.sailing.server/SailingServer (No Proxy).launch index d1cc35750e5..b2ce1901af2 100644 --- a/java/com.sap.sailing.server/SailingServer (No Proxy).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy).launch @@ -1,38 +1,38 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.xmlexport/src/com/sap/sailing/xmlexport/LeaderboardData.java b/java/com.sap.sailing.xmlexport/src/com/sap/sailing/xmlexport/LeaderboardData.java index bc2f2b10568..8fdc598c6f4 100644 --- a/java/com.sap.sailing.xmlexport/src/com/sap/sailing/xmlexport/LeaderboardData.java +++ b/java/com.sap.sailing.xmlexport/src/com/sap/sailing/xmlexport/LeaderboardData.java @@ -38,6 +38,7 @@ import com.sap.sailing.domain.common.impl.KnotSpeedImpl; import com.sap.sailing.domain.common.impl.MeterDistance; import com.sap.sailing.domain.common.tracking.GPSFixMoving; import com.sap.sailing.domain.leaderboard.Leaderboard; +import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo; import com.sap.sailing.domain.tracking.GPSFixTrack; import com.sap.sailing.domain.tracking.LineDetails; import com.sap.sailing.domain.tracking.Maneuver; @@ -607,7 +608,10 @@ public class LeaderboardData extends ExportAction { /** * Create xml elements related to a leg. */ - private Element createLegXML(TrackedLeg trackedLeg, Leaderboard leaderboard, int legCounter, Util.Pair> raceConfidenceAndErrorMessages, Util.Pair> legConfidenceAndErrorMessages) throws NoWindException, IOException, ServletException { + private Element createLegXML(TrackedLeg trackedLeg, Leaderboard leaderboard, int legCounter, + Util.Pair> raceConfidenceAndErrorMessages, + Util.Pair> legConfidenceAndErrorMessages) throws NoWindException, IOException, + ServletException { TimePoint timeSpent = MillisecondsTimePoint.now(); Leg leg = trackedLeg.getLeg(); Element legElement = new Element("leg"); @@ -633,8 +637,8 @@ public class LeaderboardData extends ExportAction { legElement.addContent(competitorElement); continue; } - TimePoint legFinishTime = competitorLeg.getFinishTime(); + final RankingInfo rankingMetricAtLegFinishTime = trackedLeg.getTrackedRace().getRankingMetric().getRankingInfo(legFinishTime); competitorLegDataElement.addContent(createTimedXML("leg_started_time_", competitorLeg.getStartTime())); Util.Pair maximumSpeed = competitorLeg.getMaximumSpeedOverGround(legFinishTime); addNamedElementWithValue(competitorLegDataElement, "maximum_speed_over_ground_in_knots", maximumSpeed != null ? maximumSpeed.getB().getKnots() : -1); @@ -650,7 +654,7 @@ public class LeaderboardData extends ExportAction { legConfidenceAndErrorMessages = updateConfidence("Competitor " + competitor.getName() + " seems to not have finished this leg before end of tracking time.", 0.1, legConfidenceAndErrorMessages); } addNamedElementWithValue(competitorLegDataElement, "time_spend_in_this_leg_as_millis", timeSpentInThisLeg != null ? timeSpentInThisLeg.asMillis() : new MillisecondsDurationImpl(0).asMillis()); - addNamedElementWithValue(competitorLegDataElement, "gap_to_leader_at_finish_in_seconds", competitorLeg.getGapToLeader(legFinishTime, WindPositionMode.LEG_MIDDLE).asSeconds()); + addNamedElementWithValue(competitorLegDataElement, "gap_to_leader_at_finish_in_seconds", competitorLeg.getGapToLeader(legFinishTime, rankingMetricAtLegFinishTime, WindPositionMode.LEG_MIDDLE).asSeconds()); Distance windwardDistanceToOverallLeader = competitorLeg.getWindwardDistanceToOverallLeader(legFinishTime, WindPositionMode.LEG_MIDDLE); addNamedElementWithValue(competitorLegDataElement, "windward_distance_to_overall_leader_that_has_finished_this_leg_in_meters", windwardDistanceToOverallLeader != null ? windwardDistanceToOverallLeader.getMeters() : 0); addNamedElementWithValue(competitorLegDataElement, "distance_traveled_in_meters", competitorLeg.getDistanceTraveled(legFinishTime).getMeters()); From d074b338d67fb758dc44e8aca75a7166cce3f976 Mon Sep 17 00:00:00 2001 From: Frederik Petersen Date: Thu, 28 May 2015 11:21:48 +0200 Subject: [PATCH 33/72] Fixed legType bug in polar service added method for logging weird input into polar service. can be enabled in code --- .../mining/GPSFixMovingWithPolarContext.java | 24 +++++++++---- .../polars/mining/PolarFixFilterCriteria.java | 36 +++++++++++++++++-- ...eedRegressionPerAngleClusterProcessor.java | 2 +- 3 files changed, 53 insertions(+), 9 deletions(-) diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/GPSFixMovingWithPolarContext.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/GPSFixMovingWithPolarContext.java index 8d9dffaf0af..241fb0113c5 100644 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/GPSFixMovingWithPolarContext.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/GPSFixMovingWithPolarContext.java @@ -21,6 +21,7 @@ import com.sap.sailing.domain.common.confidence.impl.BearingWithConfidenceImpl; import com.sap.sailing.domain.common.tracking.GPSFixMoving; import com.sap.sailing.domain.tracking.GPSFixTrack; import com.sap.sailing.domain.tracking.TrackedLeg; +import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.domain.tracking.WindWithConfidence; import com.sap.sse.common.TimePoint; @@ -39,6 +40,7 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe private final BearingWithConfidence trueWindAngle; private final WindWithConfidence> wind; private final SpeedWithBearingWithConfidence boatSpeed; + private LegType legType; public GPSFixMovingWithPolarContext(GPSFixMoving fix, TrackedRace race, Competitor competitor, ClusterGroup windSpeedClusterGroup, ClusterGroup angleClusterGroup) { @@ -144,13 +146,23 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe @Override public LegType getLegType() { - TimePoint timePoint = fix.getTimePoint(); - try { - final TrackedLeg currentLeg = race.getCurrentLeg(timePoint); - return currentLeg==null?null:currentLeg.getLegType(timePoint); - } catch (NoWindException e) { - return null; + LegType result = null; + if (legType == null) { + TimePoint timePoint = fix.getTimePoint(); + try { + TrackedLegOfCompetitor currentLegOfCompetitor = race.getCurrentLeg(getCompetitor(), timePoint); + if (currentLegOfCompetitor != null) { + final TrackedLeg currentLeg = currentLegOfCompetitor.getTrackedLeg(); + legType = currentLeg == null ? null : currentLeg.getLegType(timePoint); + } + } catch (NoWindException e) { + legType = null; + } + result = legType; + } else { + result = legType; } + return result; } @Override diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarFixFilterCriteria.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarFixFilterCriteria.java index 246bbebd6e7..953a3cb67c5 100644 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarFixFilterCriteria.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarFixFilterCriteria.java @@ -3,11 +3,13 @@ package com.sap.sailing.polars.mining; import java.util.Collection; import java.util.Iterator; import java.util.NavigableSet; +import java.util.logging.Logger; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence; import com.sap.sailing.domain.base.Waypoint; +import com.sap.sailing.domain.common.LegType; import com.sap.sailing.domain.common.Position; import com.sap.sailing.domain.common.confidence.BearingWithConfidence; import com.sap.sailing.domain.common.tracking.GPSFixMoving; @@ -22,6 +24,8 @@ import com.sap.sse.datamining.components.FilterCriterion; public class PolarFixFilterCriteria implements FilterCriterion { + private static final Logger logger = Logger.getLogger(PolarFixFilterCriteria.class.getName()); + /** * 0 if every competitor should be included. * 1 if only the leading competitor should be included and so on. @@ -57,9 +61,37 @@ public class PolarFixFilterCriteria implements FilterCriterion 70) { + logger.warning(String.format( + "Very wide upwind fix input to polar data container. Race: %s, Competitor: %s, Timepoint: %s, " + + "TWA: %s", element.getRace().getRace().getName(), element.getCompetitor().getName(), + element.getFix().getTimePoint(), twa)); + } else if (Math.abs(twa) < 35) { + logger.warning(String.format( + "Very narrow upwind fix input to polar data container. Race: %s, Competitor: %s, Timepoint: %s, " + + "TWA: %s", element.getRace().getRace().getName(), element.getCompetitor().getName(), + element.getFix().getTimePoint(), twa)); + } + } + } + private boolean importantDataIsNotNull(GPSFixMovingWithPolarContext element) { BearingWithConfidence angleToTheWind = element.getAngleToTheWind(); WindWithConfidence> windSpeed = element.getWind(); diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/SpeedRegressionPerAngleClusterProcessor.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/SpeedRegressionPerAngleClusterProcessor.java index 0b8267c03e9..19cc885d2e2 100644 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/SpeedRegressionPerAngleClusterProcessor.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/SpeedRegressionPerAngleClusterProcessor.java @@ -26,7 +26,7 @@ import com.sap.sse.datamining.shared.GroupKey; public class SpeedRegressionPerAngleClusterProcessor implements Processor, Void>{ -private static final Logger logger = Logger.getLogger(CubicRegressionPerCourseProcessor.class.getName()); + private static final Logger logger = Logger.getLogger(CubicRegressionPerCourseProcessor.class.getName()); private final Map regressions = new HashMap<>(); From 30a3b66c53b3ca69e7b3c16731ef2ca0f5038470 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 28 May 2015 11:41:45 +0200 Subject: [PATCH 34/72] default time-on-time and time-on-distance values to 1.0 / 0.0, respectively, in BaseRegattaLinkImpl --- .../sap/sailing/domain/ranking/RankingMetric.java | 11 +++++++++++ .../TimeOnTimeAndDistanceRankingMetric.java | 7 ++++--- .../domain/regattalike/BaseRegattaLikeImpl.java | 14 ++++++++++++-- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/RankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/RankingMetric.java index f011e15bf36..982742d03d5 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/RankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/RankingMetric.java @@ -5,6 +5,7 @@ import java.util.Comparator; import java.util.function.Function; import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.base.Leg; import com.sap.sailing.domain.common.Distance; import com.sap.sailing.domain.leaderboard.caching.LeaderboardDTOCalculationReuseCache; import com.sap.sailing.domain.tracking.TrackedLeg; @@ -112,6 +113,16 @@ public interface RankingMetric extends Serializable { * position at {@link #timePoint}. */ Competitor getLeaderByCorrectedEstimatedTimeToCompetitorFarthestAhead(); + + /** + * Similar to {@link #getLeaderByCorrectedEstimatedTimeToCompetitorFarthestAhead()}, but relative to a + * {@link Leg}. This will not consider any progress or position beyond the finishing of that leg. + * Instead, for those competitors who have already finished the leg, their + * {@link TrackedLegOfCompetitor#getFinishTime() finishing time} for the leg is used, and the distance traveled + * is normalized to the {@link TrackedLeg#getWindwardDistance() windward distance of the leg} at the + * {@link TrackedLeg#getReferenceTimePoint() reference time point}. + */ + Competitor getLeaderInLegByCalculatedTime(Leg leg); } public interface LegRankingInfo extends Timed, Serializable { diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java index f1af3d5cc29..909b01ee045 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java @@ -414,11 +414,12 @@ public class TimeOnTimeAndDistanceRankingMetric extends AbstractRankingMetric { } // leader in the leg is now the competitor with the least corrected time to reach the competitor farthest ahead in the leg Comparator durationComparatorNullsLast = Comparator.nullsLast(Comparator.naturalOrder()); - final Competitor leader = correctedTimeToReachFarthestAheadInLeg.entrySet().stream() + final Competitor legLeader = rankingInfo.getLeaderInLegByCalculatedTime(trackedLegOfCompetitor.getTrackedLeg().getLeg()); + final Competitor legLeader = correctedTimeToReachFarthestAheadInLeg.entrySet().stream() .sorted((e1, e2) -> durationComparatorNullsLast.compare(e1.getValue(), e2.getValue())).findFirst().get().getKey(); - result = getGapToCompetitorInOwnTime(trackedLegOfCompetitor.getCompetitor(), leader, + result = getGapToCompetitorInOwnTime(trackedLegOfCompetitor.getCompetitor(), legLeader, actualTimeFromRaceStartToReachFarthestAheadInLeg.get(trackedLegOfCompetitor.getCompetitor()), - actualTimeFromRaceStartToReachFarthestAheadInLeg.get(leader), + actualTimeFromRaceStartToReachFarthestAheadInLeg.get(legLeader), windwardDistanceFarthestTraveledUntilFinishingLeg); } return result; diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/regattalike/BaseRegattaLikeImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/regattalike/BaseRegattaLikeImpl.java index f5fb55a1948..7dbef9f0c15 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/regattalike/BaseRegattaLikeImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/regattalike/BaseRegattaLikeImpl.java @@ -64,7 +64,12 @@ public class BaseRegattaLikeImpl implements IsRegattaLike { final Double timeOnTimeFactorFromRegattaLog = getTimeOnTimeFactorFromRegattaLog(competitor); final Double result; if (timeOnTimeFactorFromRegattaLog == null) { - result = competitor.getTimeOnTimeFactor(); + final Double competitorTimeOnTimeFactorDefault = competitor.getTimeOnTimeFactor(); + if (competitorTimeOnTimeFactorDefault == null) { + result = 1.0; + } else { + result = competitorTimeOnTimeFactorDefault; + } } else { result = timeOnTimeFactorFromRegattaLog; } @@ -76,7 +81,12 @@ public class BaseRegattaLikeImpl implements IsRegattaLike { final Duration timeOnDistanceAllowancePerNauticalMileFromRegattaLog = getTimeOnDistanceAllowancePerNauticalMileFromRegattaLog(competitor); final Duration result; if (timeOnDistanceAllowancePerNauticalMileFromRegattaLog == null) { - result = competitor.getTimeOnDistanceAllowancePerNauticalMile(); + final Duration competitorAllowanceDefault = competitor.getTimeOnDistanceAllowancePerNauticalMile(); + if (competitorAllowanceDefault == null) { + result = Duration.NULL; + } else { + result = competitorAllowanceDefault; + } } else { result = timeOnDistanceAllowancePerNauticalMileFromRegattaLog; } From 591f0aaf3c454d40fc8a0993cff15306b558e062 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 28 May 2015 12:20:30 +0200 Subject: [PATCH 35/72] Bug 2916: Rotation with vendor prefix for Safari/iOS compatibility --- .../client/place/event/partials/racelist/AbstractRaceList.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/racelist/AbstractRaceList.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/racelist/AbstractRaceList.java index f4abeac01e9..98c4ff5ee97 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/racelist/AbstractRaceList.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/racelist/AbstractRaceList.java @@ -322,6 +322,7 @@ public abstract class AbstractRaceList extends Compos public void render(Context context, SimpleWindDTO value, SafeHtmlBuilder sb) { if (value != null) { SafeStylesBuilder safeStyles = new SafeStylesBuilder(); + safeStyles.trustedNameAndValue("-webkit-transform", "rotate(" + value.getTrueWindFromDeg() + "deg)"); safeStyles.trustedNameAndValue("transform", "rotate(" + value.getTrueWindFromDeg() + "deg)"); safeStyles.width(2.75, Unit.EM).height(2.75, Unit.EM); sb.append(TEMPLATE.windDirection(safeStyles.toSafeStyles())); From 18ec962a059b6c4a69e87a18f97a1072b3472769 Mon Sep 17 00:00:00 2001 From: Frederik Petersen Date: Thu, 28 May 2015 14:24:32 +0200 Subject: [PATCH 36/72] Merge both tacks in polar service --- .../domain/polars/PolarDataService.java | 6 +-- .../polars/impl/PolarDataServiceImpl.java | 37 ++++++++++------- .../mining/AngleAndSpeedRegression.java | 9 +++- .../CubicRegressionPerCourseProcessor.java | 29 ++++++------- .../mining/GPSFixMovingWithPolarContext.java | 41 ++++++++----------- ...erKey.java => LegTypePolarClusterKey.java} | 6 +-- .../mining/MovingAveragePolarClusterKey.java | 2 +- .../polars/mining/MovingAverageProcessor.java | 3 +- .../mining/MovingAverageProcessorImpl.java | 19 +++------ .../PolarDataDimensionCollectionFactory.java | 5 --- .../sailing/polars/mining/PolarDataMiner.java | 18 ++++---- .../polars/mining/PolarFixFilterCriteria.java | 4 +- .../gateway/jaxrs/api/PolarResource.java | 19 ++++----- 13 files changed, 89 insertions(+), 109 deletions(-) rename java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/{TackAndLegTypePolarClusterKey.java => LegTypePolarClusterKey.java} (54%) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/polars/PolarDataService.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/polars/PolarDataService.java index 637d96d9b58..8d65c64a5af 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/polars/PolarDataService.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/polars/PolarDataService.java @@ -173,12 +173,11 @@ public interface PolarDataService { * * @param boatClass * @param legType - * @param tack * @return The estimating function for the tack and legtype combination estimating boatspeed over windspeed for the * given boat class. All values in kn. * @throws NotEnoughDataHasBeenAddedException */ - PolynomialFunction getSpeedRegressionFunction(BoatClass boatClass, LegType legType, Tack tack) throws NotEnoughDataHasBeenAddedException; + PolynomialFunction getSpeedRegressionFunction(BoatClass boatClass, LegType legType) throws NotEnoughDataHasBeenAddedException; /** * This method is not intended to be used directly apart from debugging purposes. If you intend to use the polar service please @@ -186,12 +185,11 @@ public interface PolarDataService { * * @param boatClass * @param legType - * @param tack * @return The estimating function for the tack and legtype combination estimating true wind angle over windspeed for the * given boat class. TWA in degrees and windspeeds in knots. * @throws NotEnoughDataHasBeenAddedException */ - PolynomialFunction getAngleRegressionFunction(BoatClass boatClass, LegType legType, Tack tack) throws NotEnoughDataHasBeenAddedException; + PolynomialFunction getAngleRegressionFunction(BoatClass boatClass, LegType legType) throws NotEnoughDataHasBeenAddedException; /** * This method is not intended to be used directly apart from debugging purposes. If you intend to use the polar service please diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java index 89f69beab4c..d0dcb7fe35a 100755 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java @@ -10,6 +10,7 @@ import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence; import com.sap.sailing.domain.base.SpeedWithConfidence; +import com.sap.sailing.domain.base.impl.SpeedWithBearingWithConfidenceImpl; import com.sap.sailing.domain.common.Bearing; import com.sap.sailing.domain.common.LegType; import com.sap.sailing.domain.common.ManeuverType; @@ -20,6 +21,7 @@ import com.sap.sailing.domain.common.Tack; import com.sap.sailing.domain.common.confidence.BearingWithConfidence; import com.sap.sailing.domain.common.confidence.impl.BearingWithConfidenceImpl; import com.sap.sailing.domain.common.impl.DegreeBearingImpl; +import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl; import com.sap.sailing.domain.common.tracking.GPSFixMoving; import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException; import com.sap.sailing.domain.polars.PolarDataService; @@ -60,9 +62,19 @@ public class PolarDataServiceImpl implements PolarDataService { } @Override - public SpeedWithBearingWithConfidence getAverageSpeedWithBearing(BoatClass boatClass, - Speed windSpeed, LegType legType, Tack tack, boolean useRegressionForSpeed) throws NotEnoughDataHasBeenAddedException { - return polarDataMiner.getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType, tack, useRegressionForSpeed); + public SpeedWithBearingWithConfidence getAverageSpeedWithBearing(BoatClass boatClass, Speed windSpeed, + LegType legType, Tack tack, boolean useRegressionForSpeed) throws NotEnoughDataHasBeenAddedException { + SpeedWithBearingWithConfidence averageSpeedAndCourseOverGround = polarDataMiner + .getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType, useRegressionForSpeed); + if ((tack == Tack.PORT && legType == LegType.UPWIND) || (tack == Tack.STARBOARD && legType == LegType.DOWNWIND)) { + DegreeBearingImpl bearing = new DegreeBearingImpl(-averageSpeedAndCourseOverGround.getObject().getBearing() + .getDegrees()); + KnotSpeedWithBearingImpl speed = new KnotSpeedWithBearingImpl(averageSpeedAndCourseOverGround.getObject() + .getKnots(), bearing); + averageSpeedAndCourseOverGround = new SpeedWithBearingWithConfidenceImpl(speed, + averageSpeedAndCourseOverGround.getConfidence(), null); + } + return averageSpeedAndCourseOverGround; } @@ -139,15 +151,15 @@ public class PolarDataServiceImpl implements PolarDataService { } @Override - public PolynomialFunction getSpeedRegressionFunction(BoatClass boatClass, LegType legType, Tack tack) + public PolynomialFunction getSpeedRegressionFunction(BoatClass boatClass, LegType legType) throws NotEnoughDataHasBeenAddedException { - return polarDataMiner.getSpeedRegressionFunction(boatClass, legType, tack); + return polarDataMiner.getSpeedRegressionFunction(boatClass, legType); } @Override - public PolynomialFunction getAngleRegressionFunction(BoatClass boatClass, LegType legType, Tack tack) + public PolynomialFunction getAngleRegressionFunction(BoatClass boatClass, LegType legType) throws NotEnoughDataHasBeenAddedException { - return polarDataMiner.getAngleRegressionFunction(boatClass, legType, tack); + return polarDataMiner.getAngleRegressionFunction(boatClass, legType); } @Override @@ -171,14 +183,9 @@ public class PolarDataServiceImpl implements PolarDataService { if (boatClass == null || windSpeed == null) { throw new IllegalArgumentException("Boatclass and windspeed cannot be null."); } - SpeedWithBearingWithConfidence port = getAverageSpeedWithBearing(boatClass, windSpeed, legType, Tack.PORT); - SpeedWithBearingWithConfidence starboard = getAverageSpeedWithBearing(boatClass, windSpeed, legType, - Tack.STARBOARD); - double angleSumInDeg = Math.abs(port.getObject().getBearing().getDegrees()) - + Math.abs(starboard.getObject().getBearing().getDegrees()); - Bearing bearing = new DegreeBearingImpl(angleSumInDeg); - double confidence = (port.getConfidence() + starboard.getConfidence()) / 2; - BearingWithConfidence bearingWithConfidence = new BearingWithConfidenceImpl(bearing, confidence, + SpeedWithBearingWithConfidence speed = polarDataMiner.getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType, true); + Bearing bearing = new DegreeBearingImpl(speed.getObject().getBearing().getDegrees() * 2); + BearingWithConfidence bearingWithConfidence = new BearingWithConfidenceImpl(bearing, speed.getConfidence(), null); return bearingWithConfidence; } diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/AngleAndSpeedRegression.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/AngleAndSpeedRegression.java index 9f7fff45ac9..d21684e62de 100644 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/AngleAndSpeedRegression.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/AngleAndSpeedRegression.java @@ -8,9 +8,11 @@ import org.apache.commons.math.analysis.polynomials.PolynomialFunction; import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence; import com.sap.sailing.domain.base.impl.SpeedWithBearingWithConfidenceImpl; import com.sap.sailing.domain.common.Bearing; +import com.sap.sailing.domain.common.LegType; import com.sap.sailing.domain.common.Position; import com.sap.sailing.domain.common.Speed; import com.sap.sailing.domain.common.SpeedWithBearing; +import com.sap.sailing.domain.common.Tack; import com.sap.sailing.domain.common.confidence.BearingWithConfidence; import com.sap.sailing.domain.common.impl.DegreeBearingImpl; import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl; @@ -30,7 +32,7 @@ public class AngleAndSpeedRegression { private double maxWindSpeedInKnots = -1; public void addData(WindWithConfidence> windSpeed, - BearingWithConfidence angleToTheWind, SpeedWithBearingWithConfidence boatSpeed) { + BearingWithConfidence angleToTheWind, SpeedWithBearingWithConfidence boatSpeed) { double windSpeedInKnots = windSpeed.getObject().getKnots(); if (windSpeedInKnots > maxWindSpeedInKnots) { maxWindSpeedInKnots = windSpeedInKnots; @@ -51,7 +53,7 @@ public class AngleAndSpeedRegression { return new SpeedWithBearingWithConfidenceImpl(speedWithBearing, Math.min(1, speedRegression.getNumberOfAddedPoints() / 100.0), null); } - public Set> estimateTrueWindSpeedAndAngleCandidates(Speed speedOverGround) throws NotEnoughDataHasBeenAddedException { + public Set> estimateTrueWindSpeedAndAngleCandidates(Speed speedOverGround, LegType legType, Tack tack) throws NotEnoughDataHasBeenAddedException { double[] coefficiants = speedRegression.getOrCreatePolynomialFunction().getCoefficients(); CubicEquation equation = new CubicEquation(coefficiants[2], coefficiants[1], coefficiants[0], -speedOverGround.getKnots()); @@ -64,6 +66,9 @@ public class AngleAndSpeedRegression { boolean angleFound; try { angle = angleRegression.getOrCreatePolynomialFunction().value(windSpeedCandidateInKnots); + if ((tack == Tack.PORT && legType == LegType.UPWIND) || (tack == Tack.STARBOARD && legType == LegType.DOWNWIND)) { + angle = -angle; + } angleFound = true; } catch(NotEnoughDataHasBeenAddedException e) { angleFound = false; diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/CubicRegressionPerCourseProcessor.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/CubicRegressionPerCourseProcessor.java index c462f523d7f..fe92c251752 100644 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/CubicRegressionPerCourseProcessor.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/CubicRegressionPerCourseProcessor.java @@ -45,12 +45,13 @@ public class CubicRegressionPerCourseProcessor implements Processor getAverageSpeedAndCourseOverGround(BoatClass boatClass, Speed windSpeed, LegType legType, Tack tack) throws NotEnoughDataHasBeenAddedException { - GroupKey key = createGroupKey(boatClass, legType, tack); + public SpeedWithBearingWithConfidence getAverageSpeedAndCourseOverGround(BoatClass boatClass, + Speed windSpeed, LegType legType) throws NotEnoughDataHasBeenAddedException { + GroupKey key = createGroupKey(boatClass, legType); SpeedWithBearingWithConfidence estimatedSpeedAndAngle = null; if (regressions.containsKey(key)) { estimatedSpeedAndAngle = regressions.get(key).estimateSpeedAndAngle(windSpeed); @@ -62,11 +63,11 @@ public class CubicRegressionPerCourseProcessor implements Processor> estimateTrueWindSpeedAndAngleCandidates(BoatClass boatClass, Speed speedOverGround, LegType legType, Tack tack) { - GroupKey key = createGroupKey(boatClass, legType, tack); + GroupKey key = createGroupKey(boatClass, legType); Set> result = new HashSet<>(); if (regressions.containsKey(key)) { try { - result = regressions.get(key).estimateTrueWindSpeedAndAngleCandidates(speedOverGround); + result = regressions.get(key).estimateTrueWindSpeedAndAngleCandidates(speedOverGround, legType, tack); } catch (NotEnoughDataHasBeenAddedException e) { // Return empty result } @@ -76,20 +77,14 @@ public class CubicRegressionPerCourseProcessor implements Processor windSpeedClusterGroup; private final Set windSourcesToExcludeForSpeed; private final ClusterGroup angleClusterGroup; - private final BearingWithConfidence trueWindAngle; + private final BearingWithConfidence absTrueWindAngle; private final WindWithConfidence> wind; private final SpeedWithBearingWithConfidence boatSpeed; private LegType legType; @@ -50,7 +49,7 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe this.windSpeedClusterGroup = windSpeedClusterGroup; this.angleClusterGroup = angleClusterGroup; this.windSourcesToExcludeForSpeed = collectWindSourcesToIgnoreForSpeed(); - this.trueWindAngle = computeTrueWindAngle(); + this.absTrueWindAngle = computeTrueWindAngleAbsolute(); this.wind = race.getWindWithConfidence(fix.getPosition(), fix.getTimePoint(), windSourcesToExcludeForSpeed); this.boatSpeed = computeBoatSpeed(); } @@ -67,19 +66,22 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe return competitor; } - public BearingWithConfidence getAngleToTheWind() { - return trueWindAngle; + public BearingWithConfidence getAbsoluteAngleToTheWind() { + return absTrueWindAngle; } - private BearingWithConfidence computeTrueWindAngle() { - SpeedWithBearing boatSpeed = race.getTrack(competitor).getEstimatedSpeed(fix.getTimePoint()); + private BearingWithConfidence computeTrueWindAngleAbsolute() { + BearingWithConfidenceImpl result = null; + Bearing bearing; + try { + Bearing realBearing = race.getCurrentLeg(competitor, fix.getTimePoint()).getBeatAngle(fix.getTimePoint()); + bearing = new DegreeBearingImpl(Math.abs(realBearing.getDegrees())); + } catch (NoWindException e) { + bearing = null; + } WindWithConfidence> wind = race.getWindWithConfidence(fix.getPosition(), fix.getTimePoint()); - - BearingWithConfidenceImpl result = null; - if (wind != null && boatSpeed != null) { - Bearing bearing = boatSpeed.getBearing(); - Bearing difference = wind.getObject().getFrom().getDifferenceTo(bearing); - result = new BearingWithConfidenceImpl(difference, wind.getConfidence(), 0); + if (bearing != null && wind != null) { + result = new BearingWithConfidenceImpl(bearing, wind.getConfidence(), null); } return result; } @@ -135,15 +137,6 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe return race.getRace().getBoatClass(); } - @Override - public Tack getTack() { - return getTack(getAngleToTheWind().getObject()); - } - - public static Tack getTack(Bearing angleDifferenceWindToBoat) { - return angleDifferenceWindToBoat.getDegrees() <= 0 ? Tack.PORT : Tack.STARBOARD; - } - @Override public LegType getLegType() { LegType result = null; @@ -167,7 +160,7 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe @Override public Cluster getAngleCluster() { - return angleClusterGroup.getClusterFor(getAngleToTheWind().getObject()); + return angleClusterGroup.getClusterFor(getAbsoluteAngleToTheWind().getObject()); } } diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/TackAndLegTypePolarClusterKey.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/LegTypePolarClusterKey.java similarity index 54% rename from java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/TackAndLegTypePolarClusterKey.java rename to java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/LegTypePolarClusterKey.java index c783abcc6bf..4a60733b411 100644 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/TackAndLegTypePolarClusterKey.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/LegTypePolarClusterKey.java @@ -1,13 +1,9 @@ package com.sap.sailing.polars.mining; import com.sap.sailing.domain.common.LegType; -import com.sap.sailing.domain.common.Tack; import com.sap.sse.datamining.shared.annotations.Dimension; -public interface TackAndLegTypePolarClusterKey extends BasePolarClusterKey { - - @Dimension(messageKey = "tack") - Tack getTack(); +public interface LegTypePolarClusterKey extends BasePolarClusterKey { @Dimension(messageKey = "legType") LegType getLegType(); diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/MovingAveragePolarClusterKey.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/MovingAveragePolarClusterKey.java index c54228800de..7665f0a59f9 100644 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/MovingAveragePolarClusterKey.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/MovingAveragePolarClusterKey.java @@ -4,7 +4,7 @@ import com.sap.sailing.domain.common.Speed; import com.sap.sse.datamining.data.Cluster; import com.sap.sse.datamining.shared.annotations.Dimension; -public interface MovingAveragePolarClusterKey extends TackAndLegTypePolarClusterKey { +public interface MovingAveragePolarClusterKey extends LegTypePolarClusterKey { /** * diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/MovingAverageProcessor.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/MovingAverageProcessor.java index 529f749f480..b424d18a2dd 100755 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/MovingAverageProcessor.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/MovingAverageProcessor.java @@ -6,14 +6,13 @@ import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence; import com.sap.sailing.domain.common.LegType; import com.sap.sailing.domain.common.Speed; -import com.sap.sailing.domain.common.Tack; import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException; import com.sap.sse.datamining.components.Processor; import com.sap.sse.datamining.impl.components.GroupedDataEntry; public interface MovingAverageProcessor extends Processor, Void>{ SpeedWithBearingWithConfidence getAverageSpeedAndCourseOverGround(BoatClass boatClass, - Speed windSpeed, LegType legType, Tack tack) throws NotEnoughDataHasBeenAddedException; + Speed windSpeed, LegType legType) throws NotEnoughDataHasBeenAddedException; Set getAvailableBoatClasses(); } \ No newline at end of file diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/MovingAverageProcessorImpl.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/MovingAverageProcessorImpl.java index d389c4833de..ea352b76270 100755 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/MovingAverageProcessorImpl.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/MovingAverageProcessorImpl.java @@ -16,7 +16,6 @@ import com.sap.sailing.domain.common.LegType; import com.sap.sailing.domain.common.Position; import com.sap.sailing.domain.common.Speed; import com.sap.sailing.domain.common.SpeedWithBearing; -import com.sap.sailing.domain.common.Tack; import com.sap.sailing.domain.common.confidence.BearingWithConfidence; import com.sap.sailing.domain.common.impl.DegreeBearingImpl; import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl; @@ -77,7 +76,7 @@ public class MovingAverageProcessorImpl implements MovingAverageProcessor { averageAngleContainers.put(key, averageAngleContainer); } } - BearingWithConfidence angleToTheWind = fix.getAngleToTheWind(); + BearingWithConfidence angleToTheWind = fix.getAbsoluteAngleToTheWind(); WindWithConfidence> windSpeed = fix.getWind(); SpeedWithBearingWithConfidence boatSpeedWithConfidence = fix.getBoatSpeed(); availableBoatClasses.add(element.getDataEntry().getBoatClass()); @@ -177,21 +176,20 @@ public class MovingAverageProcessorImpl implements MovingAverageProcessor { @Override public SpeedWithBearingWithConfidence getAverageSpeedAndCourseOverGround(BoatClass boatClass, - Speed windSpeed, LegType legType, Tack tack) throws NotEnoughDataHasBeenAddedException { - SpeedWithBearingWithConfidence result = estimateSpeedAndAngle(boatClass, windSpeed, legType, tack); + Speed windSpeed, LegType legType) throws NotEnoughDataHasBeenAddedException { + SpeedWithBearingWithConfidence result = estimateSpeedAndAngle(boatClass, windSpeed, legType); return result; } - private SpeedWithBearingWithConfidence estimateSpeedAndAngle(BoatClass boatClass, Speed windSpeed, LegType legType, Tack tack) throws NotEnoughDataHasBeenAddedException { - GroupKey key = createGroupKey(boatClass, windSpeed, legType, tack); + private SpeedWithBearingWithConfidence estimateSpeedAndAngle(BoatClass boatClass, Speed windSpeed, LegType legType) throws NotEnoughDataHasBeenAddedException { + GroupKey key = createGroupKey(boatClass, windSpeed, legType); Bearing angleDiffTrueWindToBoat = estimateAngle(key); SpeedWithConfidence estimatedSpeed = estimateBoatSpeed(key).getSpeedWithConfidence(); SpeedWithBearing speedWithBearing = new KnotSpeedWithBearingImpl(estimatedSpeed.getObject().getKnots(), angleDiffTrueWindToBoat); return new SpeedWithBearingWithConfidenceImpl(speedWithBearing, estimatedSpeed.getConfidence(), null); } - private GroupKey createGroupKey(final BoatClass boatClass, final Speed windSpeed, final LegType legType, - final Tack tack) { + private GroupKey createGroupKey(final BoatClass boatClass, final Speed windSpeed, final LegType legType) { MovingAveragePolarClusterKey key = new MovingAveragePolarClusterKey() { @Override @@ -204,11 +202,6 @@ public class MovingAverageProcessorImpl implements MovingAverageProcessor { return speedClusterGroup.getClusterFor(windSpeed); } - @Override - public Tack getTack() { - return tack; - } - @Override public LegType getLegType() { return legType; diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataDimensionCollectionFactory.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataDimensionCollectionFactory.java index 19f4ef9b83e..daed33d8c9d 100644 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataDimensionCollectionFactory.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataDimensionCollectionFactory.java @@ -6,7 +6,6 @@ import java.util.Collection; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.common.Bearing; import com.sap.sailing.domain.common.LegType; -import com.sap.sailing.domain.common.Tack; import com.sap.sse.datamining.data.Cluster; import com.sap.sse.datamining.factories.FunctionFactory; import com.sap.sse.datamining.functions.Function; @@ -30,13 +29,9 @@ public class PolarDataDimensionCollectionFactory { private static void addTackAndLegTypeDimensions(Collection> dimensions, FunctionFactory functionFactory) throws NoSuchMethodException { - Function tackFunction = functionFactory - .createMethodWrappingFunction(MovingAveragePolarClusterKey.class.getMethod("getTack", - new Class[0])); Function legTypeFunction = functionFactory .createMethodWrappingFunction(MovingAveragePolarClusterKey.class.getMethod("getLegType", new Class[0])); - dimensions.add(tackFunction); dimensions.add(legTypeFunction); } diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataMiner.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataMiner.java index afd9517b42e..a4780d2351f 100755 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataMiner.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataMiner.java @@ -38,8 +38,8 @@ import com.sap.sailing.domain.common.impl.PolarSheetGenerationSettingsImpl; import com.sap.sailing.domain.common.impl.PolarSheetsDataImpl; import com.sap.sailing.domain.common.impl.PolarSheetsHistogramDataImpl; import com.sap.sailing.domain.common.impl.WindSpeedSteppingWithMaxDistance; -import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException; import com.sap.sailing.domain.common.tracking.GPSFixMoving; +import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException; import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.polars.impl.CubicEquation; import com.sap.sse.datamining.components.FilterCriterion; @@ -212,7 +212,7 @@ public class PolarDataMiner { private ClusterGroup createAngleClusterGroup() { - return new BearingClusterGroup(-180, 180, 5); + return new BearingClusterGroup(0, 180, 5); } public void addFix(GPSFixMoving fix, Competitor competitor, TrackedRace trackedRace) { @@ -392,24 +392,24 @@ public class PolarDataMiner { } public SpeedWithBearingWithConfidence getAverageSpeedAndCourseOverGround(BoatClass boatClass, - Speed windSpeed, LegType legType, Tack tack, boolean useRegressionForSpeed) throws NotEnoughDataHasBeenAddedException { + Speed windSpeed, LegType legType, boolean useRegressionForSpeed) throws NotEnoughDataHasBeenAddedException { SpeedWithBearingWithConfidence averageSpeedAndCourseOverGround = null; if (useRegressionForSpeed) { - averageSpeedAndCourseOverGround = cubicRegressionPerCourseProcessor.getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType, tack); + averageSpeedAndCourseOverGround = cubicRegressionPerCourseProcessor.getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType); } else { - averageSpeedAndCourseOverGround = movingAverageProcessor.getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType, tack); + averageSpeedAndCourseOverGround = movingAverageProcessor.getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType); } return averageSpeedAndCourseOverGround; } - public PolynomialFunction getSpeedRegressionFunction(BoatClass boatClass, LegType legType, Tack tack) + public PolynomialFunction getSpeedRegressionFunction(BoatClass boatClass, LegType legType) throws NotEnoughDataHasBeenAddedException { - return cubicRegressionPerCourseProcessor.getSpeedRegressionFunction(boatClass, legType, tack); + return cubicRegressionPerCourseProcessor.getSpeedRegressionFunction(boatClass, legType); } - public PolynomialFunction getAngleRegressionFunction(BoatClass boatClass, LegType legType, Tack tack) + public PolynomialFunction getAngleRegressionFunction(BoatClass boatClass, LegType legType) throws NotEnoughDataHasBeenAddedException { - return cubicRegressionPerCourseProcessor.getAngleRegressionFunction(boatClass, legType, tack); + return cubicRegressionPerCourseProcessor.getAngleRegressionFunction(boatClass, legType); } public PolynomialFunction getSpeedRegressionFunction(BoatClass boatClass, double trueWindAngle) diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarFixFilterCriteria.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarFixFilterCriteria.java index a89e1715a90..ac8fa458c92 100644 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarFixFilterCriteria.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarFixFilterCriteria.java @@ -69,7 +69,7 @@ public class PolarFixFilterCriteria implements FilterCriterion angleToTheWind = element.getAngleToTheWind(); + BearingWithConfidence angleToTheWind = element.getAbsoluteAngleToTheWind(); WindWithConfidence> windSpeed = element.getWind(); SpeedWithBearingWithConfidence boatSpeedWithConfidence = element.getBoatSpeed(); boolean result = false; diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/PolarResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/PolarResource.java index 4a0a4ed6ec2..020b2dc782b 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/PolarResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/PolarResource.java @@ -85,16 +85,15 @@ public class PolarResource extends AbstractSailingServerResource { StringBuilder stringBuilder = new StringBuilder(); for (BoatClass boatClass : boatClasses) { for (LegType legType : new LegType[] { LegType.UPWIND, LegType.DOWNWIND }) { - for (Tack tack : new Tack[] { Tack.PORT, Tack.STARBOARD }) { - try { - PolynomialFunction speedFunction = polarDataService.getSpeedRegressionFunction(boatClass, legType, tack); - stringBuilder.append("Speed: " + boatClass + " " + legType + " " + tack + ": " + speedFunction.toString() + "\n"); - PolynomialFunction angleFunction = polarDataService.getAngleRegressionFunction(boatClass, legType, tack); - stringBuilder.append("Angle: " + boatClass + " " + legType + " " + tack + ": " + angleFunction.toString() + "\n"); - } catch (NotEnoughDataHasBeenAddedException e) { - stringBuilder.append("No data for " + boatClass + " " + legType + " " + tack + "\n"); - } - } + try { + PolynomialFunction speedFunction = polarDataService.getSpeedRegressionFunction(boatClass, legType); + stringBuilder.append("Speed: " + boatClass + " " + legType + ": " + speedFunction.toString() + "\n"); + PolynomialFunction angleFunction = polarDataService.getAngleRegressionFunction(boatClass, legType); + stringBuilder.append("Angle: " + boatClass + " " + legType + ": " + angleFunction.toString() + "\n"); + } catch (NotEnoughDataHasBeenAddedException e) { + stringBuilder.append("No data for " + boatClass + " " + legType + "\n"); + } + } for (double trueWindAngle = -177.5; trueWindAngle < 180; trueWindAngle = trueWindAngle + 5) { try { From e4e00fa228c44f471d8782e833dd472a7be087f4 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 28 May 2015 14:32:35 +0200 Subject: [PATCH 37/72] turned competitorTracksOrderedByRank into a ConcurrentHashMap, avoiding synchronization --- .../domain/tracking/impl/TrackedLegImpl.java | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedLegImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedLegImpl.java index b65c6e245d1..7b93db79d07 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedLegImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedLegImpl.java @@ -12,6 +12,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Logger; import com.sap.sailing.domain.base.BoatClass; @@ -57,7 +58,7 @@ public class TrackedLegImpl implements TrackedLeg { private final Leg leg; private final Map trackedLegsOfCompetitors; private TrackedRaceImpl trackedRace; - private transient Map> competitorTracksOrderedByRank; + private transient ConcurrentHashMap> competitorTracksOrderedByRank; public TrackedLegImpl(DynamicTrackedRaceImpl trackedRace, Leg leg, Iterable competitors) { super(); @@ -68,12 +69,12 @@ public class TrackedLegImpl implements TrackedLeg { trackedLegsOfCompetitors.put(competitor, new TrackedLegOfCompetitorImpl(this, competitor)); } trackedRace.addListener(new CacheClearingRaceChangeListener()); - competitorTracksOrderedByRank = new HashMap<>(); + competitorTracksOrderedByRank = new ConcurrentHashMap<>(); } private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { ois.defaultReadObject(); - competitorTracksOrderedByRank = new HashMap<>(); + competitorTracksOrderedByRank = new ConcurrentHashMap<>(); } @Override @@ -124,11 +125,9 @@ public class TrackedLegImpl implements TrackedLeg { List getCompetitorTracksOrderedByRank(TimePoint timePoint, WindLegTypeAndLegBearingCache cache) { List rankedCompetitorList; - synchronized (competitorTracksOrderedByRank) { - rankedCompetitorList = competitorTracksOrderedByRank.get(timePoint); - if (rankedCompetitorList != null) { - rankedCompetitorList = new ArrayList(rankedCompetitorList); - } + rankedCompetitorList = competitorTracksOrderedByRank.get(timePoint); + if (rankedCompetitorList != null) { + rankedCompetitorList = new ArrayList(rankedCompetitorList); } if (rankedCompetitorList == null) { rankedCompetitorList = new ArrayList(); @@ -140,9 +139,7 @@ public class TrackedLegImpl implements TrackedLeg { // an the asynchronous nature of how the data is being received Collections.sort(rankedCompetitorList, getTrackedRace().getRankingMetric().getLegRankingComparator(this, timePoint, cache)); rankedCompetitorList = Collections.unmodifiableList(rankedCompetitorList); - synchronized (competitorTracksOrderedByRank) { - competitorTracksOrderedByRank.put(timePoint, rankedCompetitorList); - } + competitorTracksOrderedByRank.put(timePoint, rankedCompetitorList); if (Util.size(getTrackedLegsOfCompetitors()) != rankedCompetitorList.size()) { logger.warning("Number of competitors in leg (" + Util.size(getTrackedLegsOfCompetitors()) + ") differs from number of competitors in race (" @@ -302,9 +299,7 @@ public class TrackedLegImpl implements TrackedLeg { } private void clearCaches() { - synchronized (competitorTracksOrderedByRank) { - competitorTracksOrderedByRank.clear(); - } + competitorTracksOrderedByRank.clear(); } @Override From f11c5348922b37ad5dc6cf21d3e2dbfaf6b8c2a3 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 28 May 2015 14:33:09 +0200 Subject: [PATCH 38/72] compute current VMG only if average VMG is not available --- .../com/sap/sailing/domain/ranking/AbstractRankingMetric.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java index 276ba03d9b9..bf69509a249 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java @@ -454,9 +454,8 @@ public abstract class AbstractRankingMetric implements RankingMetric { private Duration getDurationToReach(final Position windwardPositionToReachInWhosCurrentLeg, TimePoint timePoint, final TrackedLegOfCompetitor whosLeg, WindLegTypeAndLegBearingCache cache) { final Duration toEndOfLegOrTo; - final Speed currentVMG = whosLeg.getVelocityMadeGood(timePoint, WindPositionMode.EXACT, cache); final Speed averageVMG = whosLeg.getAverageVelocityMadeGood(timePoint, cache); - final Speed vmg = Double.isNaN(averageVMG.getKnots()) ? currentVMG : averageVMG; + final Speed vmg = Double.isNaN(averageVMG.getKnots()) ? /* default to current VMG */ whosLeg.getVelocityMadeGood(timePoint, WindPositionMode.EXACT, cache) : averageVMG; toEndOfLegOrTo = vmg.getDuration( whosLeg.getTrackedLeg().getWindwardDistance( getTrackedRace().getTrack(whosLeg.getCompetitor()).getEstimatedPosition(timePoint, /* extrapolate */true), From 51929d5f67575a86632b4e517341eb1c107bcd5b Mon Sep 17 00:00:00 2001 From: Frederik Petersen Date: Thu, 28 May 2015 14:45:22 +0200 Subject: [PATCH 39/72] Fixed launch configs --- java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch | 14 +++++++++++++- java/com.sap.sailing.gwt.ui/SailingGWT.launch | 4 ++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch b/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch index 2f7207cca0f..7d6fc297515 100755 --- a/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch +++ b/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch @@ -4,6 +4,18 @@ + + + + + + + + + + + + @@ -56,7 +68,7 @@ - + diff --git a/java/com.sap.sailing.gwt.ui/SailingGWT.launch b/java/com.sap.sailing.gwt.ui/SailingGWT.launch index f08010aaad9..ae72a466d25 100755 --- a/java/com.sap.sailing.gwt.ui/SailingGWT.launch +++ b/java/com.sap.sailing.gwt.ui/SailingGWT.launch @@ -12,7 +12,7 @@ - + @@ -69,7 +69,7 @@ - + From 923d3b520f0af4c7ba55991c562fe2b199a15673 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 28 May 2015 14:47:10 +0200 Subject: [PATCH 40/72] The client locale can be obtained through DispatchContext on the server side --- .../shared/dispatch/SimpleDispatch.java | 3 ++- .../ui/server/dispatch/DispatchRPCImpl.java | 2 +- .../ui/shared/dispatch/DispatchContext.java | 9 ++++++++ .../shared/dispatch/DispatchContextImpl.java | 22 +++++++++++++++---- .../ui/shared/dispatch/RequestWrapper.java | 9 +++++++- .../event/GetEventOverviewStageAction.java | 1 + 6 files changed, 39 insertions(+), 7 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/dispatch/SimpleDispatch.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/dispatch/SimpleDispatch.java index 75062a7d3fb..401caa60100 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/dispatch/SimpleDispatch.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/dispatch/SimpleDispatch.java @@ -3,6 +3,7 @@ package com.sap.sailing.gwt.home.client.shared.dispatch; import java.util.Date; import com.google.gwt.core.client.GWT; +import com.google.gwt.i18n.client.LocaleInfo; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.rpc.ServiceDefTarget; import com.sap.sailing.gwt.ui.client.RemoteServiceMappingConstants; @@ -32,7 +33,7 @@ public class SimpleDispatch implements DispatchAsync { @Override public > void execute(A action, final AsyncCallback callback) { - dispatchRPC.execute(new RequestWrapper(action), new AsyncCallback>() { + dispatchRPC.execute(new RequestWrapper(action, LocaleInfo.getCurrentLocale().getLocaleName()), new AsyncCallback>() { @Override public void onFailure(Throwable caught) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/dispatch/DispatchRPCImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/dispatch/DispatchRPCImpl.java index 97c051d69fa..3514b566ec4 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/dispatch/DispatchRPCImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/dispatch/DispatchRPCImpl.java @@ -28,7 +28,7 @@ public class DispatchRPCImpl extends ProxiedRemoteServiceServlet implements Disp @Override public > ResultWrapper execute(RequestWrapper request) throws DispatchException { - R executionResult = request.getAction().execute(new DispatchContextImpl(request.getCurrentClientTime(), racingEventServiceTracker.getService())); + R executionResult = request.getAction().execute(new DispatchContextImpl(request.getCurrentClientTime(), racingEventServiceTracker.getService(), request.getClientLocaleName())); return new ResultWrapper(executionResult); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/DispatchContext.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/DispatchContext.java index dc49ad5ecfd..8ea041e4819 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/DispatchContext.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/DispatchContext.java @@ -1,9 +1,18 @@ package com.sap.sailing.gwt.ui.shared.dispatch; +import java.util.Date; +import java.util.Locale; + import com.sap.sailing.server.RacingEventService; public interface DispatchContext { RacingEventService getRacingEventService(); + + String getClientLocaleName(); + + Locale getClientLocale(); + + Date getCurrentClientTime(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/DispatchContextImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/DispatchContextImpl.java index 44071ace6d7..1813050dcaf 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/DispatchContextImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/DispatchContextImpl.java @@ -1,6 +1,7 @@ package com.sap.sailing.gwt.ui.shared.dispatch; import java.util.Date; +import java.util.Locale; import com.sap.sailing.server.RacingEventService; @@ -8,11 +9,13 @@ import com.sap.sailing.server.RacingEventService; public class DispatchContextImpl implements DispatchContext { private final RacingEventService racingEventService; private final Date currentClientTime; - private final Date currentServerTime = new Date(); +// private final Date currentServerTime = new Date(); + private String clientLocaleName; - public DispatchContextImpl(Date currentClientTime, RacingEventService racingEventService) { + public DispatchContextImpl(Date currentClientTime, RacingEventService racingEventService, String clientLocaleName) { this.currentClientTime = currentClientTime; this.racingEventService = racingEventService; + this.clientLocaleName = clientLocaleName; } @Override @@ -20,11 +23,22 @@ public class DispatchContextImpl implements DispatchContext { return racingEventService; } + @Override public Date getCurrentClientTime() { return currentClientTime; } - public Date getCurrentServerTime() { - return currentServerTime; +// public Date getCurrentServerTime() { +// return currentServerTime; +// } + + @Override + public String getClientLocaleName() { + return clientLocaleName; + } + + @Override + public Locale getClientLocale() { + return Locale.forLanguageTag(clientLocaleName); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/RequestWrapper.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/RequestWrapper.java index 3cfec4c936f..0a7be0417ff 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/RequestWrapper.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/RequestWrapper.java @@ -8,15 +8,18 @@ public class RequestWrapper> implements Is private Date currentClientTime = new Date(); + private String clientLocaleName; + private A action; @SuppressWarnings("unused") private RequestWrapper() { } - public RequestWrapper(A action) { + public RequestWrapper(A action, String clientLocaleName) { super(); this.action = action; + this.clientLocaleName = clientLocaleName; } public A getAction() { @@ -26,4 +29,8 @@ public class RequestWrapper> implements Is public Date getCurrentClientTime() { return currentClientTime; } + + public String getClientLocaleName() { + return clientLocaleName; + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java index 1de1703ac92..d1009001f1d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewStageAction.java @@ -52,6 +52,7 @@ public class GetEventOverviewStageAction implements Action videoURLs = event.getVideoURLs(); for (int i = Util.size(videoURLs) - 1; i >= 0; i--) { + // TODO fmittag/pgt: implement locale specific live stream using context.getClientLocaleName() or context.getClientLocale() String videoUrl = Util.get(videoURLs, i).toString(); MimeType type = MediaUtils.detectMimeTypeFromUrl(videoUrl); if (type == MimeType.youtube || type == MimeType.vimeo || type == MimeType.mp4) { From 97e7a9d183316f494d30983fb7695d34a6e0553f Mon Sep 17 00:00:00 2001 From: Frederik Petersen Date: Thu, 28 May 2015 14:59:47 +0200 Subject: [PATCH 41/72] Fixed access to average speed for supplied angle and windspeed --- .../sap/sailing/polars/impl/PolarDataServiceImpl.java | 2 +- .../polars/mining/GPSFixMovingWithPolarContext.java | 9 ++++++--- .../mining/SpeedRegressionPerAngleClusterProcessor.java | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java index d0dcb7fe35a..678eeaf7be1 100755 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java @@ -165,7 +165,7 @@ public class PolarDataServiceImpl implements PolarDataService { @Override public PolynomialFunction getSpeedRegressionFunction(BoatClass boatClass, double trueWindAngle) throws NotEnoughDataHasBeenAddedException { - return polarDataMiner.getSpeedRegressionFunction(boatClass, trueWindAngle); + return polarDataMiner.getSpeedRegressionFunction(boatClass, Math.abs(trueWindAngle)); } @Override diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/GPSFixMovingWithPolarContext.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/GPSFixMovingWithPolarContext.java index 375eef196d0..2e750ef5f2c 100644 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/GPSFixMovingWithPolarContext.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/GPSFixMovingWithPolarContext.java @@ -72,10 +72,13 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe private BearingWithConfidence computeTrueWindAngleAbsolute() { BearingWithConfidenceImpl result = null; - Bearing bearing; + Bearing bearing = null; try { - Bearing realBearing = race.getCurrentLeg(competitor, fix.getTimePoint()).getBeatAngle(fix.getTimePoint()); - bearing = new DegreeBearingImpl(Math.abs(realBearing.getDegrees())); + TrackedLegOfCompetitor currentLeg = race.getCurrentLeg(competitor, fix.getTimePoint()); + if (currentLeg != null) { + Bearing realBearing = currentLeg.getBeatAngle(fix.getTimePoint()); + bearing = new DegreeBearingImpl(Math.abs(realBearing.getDegrees())); + } } catch (NoWindException e) { bearing = null; } diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/SpeedRegressionPerAngleClusterProcessor.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/SpeedRegressionPerAngleClusterProcessor.java index 19cc885d2e2..5953fde119b 100644 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/SpeedRegressionPerAngleClusterProcessor.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/SpeedRegressionPerAngleClusterProcessor.java @@ -67,7 +67,7 @@ public class SpeedRegressionPerAngleClusterProcessor implements Processor Date: Thu, 28 May 2015 15:15:36 +0200 Subject: [PATCH 42/72] cache leg info about boat farthest ahead and calculate and cache the leader by calculated time for the leg in RankingInfo --- .../domain/ranking/AbstractRankingMetric.java | 137 ++++++++++++++++-- .../ranking/OneDesignRankingMetric.java | 7 +- .../sailing/domain/ranking/RankingMetric.java | 6 +- .../TimeOnTimeAndDistanceRankingMetric.java | 91 +----------- 4 files changed, 138 insertions(+), 103 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java index bf69509a249..767f2a8094f 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java @@ -2,7 +2,9 @@ package com.sap.sailing.domain.ranking; import java.util.Comparator; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.StreamSupport; @@ -10,9 +12,11 @@ import java.util.stream.StreamSupport; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Leg; import com.sap.sailing.domain.base.Waypoint; +import com.sap.sailing.domain.base.impl.CompetitorImpl; import com.sap.sailing.domain.common.Distance; import com.sap.sailing.domain.common.Position; import com.sap.sailing.domain.common.Speed; +import com.sap.sailing.domain.common.impl.MeterDistance; import com.sap.sailing.domain.leaderboard.caching.LeaderboardDTOCalculationReuseCache; import com.sap.sailing.domain.tracking.MarkPassing; import com.sap.sailing.domain.tracking.TrackedLeg; @@ -121,14 +125,77 @@ public abstract class AbstractRankingMetric implements RankingMetric { } } - public class RankingInfoImpl implements RankingMetric.RankingInfo { - private static final long serialVersionUID = -2390284312153324336L; - + /** + * Helper instance used to encode null values in {@link ConcurrentHashMap} instances which do not accept + * null as key nor value. + */ + private final static Competitor NULL_COMPETITOR = new CompetitorImpl(null, null, null, null, null, null, null, null, null); + + public abstract class AbstractRankingInfo implements RankingMetric.RankingInfo { + private static final long serialVersionUID = 6845168655725234325L; + /** * The time point for which this ranking information is valid */ private final TimePoint timePoint; + /** + * Caches, on demand, the results of calls to {@link #getCompetitorFarthestAheadInLeg(Leg, TimePoint, WindLegTypeAndLegBearingCache)}. + * null values are encoded as the {@link #NULL_COMPETITOR} and must be translated back to null before returning + * to a caller outside of this class. + */ + private final ConcurrentHashMap competitorFarthestAheadInLeg; + + public AbstractRankingInfo(final TimePoint timePoint) { + this.timePoint = timePoint; + this.competitorFarthestAheadInLeg = new ConcurrentHashMap<>(); + } + + @Override + public TimePoint getTimePoint() { + return timePoint; + } + + @Override + public Duration getActualTimeFromRaceStartToReachFarthestAheadInLeg(Competitor competitor, Leg leg, WindLegTypeAndLegBearingCache cache) { + final Duration result; + final TrackedLegOfCompetitor tloc = getTrackedRace().getTrackedLeg(competitor, getTimePoint()); + final Duration raceDurationAtTimePoint = getTrackedRace().getStartOfRace().until(getTimePoint()); + if (tloc.hasStartedLeg(getTimePoint())) { + final Competitor competitorFarthestAheadInLeg = getCompetitorFarthestAheadInLeg(leg, getTimePoint(), cache); + final TrackedLegOfCompetitor tlocOfCompetitorFarthestAheadInLeg = tloc.getTrackedLeg().getTrackedLeg(competitorFarthestAheadInLeg); + final Duration predictedDurationFromTimePointToReachFarthestAheadInLeg = getPredictedDurationToReachWindwardPositionOf( + tloc, tlocOfCompetitorFarthestAheadInLeg, getTimePoint(), cache); + final Duration cDurationFromRaceStartToReachFarthestInLeg = raceDurationAtTimePoint.plus(predictedDurationFromTimePointToReachFarthestAheadInLeg); + result = cDurationFromRaceStartToReachFarthestInLeg; + } else { + result = null; + } + return result; + } + + @Override + public Competitor getCompetitorFarthestAheadInLeg(Leg leg, TimePoint timePoint, WindLegTypeAndLegBearingCache cache) { + Competitor result = competitorFarthestAheadInLeg.get(leg); + if (result == NULL_COMPETITOR) { + result = null; + } else if (result == null) { + result = AbstractRankingMetric.this.getCompetitorFarthestAheadInLeg(getTrackedRace().getTrackedLeg(leg), timePoint, cache); + competitorFarthestAheadInLeg.put(leg, result); + } + return result; + } + + @Override + public Competitor getLeaderInLegByCalculatedTime(Leg leg, WindLegTypeAndLegBearingCache cache) { + final TrackedLeg trackedLeg = getTrackedRace().getTrackedLeg(leg); + return trackedLeg.getLeader(getTimePoint(), cache); + } + } + + public class RankingInfoImpl extends AbstractRankingInfo { + private static final long serialVersionUID = -2390284312153324336L; + /** * The basic information for each competitor, telling about actual and corrected times as well as information * about actual and corrected times needed to reach the position of the competitor farthest ahead at @@ -145,8 +212,8 @@ public abstract class AbstractRankingMetric implements RankingMetric { private final Competitor leaderByCorrectedEstimatedTimeToCompetitorFarthestAhead; public RankingInfoImpl(TimePoint timePoint, Map competitorRankingInfo, Competitor competitorFarthestAhead) { + super(timePoint); final Comparator durationComparatorNullsLast = Comparator.nullsLast(Comparator.naturalOrder()); - this.timePoint = timePoint; this.competitorRankingInfo = c->competitorRankingInfo.get(c); this.competitorFarthestAhead = competitorFarthestAhead; leaderByCorrectedEstimatedTimeToCompetitorFarthestAhead = competitorRankingInfo.keySet().stream().sorted( @@ -156,11 +223,6 @@ public abstract class AbstractRankingMetric implements RankingMetric { findFirst().get(); } - @Override - public TimePoint getTimePoint() { - return timePoint; - } - @Override public Function getCompetitorRankingInfo() { return competitorRankingInfo; @@ -553,4 +615,61 @@ public abstract class AbstractRankingMetric implements RankingMetric { } return result; } + + /** + * @return null if no competitor has started the leg yet; the first competitor to finish the leg if any + * has already finished the leg at timePoint; or the competitor with the greatest windward + * distance traveled in the leg at timePoint otherwise + */ + protected Competitor getCompetitorFarthestAheadInLeg(TrackedLeg trackedLeg, TimePoint timePoint, WindLegTypeAndLegBearingCache cache) { + Competitor firstAroundMark = getFirstLegFinisherBefore(trackedLeg, timePoint); + final Competitor result; + if (firstAroundMark != null) { + result = firstAroundMark; + } else { + Iterable markPassingsForLegStart = getTrackedRace().getMarkPassingsInOrder(trackedLeg.getLeg().getFrom()); + Distance maxWindwardDistanceTraveled = new MeterDistance(Double.MIN_VALUE); + Competitor competitorFarthestAlong = null; + getTrackedRace().lockForRead(markPassingsForLegStart); + try { + for (MarkPassing mp : markPassingsForLegStart) { + if (mp.getTimePoint().after(timePoint)) { + break; + } + final Distance windwardDistanceTraveled = getWindwardDistanceTraveled(mp.getCompetitor(), mp.getWaypoint(), + timePoint, cache); + if (windwardDistanceTraveled.compareTo(maxWindwardDistanceTraveled) > 0) { + maxWindwardDistanceTraveled = windwardDistanceTraveled; + competitorFarthestAlong = mp.getCompetitor(); + } + } + } finally { + getTrackedRace().unlockAfterRead(markPassingsForLegStart); + } + result = competitorFarthestAlong; + } + return result; + } + + /** + * Determines the first competitor finishing the leg identified by trackedLeg at or before timePoint. If + * no such competitor exists, null is returned. + */ + private Competitor getFirstLegFinisherBefore(TrackedLeg trackedLeg, TimePoint timePoint) { + Iterable markPassingsForLegEnd = getTrackedRace().getMarkPassingsInOrder(trackedLeg.getLeg().getTo()); + Competitor firstAroundMark = null; + getTrackedRace().lockForRead(markPassingsForLegEnd); + try { + final Iterator i = markPassingsForLegEnd.iterator(); + if (i.hasNext()) { + MarkPassing markPassing = i.next(); + if (!markPassing.getTimePoint().after(timePoint)) { + firstAroundMark = markPassing.getCompetitor(); + } + } + } finally { + getTrackedRace().unlockAfterRead(markPassingsForLegEnd); + } + return firstAroundMark; + } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/OneDesignRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/OneDesignRankingMetric.java index 90bab4b643d..e776d9ae64f 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/OneDesignRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/OneDesignRankingMetric.java @@ -75,14 +75,9 @@ public class OneDesignRankingMetric extends AbstractRankingMetric { @Override public RankingInfo getRankingInfo(final TimePoint timePoint, final WindLegTypeAndLegBearingCache cache) { - return new RankingInfo() { + return new AbstractRankingInfo(timePoint) { private static final long serialVersionUID = 25689357311324825L; - @Override - public TimePoint getTimePoint() { - return timePoint; - } - @Override public Function getCompetitorRankingInfo() { return competitor -> getCompetitorRankingInfo(competitor); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/RankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/RankingMetric.java index 982742d03d5..83d5b32cbfa 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/RankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/RankingMetric.java @@ -122,7 +122,11 @@ public interface RankingMetric extends Serializable { * is normalized to the {@link TrackedLeg#getWindwardDistance() windward distance of the leg} at the * {@link TrackedLeg#getReferenceTimePoint() reference time point}. */ - Competitor getLeaderInLegByCalculatedTime(Leg leg); + Competitor getLeaderInLegByCalculatedTime(Leg leg, WindLegTypeAndLegBearingCache cache); + + Competitor getCompetitorFarthestAheadInLeg(Leg leg, TimePoint timePoint, WindLegTypeAndLegBearingCache cache); + + Duration getActualTimeFromRaceStartToReachFarthestAheadInLeg(Competitor competitor, Leg leg, WindLegTypeAndLegBearingCache cache); } public interface LegRankingInfo extends Timed, Serializable { diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java index 909b01ee045..c341f8a3f11 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java @@ -2,7 +2,6 @@ package com.sap.sailing.domain.ranking; import java.util.Comparator; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; import java.util.function.Function; import java.util.function.Supplier; @@ -14,7 +13,6 @@ import com.sap.sailing.domain.base.Waypoint; import com.sap.sailing.domain.common.Distance; import com.sap.sailing.domain.common.Mile; import com.sap.sailing.domain.common.Position; -import com.sap.sailing.domain.common.impl.MeterDistance; import com.sap.sailing.domain.tracking.MarkPassing; import com.sap.sailing.domain.tracking.TrackedLeg; import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; @@ -160,63 +158,6 @@ public class TimeOnTimeAndDistanceRankingMetric extends AbstractRankingMetric { compareTo(correctedTimesToReachFastestBoatsPositionAtTimePointOrEndOfLegMeasuredFromStartOfRace.get(tloc2.getCompetitor())); } - /** - * @return null if no competitor has started the leg yet; the first competitor to finish the leg if any - * has already finished the leg at timePoint; or the competitor with the greatest windward - * distance traveled in the leg at timePoint otherwise - */ - private Competitor getCompetitorFarthestAheadInLeg(TrackedLeg trackedLeg, TimePoint timePoint, WindLegTypeAndLegBearingCache cache) { - Competitor firstAroundMark = getFirstLegFinisherBefore(trackedLeg, timePoint); - final Competitor result; - if (firstAroundMark != null) { - result = firstAroundMark; - } else { - Iterable markPassingsForLegStart = getTrackedRace().getMarkPassingsInOrder(trackedLeg.getLeg().getFrom()); - Distance maxWindwardDistanceTraveled = new MeterDistance(Double.MIN_VALUE); - Competitor competitorFarthestAlong = null; - getTrackedRace().lockForRead(markPassingsForLegStart); - try { - for (MarkPassing mp : markPassingsForLegStart) { - if (mp.getTimePoint().after(timePoint)) { - break; - } - final Distance windwardDistanceTraveled = getWindwardDistanceTraveled(mp.getCompetitor(), mp.getWaypoint(), - timePoint, cache); - if (windwardDistanceTraveled.compareTo(maxWindwardDistanceTraveled) > 0) { - maxWindwardDistanceTraveled = windwardDistanceTraveled; - competitorFarthestAlong = mp.getCompetitor(); - } - } - } finally { - getTrackedRace().unlockAfterRead(markPassingsForLegStart); - } - result = competitorFarthestAlong; - } - return result; - } - - /** - * Determines the first competitor finishing the leg identified by trackedLeg at or before timePoint. If - * no such competitor exists, null is returned. - */ - private Competitor getFirstLegFinisherBefore(TrackedLeg trackedLeg, TimePoint timePoint) { - Iterable markPassingsForLegEnd = getTrackedRace().getMarkPassingsInOrder(trackedLeg.getLeg().getTo()); - Competitor firstAroundMark = null; - getTrackedRace().lockForRead(markPassingsForLegEnd); - try { - final Iterator i = markPassingsForLegEnd.iterator(); - if (i.hasNext()) { - MarkPassing markPassing = i.next(); - if (!markPassing.getTimePoint().after(timePoint)) { - firstAroundMark = markPassing.getCompetitor(); - } - } - } finally { - getTrackedRace().unlockAfterRead(markPassingsForLegEnd); - } - return firstAroundMark; - } - @Override public Duration getCorrectedTime(Competitor competitor, TimePoint timePoint, WindLegTypeAndLegBearingCache cache) { final Duration timeActuallySpent = getActualTimeSinceStartOfRace(competitor, timePoint); @@ -379,47 +320,23 @@ public class TimeOnTimeAndDistanceRankingMetric extends AbstractRankingMetric { public Duration getLegGapToLegLeaderInOwnTime(TrackedLegOfCompetitor trackedLegOfCompetitor, TimePoint timePoint, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) { final Duration result; + final Leg leg = trackedLegOfCompetitor.getLeg(); if (getTrackedRace().getStartOfRace() == null || !trackedLegOfCompetitor.hasStartedLeg(timePoint)) { result = null; } else { - final Duration raceDurationAtTimePoint = getTrackedRace().getStartOfRace().until(timePoint); final Competitor farthestAheadOrEarliestLegFinisher = getCompetitorFarthestAheadInLeg(trackedLegOfCompetitor.getTrackedLeg(), timePoint, cache); final TrackedLegOfCompetitor tlocOfFarthestAhead = trackedLegOfCompetitor.getTrackedLeg().getTrackedLeg(farthestAheadOrEarliestLegFinisher); final boolean farthestAheadAlreadyFinishedLeg = tlocOfFarthestAhead.hasFinishedLeg(timePoint); final Distance windwardDistanceFarthestTraveledUntilFinishingLeg = getWindwardDistanceTraveled(farthestAheadOrEarliestLegFinisher, farthestAheadAlreadyFinishedLeg ? tlocOfFarthestAhead.getFinishTime() : timePoint, cache); - final Map correctedTimeToReachFarthestAheadInLeg = new HashMap<>(); - final Map actualTimeFromRaceStartToReachFarthestAheadInLeg = new HashMap<>(); // Consider all competitors, regardless of whether they have started the leg or not; a competitor in a previous // leg may well be the race leader. However, if a competitor has finished the leg already, use the finishing time // point for that competitor. - // FIXME need to calculate the ranking stuff only once for requests for all competitors to this method, or else we'll end up with n^2 effort - // FIXME The competitor iteration is only necessary here because we need to know the "leader"; other than that, computing things for the leader and the trackedLegOfCompetitor's competitor is sufficient here - // FIXME Grab the leader information from RankingInfo; CAUTION: leg leader is not necessarily identical to race leader! RankingInfo may need another field for each leg leader - for (Competitor c : getTrackedRace().getRace().getCompetitors()) { - final TrackedLegOfCompetitor tloc = trackedLegOfCompetitor.getTrackedLeg().getTrackedLeg(c); - if (tloc.hasStartedLeg(timePoint)) { - final Duration predictedDurationFromTimePointToReachFarthestAheadInLeg = getPredictedDurationToReachWindwardPositionOf(tloc, tlocOfFarthestAhead, timePoint, cache); - final Duration cDurationFromRaceStartToReachFarthestInLeg = raceDurationAtTimePoint.plus(predictedDurationFromTimePointToReachFarthestAheadInLeg); - actualTimeFromRaceStartToReachFarthestAheadInLeg.put(c, cDurationFromRaceStartToReachFarthestInLeg); - final Duration correctedTimeWhenReachingFarthestAheadInLeg = getCorrectedTime(c, ()->tloc.getTrackedLeg().getLeg(), - ()->farthestAheadAlreadyFinishedLeg?getTrackedRace().getApproximatePosition(tlocOfFarthestAhead.getTrackedLeg().getLeg().getTo(), tlocOfFarthestAhead.getFinishTime()): - getTrackedRace().getTrack(farthestAheadOrEarliestLegFinisher).getEstimatedPosition(timePoint, /* extrapolate */ true), - cDurationFromRaceStartToReachFarthestInLeg, windwardDistanceFarthestTraveledUntilFinishingLeg); - correctedTimeToReachFarthestAheadInLeg.put(c, correctedTimeWhenReachingFarthestAheadInLeg); - } else { - actualTimeFromRaceStartToReachFarthestAheadInLeg.put(c, null); - correctedTimeToReachFarthestAheadInLeg.put(c, null); - } - } // leader in the leg is now the competitor with the least corrected time to reach the competitor farthest ahead in the leg - Comparator durationComparatorNullsLast = Comparator.nullsLast(Comparator.naturalOrder()); - final Competitor legLeader = rankingInfo.getLeaderInLegByCalculatedTime(trackedLegOfCompetitor.getTrackedLeg().getLeg()); - final Competitor legLeader = correctedTimeToReachFarthestAheadInLeg.entrySet().stream() - .sorted((e1, e2) -> durationComparatorNullsLast.compare(e1.getValue(), e2.getValue())).findFirst().get().getKey(); + final Competitor legLeader = rankingInfo.getLeaderInLegByCalculatedTime(trackedLegOfCompetitor.getTrackedLeg().getLeg(), cache); result = getGapToCompetitorInOwnTime(trackedLegOfCompetitor.getCompetitor(), legLeader, - actualTimeFromRaceStartToReachFarthestAheadInLeg.get(trackedLegOfCompetitor.getCompetitor()), - actualTimeFromRaceStartToReachFarthestAheadInLeg.get(legLeader), + rankingInfo.getActualTimeFromRaceStartToReachFarthestAheadInLeg(trackedLegOfCompetitor.getCompetitor(), leg, cache), + rankingInfo.getActualTimeFromRaceStartToReachFarthestAheadInLeg(legLeader, leg, cache), windwardDistanceFarthestTraveledUntilFinishingLeg); } return result; From e62091996ec26b2324aa4733751aaf9e9ad12e11 Mon Sep 17 00:00:00 2001 From: Frederik Petersen Date: Thu, 28 May 2015 15:48:26 +0200 Subject: [PATCH 43/72] Added some confidence by datacount calculations to angle cluster polar service --- .../sailing/polars/mining/PolarDataMiner.java | 8 ++++- ...eedRegressionPerAngleClusterProcessor.java | 30 +++++++++++++++---- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataMiner.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataMiner.java index a4780d2351f..58c6d535ed6 100755 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataMiner.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataMiner.java @@ -326,8 +326,14 @@ public class PolarDataMiner { SpeedWithConfidence speedWithConfidence; try { int convertedAngle = convertAngleIfNecessary(angle); - speedWithConfidence = speedRegressionPerAngleClusterProcessor.estimateBoatSpeed(boatClass, + SpeedWithConfidence regressionResult = speedRegressionPerAngleClusterProcessor.estimateBoatSpeed(boatClass, new KnotSpeedImpl(windSpeed), new DegreeBearingImpl(convertedAngle)); + if (regressionResult.getConfidence() > 0.1) { + speedWithConfidence = regressionResult; + } else { + // Low confidence. So put in 0 speed for chart + speedWithConfidence = new SpeedWithConfidenceImpl(new KnotSpeedImpl(0), regressionResult.getConfidence(), null); + } } catch (NotEnoughDataHasBeenAddedException e) { // No data so put in a 0 speed with 0 confidence speedWithConfidence = new SpeedWithConfidenceImpl(new KnotSpeedImpl(0), 0, null); diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/SpeedRegressionPerAngleClusterProcessor.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/SpeedRegressionPerAngleClusterProcessor.java index 5953fde119b..e1fb5b9e1b4 100644 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/SpeedRegressionPerAngleClusterProcessor.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/SpeedRegressionPerAngleClusterProcessor.java @@ -29,6 +29,8 @@ public class SpeedRegressionPerAngleClusterProcessor implements Processor regressions = new HashMap<>(); + + private final Map fixCountPerBoatClass = new HashMap<>(); private final ClusterGroup angleClusterGroup; @@ -46,6 +48,13 @@ public class SpeedRegressionPerAngleClusterProcessor implements Processor element) { GroupKey key = element.getKey(); IncrementalLeastSquares regression; + BoatClass boatClass = element.getDataEntry().getBoatClass(); + synchronized (fixCountPerBoatClass) { + if (!fixCountPerBoatClass.containsKey(boatClass)) { + fixCountPerBoatClass.put(boatClass, 0L); + } + fixCountPerBoatClass.put(boatClass, fixCountPerBoatClass.get(boatClass) + 1); + } synchronized (regressions) { regression = regressions.get(key); if (regression == null) { @@ -66,18 +75,29 @@ public class SpeedRegressionPerAngleClusterProcessor implements Processor estimateBoatSpeed(BoatClass boatClass, Speed windSpeed, Bearing trueWindAngle) throws NotEnoughDataHasBeenAddedException { double speedSum = 0; double numberOfSpeeds = 0; - for (int i = -5; i <= 5; i++) { + long fixCount = 0; + for (int i = -2; i <= 2; i++) { GroupKey key = createGroupKey(boatClass, new DegreeBearingImpl(Math.abs(trueWindAngle.getDegrees()) + i)); if (regressions.containsKey(key)) { - speedSum += regressions.get(key).getOrCreatePolynomialFunction().value(windSpeed.getKnots()); - numberOfSpeeds++; + IncrementalLeastSquares incrementalLeastSquares = regressions.get(key); + fixCount = fixCount + incrementalLeastSquares.getNumberOfAddedPoints(); + if (fixCount > 10) { + speedSum += incrementalLeastSquares.getOrCreatePolynomialFunction().value(windSpeed.getKnots()); + numberOfSpeeds++; + } } } - if (numberOfSpeeds < 1) { + fixCount = (long) (fixCount / numberOfSpeeds); + long fixCountOverall = 0; + if (numberOfSpeeds < 2 || fixCount < 10) { throw new NotEnoughDataHasBeenAddedException("Not enough data has been added to Per Course Regressions"); + } else { + synchronized (fixCountPerBoatClass) { + fixCountOverall = fixCountPerBoatClass.get(boatClass); + } } Speed speed = new KnotSpeedImpl(speedSum / numberOfSpeeds); - return new SpeedWithConfidenceImpl(speed, /*FIXME*/ 0.5, null); + return new SpeedWithConfidenceImpl(speed, Math.min(1, 5.0 * ((double) fixCount / fixCountOverall)), null); } private GroupKey createGroupKey(final BoatClass boatClass, final Bearing angle) { From f522527d6551b83b93c6a0a36ba68c48f296ba52 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 28 May 2015 16:12:09 +0200 Subject: [PATCH 44/72] accelerated chart calculations by pre-calculating RankingInfo beforehand, then sharing --- .../domain/test/mock/MockedTrackedRace.java | 9 ++------ ...ockedTrackedRaceWithStartTimeAndRanks.java | 9 ++------ .../impl/AbstractSimpleLeaderboardImpl.java | 4 ++-- .../tracking/TrackedLegOfCompetitor.java | 9 +++++--- .../sailing/domain/tracking/TrackedRace.java | 23 ++++++++----------- .../impl/TrackedLegOfCompetitorImpl.java | 6 ++--- .../domain/tracking/impl/TrackedRaceImpl.java | 16 +++++-------- .../gwt/ui/test/MockedTrackedRace.java | 9 ++------ .../gwt/ui/client/DetailTypeFormatter.java | 12 +++++----- .../sailing/gwt/ui/client/StringMessages.java | 8 +++---- .../gwt/ui/client/StringMessages.properties | 14 +++++------ .../ui/client/StringMessages_cn.properties | 14 +++++------ .../ui/client/StringMessages_de.properties | 12 +++++----- .../ui/client/StringMessages_ru.properties | 14 +++++------ .../gwt/ui/server/SailingServiceImpl.java | 7 ++++-- .../gateway/jaxrs/api/RegattasResource.java | 2 +- .../server/masterdata/DummyTrackedRace.java | 9 ++------ .../sailing/xmlexport/LeaderboardData.java | 2 +- 18 files changed, 78 insertions(+), 101 deletions(-) diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java index ec4d14c8127..c76c88397ae 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java @@ -44,6 +44,7 @@ import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException; import com.sap.sailing.domain.polars.PolarDataService; import com.sap.sailing.domain.racelog.tracking.GPSFixStore; import com.sap.sailing.domain.ranking.RankingMetric; +import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo; import com.sap.sailing.domain.ranking.RankingMetricConstructor; import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier; import com.sap.sailing.domain.regattalike.RegattaLikeListener; @@ -934,15 +935,9 @@ public class MockedTrackedRace implements DynamicTrackedRace { return null; } - @Override - public Distance getCorrectedWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, - WindPositionMode windPositionMode) throws NoWindException { - return null; - } - @Override public Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, - WindPositionMode windPositionMode, WindLegTypeAndLegBearingCache cache) { + WindPositionMode windPositionMode, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) { return null; } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java index 9489add3d10..007efbaa6d7 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java @@ -35,6 +35,7 @@ import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException; import com.sap.sailing.domain.polars.PolarDataService; import com.sap.sailing.domain.racelog.tracking.GPSFixStore; import com.sap.sailing.domain.ranking.RankingMetric; +import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo; import com.sap.sailing.domain.tracking.CourseDesignChangedListener; import com.sap.sailing.domain.tracking.GPSFixTrack; import com.sap.sailing.domain.tracking.LineDetails; @@ -610,15 +611,9 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace { return 0; } - @Override - public Distance getCorrectedWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, - WindPositionMode windPositionMode) throws NoWindException { - return null; - } - @Override public Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, - WindPositionMode windPositionMode, WindLegTypeAndLegBearingCache cache) { + WindPositionMode windPositionMode, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) { return null; } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java index 863d98cfcb2..4eb21116aec 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java @@ -1581,7 +1581,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race private RaceDetails calculateRaceDetails(TrackedRace trackedRace, Competitor competitor, TimePoint timePoint, boolean waitForLatestAnalyses, Map> legRanksCache, - WindLegTypeAndLegBearingCache cache, RankingInfo rankingInfo) throws NoWindException { + WindLegTypeAndLegBearingCache cache, final RankingInfo rankingInfo) throws NoWindException { final List legDetails = new ArrayList(); final Course course = trackedRace.getRace().getCourse(); course.lockForRead(); // hold back any course re-configurations while looping over the legs @@ -1600,7 +1600,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race legDetails.add(legEntry); } final Distance windwardDistanceToOverallLeader = trackedRace == null ? null : trackedRace - .getWindwardDistanceToOverallLeader(competitor, timePoint, WindPositionMode.LEG_MIDDLE, cache); + .getWindwardDistanceToOverallLeader(competitor, timePoint, WindPositionMode.LEG_MIDDLE, rankingInfo, cache); Distance averageAbsoluteCrossTrackError; try { averageAbsoluteCrossTrackError = trackedRace == null ? null : trackedRace.getAverageAbsoluteCrossTrackError( diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedLegOfCompetitor.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedLegOfCompetitor.java index b95e5b704b2..107b584152b 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedLegOfCompetitor.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedLegOfCompetitor.java @@ -233,14 +233,17 @@ public interface TrackedLegOfCompetitor extends Serializable { * distance between this leg's competitor and the leader is returned. Note that this can lead to a situation where * the distance to leader is unrelated to the {@link #getWindwardDistanceToGo(TimePoint, WindPositionMode) distance to go} which is * used for ranking. + * + * @param rankingInfo materialized ranking information that is pre-calculated to avoid expensive redundant work */ - Distance getWindwardDistanceToOverallLeader(TimePoint timePoint, WindPositionMode windPositionMode); + Distance getWindwardDistanceToOverallLeader(TimePoint timePoint, WindPositionMode windPositionMode, RankingInfo rankingInfo); /** - * Same as {@link #getWindwardDistanceToOverallLeader(TimePoint, WindPositionMode)}, only that a cache for leg type + * Same as {@link #getWindwardDistanceToOverallLeader(TimePoint, WindPositionMode, RankingInfo)}, only that a cache for leg type * calculation is passed. + * @param rankingInfo TODO */ - Distance getWindwardDistanceToOverallLeader(TimePoint timePoint, WindPositionMode windPositionMode, WindLegTypeAndLegBearingCache cache); + Distance getWindwardDistanceToOverallLeader(TimePoint timePoint, WindPositionMode windPositionMode, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache); /** * Computes the average absolute cross track error for this leg. The cross track error for each fix is taken to be a diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java index f33ae238f70..18847ed51d7 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java @@ -41,6 +41,7 @@ import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException; import com.sap.sailing.domain.polars.PolarDataService; import com.sap.sailing.domain.racelog.tracking.GPSFixStore; import com.sap.sailing.domain.ranking.RankingMetric; +import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo; import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; import com.sap.sse.common.Util; @@ -515,16 +516,19 @@ public interface TrackedRace extends Serializable { Distance getDistanceTraveledIncludingGateStart(Competitor competitor, TimePoint timePoint); /** - * See {@link TrackedLegOfCompetitor#getWindwardDistanceToOverallLeader(TimePoint, WindPositionMode)} + * See {@link TrackedLegOfCompetitor#getWindwardDistanceToOverallLeader(TimePoint, WindPositionMode, RankingInfo)} */ Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode); /** - * Same as {@link #getWindwardDistanceToOverallLeader(Competitor, TimePoint, WindPositionMode)}, only with an additional - * cache to speed up wind and leg type and leg bearing calculations in case of multiple similar look-ups for the same - * time point. + * Same as {@link #getWindwardDistanceToOverallLeader(Competitor, TimePoint, WindPositionMode)}, only with an + * additional cache to speed up wind and leg type and leg bearing calculations in case of multiple similar look-ups + * for the same time point. + * + * @param rankingInfo + * materialized ranking information that is expensive to calculate, avoiding redundant calculations */ - Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode, WindLegTypeAndLegBearingCache cache); + Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache); /** * Calls {@link #getWindWithConfidence(Position, TimePoint, Iterable)} and excludes those wind sources listed in @@ -818,13 +822,4 @@ public interface TrackedRace extends Serializable { Duration getEstimatedTimeToComplete(TimePoint timepoint) throws NotEnoughDataHasBeenAddedException, NoWindException; void setPolarDataService(PolarDataService polarDataService); - - /** - * With a handicap system in place, computes the windward distance to the race's overall leader based on the correction factors - * introduced by the handicap's ranking and scoring system. For one-design classes, this method returns the same result as - * {@link #getWindwardDistanceToOverallLeader(Competitor, TimePoint, WindPositionMode)}. - */ - Distance getCorrectedWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, - WindPositionMode windPositionMode) throws NoWindException; - } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedLegOfCompetitorImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedLegOfCompetitorImpl.java index 59617c611ef..65b7b54f330 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedLegOfCompetitorImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedLegOfCompetitorImpl.java @@ -407,12 +407,12 @@ public class TrackedLegOfCompetitorImpl implements TrackedLegOfCompetitor { } @Override - public Distance getWindwardDistanceToOverallLeader(TimePoint timePoint, WindPositionMode windPositionMode) { - return getWindwardDistanceToOverallLeader(timePoint, windPositionMode, new LeaderboardDTOCalculationReuseCache(timePoint)); + public Distance getWindwardDistanceToOverallLeader(TimePoint timePoint, WindPositionMode windPositionMode, final RankingInfo rankingInfo) { + return getWindwardDistanceToOverallLeader(timePoint, windPositionMode, rankingInfo, new LeaderboardDTOCalculationReuseCache(timePoint)); } @Override - public Distance getWindwardDistanceToOverallLeader(TimePoint timePoint, WindPositionMode windPositionMode, WindLegTypeAndLegBearingCache cache) { + public Distance getWindwardDistanceToOverallLeader(TimePoint timePoint, WindPositionMode windPositionMode, final RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) { // FIXME bug 607 it seems the following fetches the leader of this leg, not the overall leader; validate!!! Use getTrackedRace().getRanks() instead Competitor leader = getTrackedRace().getOverallLeader(timePoint, cache); TrackedLegOfCompetitor leaderLeg = getTrackedRace().getCurrentLeg(leader, timePoint); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java index 1073903a965..b29da580d62 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java @@ -107,6 +107,7 @@ import com.sap.sailing.domain.racelog.tracking.GPSFixStore; import com.sap.sailing.domain.racelogtracking.DeviceMapping; import com.sap.sailing.domain.ranking.OneDesignRankingMetric; import com.sap.sailing.domain.ranking.RankingMetric; +import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo; import com.sap.sailing.domain.ranking.RankingMetricConstructor; import com.sap.sailing.domain.tracking.DynamicGPSFixTrack; import com.sap.sailing.domain.tracking.GPSFixTrack; @@ -2871,13 +2872,15 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl @Override public Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode) { final TrackedLegOfCompetitor trackedLeg = getTrackedLeg(competitor, timePoint); - return trackedLeg == null ? null : trackedLeg.getWindwardDistanceToOverallLeader(timePoint, windPositionMode); + return trackedLeg == null ? null : trackedLeg.getWindwardDistanceToOverallLeader(timePoint, windPositionMode, + getRankingMetric().getRankingInfo(timePoint)); } @Override - public Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode, WindLegTypeAndLegBearingCache cache) { + public Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, + WindPositionMode windPositionMode, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) { final TrackedLegOfCompetitor trackedLeg = getTrackedLeg(competitor, timePoint); - return trackedLeg == null ? null : trackedLeg.getWindwardDistanceToOverallLeader(timePoint, windPositionMode, cache); + return trackedLeg == null ? null : trackedLeg.getWindwardDistanceToOverallLeader(timePoint, windPositionMode, rankingInfo, cache); } @Override @@ -3584,11 +3587,4 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl public void setPolarDataService(PolarDataService polarDataService) { this.polarDataService = polarDataService; } - - @Override - public Distance getCorrectedWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, - WindPositionMode windPositionMode) throws NoWindException { - // TODO bug 1018, see comment #17: implement the calculation for corrected windward distance - return getWindwardDistanceToOverallLeader(competitor, timePoint, windPositionMode); - } } diff --git a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java index 4636a629292..28cf967bdf7 100755 --- a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java +++ b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java @@ -37,6 +37,7 @@ import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException; import com.sap.sailing.domain.polars.PolarDataService; import com.sap.sailing.domain.racelog.tracking.GPSFixStore; import com.sap.sailing.domain.ranking.RankingMetric; +import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo; import com.sap.sailing.domain.tracking.CourseDesignChangedListener; import com.sap.sailing.domain.tracking.DynamicGPSFixTrack; import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet; @@ -736,12 +737,6 @@ public class MockedTrackedRace implements DynamicTrackedRace { public void setPolarDataService(PolarDataService polarDataService) { } - @Override - public Distance getCorrectedWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, - WindPositionMode windPositionMode) { - return null; - } - @Override public Duration getEstimatedTimeToComplete(TimePoint timepoint) throws NotEnoughDataHasBeenAddedException, NoWindException { @@ -750,7 +745,7 @@ public class MockedTrackedRace implements DynamicTrackedRace { @Override public Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, - WindPositionMode windPositionMode, WindLegTypeAndLegBearingCache cache) { + WindPositionMode windPositionMode, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) { return null; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/DetailTypeFormatter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/DetailTypeFormatter.java index d62f2f12d55..28d96586320 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/DetailTypeFormatter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/DetailTypeFormatter.java @@ -45,7 +45,7 @@ public class DetailTypeFormatter { case GAP_TO_LEADER_IN_SECONDS: return stringMessages.gapToLeaderInSeconds(); case CORRECTED_TIME_TRAVELED: - return stringMessages.correctedTimeTraveled(); + return stringMessages.calculatedTimeTraveled(); case GAP_CHANGE_SINCE_LEG_START_IN_SECONDS: return stringMessages.gapChangeSinceLegStartInSeconds(); case SIDE_TO_WHICH_MARK_AT_LEG_START_WAS_ROUNDED: @@ -129,9 +129,9 @@ public class DetailTypeFormatter { case RACE_TIME_TRAVELED: return stringMessages.time(); case RACE_CORRECTED_TIME_TRAVELED: - return stringMessages.correctedTimeTraveled(); + return stringMessages.calculatedTimeTraveled(); case RACE_CORRECTED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD: - return stringMessages.raceCorrectedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSeconds(); + return stringMessages.raceCalculatedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSeconds(); case RACE_TIME_TRAVELED_DOWNWIND: return stringMessages.timeDownwind(); case RACE_TIME_TRAVELED_REACHING: @@ -289,7 +289,7 @@ public class DetailTypeFormatter { case GAP_TO_LEADER_IN_SECONDS: return stringMessages.gapToLeaderInSecondsTooltip(); case CORRECTED_TIME_TRAVELED: - return stringMessages.correctedTimeTraveledTooltip(); + return stringMessages.calculatedTimeTraveledTooltip(); case JIBE: return stringMessages.jibeTooltip(); case MAXIMUM_SPEED_OVER_GROUND_IN_KNOTS: @@ -327,9 +327,9 @@ public class DetailTypeFormatter { case RACE_GAP_TO_LEADER_IN_SECONDS: return stringMessages.gapToLeaderInSecondsTooltip(); case RACE_CORRECTED_TIME_TRAVELED: - return stringMessages.correctedTimeTraveledTooltip(); + return stringMessages.calculatedTimeTraveledTooltip(); case RACE_CORRECTED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD: - return stringMessages.raceCorrectedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSecondsTooltip(); + return stringMessages.raceCalculatedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSecondsTooltip(); case RACE_RANK: return stringMessages.rankTooltip(); case REGATTA_RANK: diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java index 8c33c821644..b2eeaf09e4f 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java @@ -1288,10 +1288,10 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c String timeOnTimeAndDistanceRankingMetricDescription(); String timeOnTimeFactor(); String timeOnDistanceAllowanceInSecondsPerNauticalMile(); - String correctedTimeTraveled(); - String correctedTimeTraveledTooltip(); + String calculatedTimeTraveled(); + String calculatedTimeTraveledTooltip(); String timeOnTimeFactorTooltip(); String timeOnDistanceAllowanceInSecondsPerNauticalMileTooltip(); - String raceCorrectedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSeconds(); - String raceCorrectedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSecondsTooltip(); + String raceCalculatedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSeconds(); + String raceCalculatedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSecondsTooltip(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index a347dbddb75..c03a329f4d5 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -86,7 +86,7 @@ currentSpeedOverGroundInKnotsTooltip=The current speed over ground. estimatedTimeToNextWaypointInSeconds=ETA estimatedTimeToNextWaypointInSecondsTooltip=The estimated time that the competitor needs to reach the next waypoint, based on the competitor''s current velocity made good, considering the true wind direction. gapToLeaderInSeconds=Gap to leader -gapToLeaderInSecondsTooltip=Estimates the (corrected) arrival time at the current position of the boat that is farthest ahead,\nbased on average VMG for the current leg and with performance equal to that of the race leader for subsequent legs.\nThe gap tells how much earlier the competitor would have had to be where she currently is\nin order to rank equal to the race leader at the projected arrival at the current position of the boat farthest ahead. +gapToLeaderInSecondsTooltip=Estimates the (calculated) arrival time at the current position of the boat that is farthest ahead,\nbased on average VMG for the current leg and with performance equal to that of the race leader for subsequent legs.\nThe gap tells how much earlier the competitor would have had to be where she currently is\nin order to rank equal to the race leader at the projected arrival at the current position of the boat farthest ahead. velocityMadeGoodInKnots=VMG velocityMadeGoodInKnotsTooltip=The velocity made good, which is the windward/leeward speed for upwind/downwind legs, respectively, or the along-track speed for reaching legs. windwardDistanceToGoInMeters=Windward distance to go @@ -1253,12 +1253,12 @@ orcPerformanceCurveRankingMetric=ORC Performance Curve timeOnTimeAndDistanceRankingMetric=Time-on-Time/Time-on-Distance oneDesignRankingMetricDescription=One-Design: First across the line wins;\nin-race ranks based on windward positions (upwind/downwind) or along-course position (reaching) orcPerformanceCurveRankingMetricDescription=ORC Performance Curve: Sophisticated handicapping scheme that awards time allowances based on a VPP/polar assuming pre-defined legs'' angles to the wind;\nbased on these allowances, an "implied wind" is calculated which is the basis for ranking.\nImplied wind can be calculated at any time in the race and is therefore the basis for in-race ranking. -timeOnTimeAndDistanceRankingMetricDescription=Time-on-Time / Time-on-Distance: Final ranking by corrected time;\ntime is corrected by optionally applying a factor to the actual time (defaulting to 1.0)\nand subtracting an allowance in seconds per nautical mile,\napplied to the course length.\nIn-race ranks based on expected arrival at fastest boat's current position\nassuming current leg's average VMG/VMC. +timeOnTimeAndDistanceRankingMetricDescription=Time-on-Time / Time-on-Distance: Final ranking by calculated time;\ntime is calculated by optionally applying a factor to the actual time (defaulting to 1.0)\nand subtracting an allowance in seconds per nautical mile,\napplied to the course length.\nIn-race ranks based on expected arrival at fastest boat's current position\nassuming current leg's average VMG/VMC. timeOnTimeFactor=ToT Factor timeOnDistanceAllowanceInSecondsPerNauticalMile=ToD Allowance timeOnTimeFactorTooltip=Time-on-Time factor; actual time is multiplied with this factor in calculated time formula -timeOnDistanceAllowanceInSecondsPerNauticalMileTooltip=Time-on-Distance allowance in seconds per nautical mile;\ndistance sailed is multiplied with this allowance, and the resulting seconds are subtracted from the actual time sailed\n(optionally corrected by the time-on-time factor) in the calculated time formula -correctedTimeTraveled=Corrected Time -correctedTimeTraveledTooltip=Corrected time according to competitor''s handicap\nbased on time since start of race and (windward) distance traveled -raceCorrectedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSeconds=Corr.Time@Fastest -raceCorrectedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSecondsTooltip=Corrected time at estimated arrival at the competitor that is currently farthest ahead in the race;\nestimation based on average VMG in current leg and equal (corrected) performance to fastest boat in all subsequent legs +timeOnDistanceAllowanceInSecondsPerNauticalMileTooltip=Time-on-Distance allowance in seconds per nautical mile;\ndistance sailed is multiplied with this allowance, and the resulting seconds are subtracted from the actual time sailed\n(optionally calculated by applying the time-on-time factor) in the calculated time formula +calculatedTimeTraveled=Calculated Time +calculatedTimeTraveledTooltip=Calculated time according to competitor''s handicap\nbased on time since start of race and (windward) distance traveled +raceCalculatedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSeconds=Calc.Time @ Fastest +raceCalculatedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSecondsTooltip=Calculated time at estimated arrival at the competitor that is currently farthest ahead in the race;\nestimation based on average VMG in current leg and equal (calculated) performance to fastest boat in all subsequent legs diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_cn.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_cn.properties index 0981a062730..4d160534af8 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_cn.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_cn.properties @@ -1079,7 +1079,7 @@ clickAndDragToZoomIn=Click and drag in the plot area to zoom in runAutomaticallyTooltip=Run the query automatically, after you changed e.g. the statistic or the grouping. essThreeDisplayed=Three minutes till start actionEdit=Edit -gapToLeaderInSecondsTooltip=Estimates the (corrected) arrival time at the current position of the boat that is farthest ahead,\nbased on average VMG for the current leg and with performance equal to that of the race leader for subsequent legs.\nThe gap tells how much earlier the competitor would have had to be where she currently is\nin order to rank equal to the race leader at the projected arrival at the current position of the boat farthest ahead. +gapToLeaderInSecondsTooltip=Estimates the (calculated) arrival time at the current position of the boat that is farthest ahead,\nbased on average VMG for the current leg and with performance equal to that of the race leader for subsequent legs.\nThe gap tells how much earlier the competitor would have had to be where she currently is\nin order to rank equal to the race leader at the projected arrival at the current position of the boat farthest ahead. showAllCompetitors=显示所有参赛队 leaderboardNotContainedInLeaderboardGroup=The leaderboard {0} is not contained in leaderboard group {1}. playSpeed=游戏速度 @@ -1244,12 +1244,12 @@ orcPerformanceCurveRankingMetric=ORC Performance Curve timeOnTimeAndDistanceRankingMetric=Time-on-Time/Time-on-Distance oneDesignRankingMetricDescription=One-Design: First across the line wins;\nin-race ranks based on windward positions (upwind/downwind) or along-course position (reaching) orcPerformanceCurveRankingMetricDescription=ORC Performance Curve: Sophisticated handicapping scheme that awards time allowances based on a VPP/polar assuming pre-defined legs'' angles to the wind;\nbased on these allowances, an "implied wind" is calculated which is the basis for ranking.\nImplied wind can be calculated at any time in the race and is therefore the basis for in-race ranking. -timeOnTimeAndDistanceRankingMetricDescription=Time-on-Time / Time-on-Distance: Final ranking by corrected time;\ntime is corrected by optionally applying a factor to the actual time (defaulting to 1.0)\nand subtracting an allowance in seconds per nautical mile,\napplied to the course length.\nIn-race ranks based on expected arrival at fastest boat's current position\nassuming current leg's average VMG/VMC. +timeOnTimeAndDistanceRankingMetricDescription=Time-on-Time / Time-on-Distance: Final ranking by calculated time;\ntime is calculated by optionally applying a factor to the actual time (defaulting to 1.0)\nand subtracting an allowance in seconds per nautical mile,\napplied to the course length.\nIn-race ranks based on expected arrival at fastest boat's current position\nassuming current leg's average VMG/VMC. timeOnTimeFactor=Time-on-time handicap factor timeOnDistanceAllowanceInSecondsPerNauticalMile=Time-on-distance handicap allowance in seconds per nautical mile timeOnTimeFactorTooltip=Time-on-Time factor; actual time is multiplied with this factor in calculated time formula -timeOnDistanceAllowanceInSecondsPerNauticalMileTooltip=Time-on-Distance allowance in seconds per nautical mile;\ndistance sailed is multiplied with this allowance, and the resulting seconds are subtracted from the actual time sailed\n(optionally corrected by the time-on-time factor) in the calculated time formula -correctedTimeTraveled=Corrected Time -correctedTimeTraveledTooltip=Corrected time according to competitor''s handicap\nbased on time since start of race and (windward) distance traveled -raceCorrectedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSeconds=Corr.Time@Fastest -raceCorrectedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSecondsTooltip=Corrected time at estimated arrival at the competitor that is currently farthest ahead in the race;\nestimation based on average VMG in current leg and equal (corrected) performance to fastest boat in all subsequent legs +timeOnDistanceAllowanceInSecondsPerNauticalMileTooltip=Time-on-Distance allowance in seconds per nautical mile;\ndistance sailed is multiplied with this allowance, and the resulting seconds are subtracted from the actual time sailed\n(optionally calculated by applying the time-on-time factor) in the calculated time formula +calculatedTimeTraveled=Calculated Time +calculatedTimeTraveledTooltip=Calculated time according to competitor''s handicap\nbased on time since start of race and (windward) distance traveled +raceCalculatedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSeconds=Calc.Time @ Fastest +raceCalculatedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSecondsTooltip=Calculated time at estimated arrival at the competitor that is currently farthest ahead in the race;\nestimation based on average VMG in current leg and equal (calculated) performance to fastest boat in all subsequent legs diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties index 35e98f5df5b..5beec811b2d 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties @@ -86,7 +86,7 @@ currentSpeedOverGroundInKnotsTooltip=Die aktuelle Fahrt über Grund estimatedTimeToNextWaypointInSeconds=ETA estimatedTimeToNextWaypointInSecondsTooltip=Die vorraussichtliche Zeit, die der Teilnehmer benötigen wird,\num den nächsten Wegpunkt zu erreichen gapToLeaderInSeconds=Abstand zum Führenden -gapToLeaderInSecondsTooltip=Schätzt die (korrigierte) Ankunftszeit an der jetzigen Position des bisher nach gesegelter Distanz in Führung liegenden Teilnehmers\nbasierend auf dem VMG des aktuellen Bahnschenkels, danach gleichauf mit dem Führenden.\nDer Zeitabstand besagt dann, wieviel früher der Teilnehmer an seiner jetzigen Position hätte sein müssen, um gemäß dieser Vorhersage gleichauf mit dem Führenden nach korrigierter Zeit zu liegen. +gapToLeaderInSecondsTooltip=Schätzt die (berechnete) Ankunftszeit an der jetzigen Position des bisher nach gesegelter Distanz in Führung liegenden Teilnehmers\nbasierend auf dem VMG des aktuellen Bahnschenkels, danach gleichauf mit dem Führenden.\nDer Zeitabstand besagt dann, wieviel früher der Teilnehmer an seiner jetzigen Position hätte sein müssen, um gemäß dieser Vorhersage gleichauf mit dem Führenden nach korrigierter Zeit zu liegen. velocityMadeGoodInKnots=VMG velocityMadeGoodInKnotsTooltip=Die effektive Geschwindigkeit zum Ziel; auf der Kreuz die windwärtige Geschwindigkeit; auf der Vorwindstrecke die leewärtige Geschwindigkeit windwardDistanceToGoInMeters=Abstand in Windrichtung zur nächsten Bahnmarke @@ -512,7 +512,7 @@ finished=beendet upcoming=demnächst inProgress=aktiv passedTo=an {0} gerundet -gapChangeSinceLegStartInSeconds=Gap Änderung +gapChangeSinceLegStartInSeconds=Änderung Abstand zum Führenden gapChangeSinceLegStartInSecondsTooltip=Die Änderung des Abstands zum Führenden seit dem letzten Schenkelstart.\nEine negative Zahl bedeutet,\ndass sich der Abstand verringert hat; eine positive Zahl bedeutet, dass er sich vergrößert hat. sideToWhichMarkAtLegStartWasRounded=Tonne gerundet an sideToWhichMarkAtLegStartWasRoundedTooltip=Seite, an der die Bahnmarke am Schenkelstart gerundet wurde @@ -1248,7 +1248,7 @@ timeOnTimeFactor=ToT Faktor timeOnDistanceAllowanceInSecondsPerNauticalMile=ToD Zuteilung timeOnTimeFactorTooltip=Zeit-auf-Zeit Faktor; tatsächlich gesegelte Zeit wird für die berechnete Zeit mit diesem Faktor multipliziert timeOnDistanceAllowanceInSecondsPerNauticalMileTooltip=Zeit-auf-Distanz Zuteilung in Sekunden pro Seemeile;\ndie gesegelte Distanz wird mit diesem Wert multipliziert, und die sich ergebende Zeit wird von der (ggf. per ToT-Faktor angepassten) Zeit subtrahiert -correctedTimeTraveled=Berechnete Zeit -correctedTimeTraveledTooltip=Berechnete Zeit anhand Teilnehmer-Handicap\nauf der Grundlage von Zeit seit Rennstart und zurückgelegter Distanz -raceCorrectedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSeconds=Ber.Zeit@Führender -raceCorrectedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSecondsTooltip=Berechnete Zeit bei erwarteter Ankunft am derzeit absolut in Führung liegenden Teilnehmers;\nSchätzung basierend auf durchschnittlichem VMG im aktuellen Bahnschenkel und gleicher verrechneter Geschwindigket wie der absolut in Führung liegende Teilnehmer\nfür alle nachfolgenden Bahnschenkel +calculatedTimeTraveled=Berechnete Zeit +calculatedTimeTraveledTooltip=Berechnete Zeit anhand Teilnehmer-Handicap\nauf der Grundlage von Zeit seit Rennstart und zurückgelegter Distanz +raceCalcluatedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSeconds=Ber.Zeit@Führender +raceCalculatedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSecondsTooltip=Berechnete Zeit bei erwarteter Ankunft am derzeit absolut in Führung liegenden Teilnehmers;\nSchätzung basierend auf durchschnittlichem VMG im aktuellen Bahnschenkel und gleicher verrechneter Geschwindigket wie der absolut in Führung liegende Teilnehmer\nfür alle nachfolgenden Bahnschenkel diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties index 98420b7ecd8..bd92df88f18 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties @@ -86,7 +86,7 @@ currentSpeedOverGroundInKnotsTooltip=Текущая скорость относ estimatedTimeToNextWaypointInSeconds=Расчетное время прибытия (ETA). estimatedTimeToNextWaypointInSecondsTooltip= Расчетное время, необходимое участнику для прибытия в следующую промежуточную точку маршрута, исходя из скорости лавирования участника и с учетом истинного направление ветра. gapToLeaderInSeconds=Отставание от лидера -gapToLeaderInSecondsTooltip=Estimates the (corrected) arrival time at the current position of the boat that is farthest ahead,\nbased on average VMG for the current leg and with performance equal to that of the race leader for subsequent legs.\nThe gap tells how much earlier the competitor would have had to be where she currently is\nin order to rank equal to the race leader at the projected arrival at the current position of the boat farthest ahead. +gapToLeaderInSecondsTooltip=Estimates the (calculated) arrival time at the current position of the boat that is farthest ahead,\nbased on average VMG for the current leg and with performance equal to that of the race leader for subsequent legs.\nThe gap tells how much earlier the competitor would have had to be where she currently is\nin order to rank equal to the race leader at the projected arrival at the current position of the boat farthest ahead. velocityMadeGoodInKnots=Скорость лавирования (VMG) velocityMadeGoodInKnotsTooltip=Скорость лавирования, представляет собой скорость продвижения на ветер/ по ветру для этапов движения против ветра/ по ветру соответственно, или скорость в направлении движения при лавировании по ветру windwardDistanceToGoInMeters=Расстояние, которое необходимо пройти на ветер @@ -1192,12 +1192,12 @@ orcPerformanceCurveRankingMetric=ORC Performance Curve timeOnTimeAndDistanceRankingMetric=Time-on-Time/Time-on-Distance oneDesignRankingMetricDescription=One-Design: First across the line wins;\nin-race ranks based on windward positions (upwind/downwind) or along-course position (reaching) orcPerformanceCurveRankingMetricDescription=ORC Performance Curve: Sophisticated handicapping scheme that awards time allowances based on a VPP/polar assuming pre-defined legs'' angles to the wind;\nbased on these allowances, an "implied wind" is calculated which is the basis for ranking.\nImplied wind can be calculated at any time in the race and is therefore the basis for in-race ranking. -timeOnTimeAndDistanceRankingMetricDescription=Time-on-Time / Time-on-Distance: Final ranking by corrected time;\ntime is corrected by optionally applying a factor to the actual time (defaulting to 1.0)\nand subtracting an allowance in seconds per nautical mile,\napplied to the course length.\nIn-race ranks based on expected arrival at fastest boat's current position\nassuming current leg's average VMG/VMC. +timeOnTimeAndDistanceRankingMetricDescription=Time-on-Time / Time-on-Distance: Final ranking by calculated time;\ntime is calculated by optionally applying a factor to the actual time (defaulting to 1.0)\nand subtracting an allowance in seconds per nautical mile,\napplied to the course length.\nIn-race ranks based on expected arrival at fastest boat's current position\nassuming current leg's average VMG/VMC. timeOnTimeFactor=Time-on-time handicap factor timeOnDistanceAllowanceInSecondsPerNauticalMile=Time-on-distance handicap allowance in seconds per nautical mile timeOnTimeFactorTooltip=Time-on-Time factor; actual time is multiplied with this factor in calculated time formula -timeOnDistanceAllowanceInSecondsPerNauticalMileTooltip=Time-on-Distance allowance in seconds per nautical mile;\ndistance sailed is multiplied with this allowance, and the resulting seconds are subtracted from the actual time sailed\n(optionally corrected by the time-on-time factor) in the calculated time formula -correctedTimeTraveled=Corrected Time -correctedTimeTraveledTooltip=Corrected time according to competitor''s handicap\nbased on time since start of race and (windward) distance traveled -raceCorrectedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSeconds=Corr.Time@Fastest -raceCorrectedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSecondsTooltip=Corrected time at estimated arrival at the competitor that is currently farthest ahead in the race;\nestimation based on average VMG in current leg and equal (corrected) performance to fastest boat in all subsequent legs +timeOnDistanceAllowanceInSecondsPerNauticalMileTooltip=Time-on-Distance allowance in seconds per nautical mile;\ndistance sailed is multiplied with this allowance, and the resulting seconds are subtracted from the actual time sailed\n(optionally calculated by applying the time-on-time factor) in the calculated time formula +calculatedTimeTraveled=Calculated Time +calculatedTimeTraveledTooltip=Calculated time according to competitor''s handicap\nbased on time since start of race and (windward) distance traveled +raceCalculatedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSeconds=Calc.Time @ Fastest +raceCalculatedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSecondsTooltip=Calculated time at estimated arrival at the competitor that is currently farthest ahead in the race;\nestimation based on average VMG in current leg and equal (calculated) performance to fastest boat in all subsequent legs 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 33fa72e2e33..c158f4bdbff 100755 --- 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 @@ -238,6 +238,7 @@ import com.sap.sailing.domain.racelogtracking.DeviceMapping; import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapter; import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapterFactory; import com.sap.sailing.domain.racelogtracking.impl.DeviceMappingImpl; +import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo; import com.sap.sailing.domain.ranking.RankingMetricsFactory; import com.sap.sailing.domain.regattalike.HasRegattaLike; import com.sap.sailing.domain.regattalike.LeaderboardThatHasRegattaLike; @@ -2720,13 +2721,15 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S break; case GAP_TO_LEADER_IN_SECONDS: if (trackedLeg != null) { - final Duration gapToLeaderInOwnTime = trackedLeg.getTrackedLeg().getTrackedRace().getRankingMetric().getGapToLeaderInOwnTime(competitor, timePoint, cache); + final RankingInfo rankingInfo = trackedRace.getRankingMetric().getRankingInfo(timePoint); + final Duration gapToLeaderInOwnTime = trackedLeg.getTrackedLeg().getTrackedRace().getRankingMetric().getGapToLeaderInOwnTime(rankingInfo, competitor, cache); result = gapToLeaderInOwnTime == null ? null : gapToLeaderInOwnTime.asSeconds(); } break; case WINDWARD_DISTANCE_TO_OVERALL_LEADER: if (trackedLeg != null) { - Distance distanceToLeader = trackedLeg.getWindwardDistanceToOverallLeader(timePoint, WindPositionMode.LEG_MIDDLE); + final RankingInfo rankingInfo = trackedRace.getRankingMetric().getRankingInfo(timePoint); + Distance distanceToLeader = trackedLeg.getWindwardDistanceToOverallLeader(timePoint, WindPositionMode.LEG_MIDDLE, rankingInfo); result = (distanceToLeader == null) ? null : distanceToLeader.getMeters(); } break; diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java index dd4905cfc63..1ca9d529ce0 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java @@ -997,7 +997,7 @@ public class RegattasResource extends AbstractSailingServerResource { } Distance windwardDistanceToOverallLeader = currentLegOfCompetitor - .getWindwardDistanceToOverallLeader(timePoint, WindPositionMode.LEG_MIDDLE); + .getWindwardDistanceToOverallLeader(timePoint, WindPositionMode.LEG_MIDDLE, rankingInfo); if (windwardDistanceToOverallLeader != null) { jsonCompetitorInLeg.put("gapToLeader-m", roundDouble(windwardDistanceToOverallLeader.getMeters(), 2)); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java index 3635e75c91d..37417c80a82 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java @@ -34,6 +34,7 @@ import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException; import com.sap.sailing.domain.polars.PolarDataService; import com.sap.sailing.domain.racelog.tracking.GPSFixStore; import com.sap.sailing.domain.ranking.RankingMetric; +import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo; import com.sap.sailing.domain.tracking.CourseDesignChangedListener; import com.sap.sailing.domain.tracking.GPSFixTrack; import com.sap.sailing.domain.tracking.LineDetails; @@ -589,12 +590,6 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials { public void setPolarDataService(PolarDataService polarDataService) { } - @Override - public Distance getCorrectedWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, - WindPositionMode windPositionMode) { - return null; - } - @Override public Duration getEstimatedTimeToComplete(TimePoint timepoint) throws NotEnoughDataHasBeenAddedException, NoWindException { @@ -603,7 +598,7 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials { @Override public Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, - WindPositionMode windPositionMode, WindLegTypeAndLegBearingCache cache) { + WindPositionMode windPositionMode, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) { return null; } diff --git a/java/com.sap.sailing.xmlexport/src/com/sap/sailing/xmlexport/LeaderboardData.java b/java/com.sap.sailing.xmlexport/src/com/sap/sailing/xmlexport/LeaderboardData.java index 8fdc598c6f4..7adcb3094ec 100644 --- a/java/com.sap.sailing.xmlexport/src/com/sap/sailing/xmlexport/LeaderboardData.java +++ b/java/com.sap.sailing.xmlexport/src/com/sap/sailing/xmlexport/LeaderboardData.java @@ -655,7 +655,7 @@ public class LeaderboardData extends ExportAction { } addNamedElementWithValue(competitorLegDataElement, "time_spend_in_this_leg_as_millis", timeSpentInThisLeg != null ? timeSpentInThisLeg.asMillis() : new MillisecondsDurationImpl(0).asMillis()); addNamedElementWithValue(competitorLegDataElement, "gap_to_leader_at_finish_in_seconds", competitorLeg.getGapToLeader(legFinishTime, rankingMetricAtLegFinishTime, WindPositionMode.LEG_MIDDLE).asSeconds()); - Distance windwardDistanceToOverallLeader = competitorLeg.getWindwardDistanceToOverallLeader(legFinishTime, WindPositionMode.LEG_MIDDLE); + Distance windwardDistanceToOverallLeader = competitorLeg.getWindwardDistanceToOverallLeader(legFinishTime, WindPositionMode.LEG_MIDDLE, rankingMetricAtLegFinishTime); addNamedElementWithValue(competitorLegDataElement, "windward_distance_to_overall_leader_that_has_finished_this_leg_in_meters", windwardDistanceToOverallLeader != null ? windwardDistanceToOverallLeader.getMeters() : 0); addNamedElementWithValue(competitorLegDataElement, "distance_traveled_in_meters", competitorLeg.getDistanceTraveled(legFinishTime).getMeters()); addNamedElementWithValue(competitorLegDataElement, "average_speed_over_ground_in_knots", competitorLeg.getAverageSpeedOverGround(legFinishTime).getKnots()); From 9c5bf2c3b10c520ea96ec59e46038bffa9603c33 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 28 May 2015 17:10:04 +0200 Subject: [PATCH 45/72] switched from "windward distance to leader" to "windward distance to competitor farthest ahead" --- .../sap/sailing/domain/common/DetailType.java | 4 ++-- .../common/dto/LeaderboardEntryDTO.java | 10 ++++----- .../sailing/domain/test/ReachingLegTest.java | 22 +++++++++---------- .../domain/test/mock/MockedTrackedRace.java | 4 ++-- ...ockedTrackedRaceWithStartTimeAndRanks.java | 4 ++-- .../impl/AbstractSimpleLeaderboardImpl.java | 20 ++++++++--------- .../tracking/TrackedLegOfCompetitor.java | 6 ++--- .../sailing/domain/tracking/TrackedRace.java | 11 +++++----- .../impl/TrackedLegOfCompetitorImpl.java | 12 +++++----- .../domain/tracking/impl/TrackedRaceImpl.java | 8 +++---- .../gwt/ui/test/MockedTrackedRace.java | 4 ++-- .../gwt/ui/client/DetailTypeFormatter.java | 16 +++++++------- .../sailing/gwt/ui/client/StringMessages.java | 2 +- .../gwt/ui/client/StringMessages.properties | 4 ++-- .../ui/client/StringMessages_cn.properties | 4 ++-- .../ui/client/StringMessages_de.properties | 4 ++-- .../ui/client/StringMessages_ru.properties | 4 ++-- .../charts/AbstractCompetitorRaceChart.java | 2 +- .../charts/MultiCompetitorRaceChart.java | 2 +- ...iCompetitorRaceChartSettingsComponent.java | 2 +- .../gwt/ui/leaderboard/LeaderboardPanel.java | 15 +++++++------ .../LeaderboardSettingsFactory.java | 2 +- .../gwt/ui/server/SailingServiceImpl.java | 4 ++-- .../gateway/jaxrs/api/RegattasResource.java | 8 +++---- .../SailingServer (No Proxy).launch | 2 +- .../server/masterdata/DummyTrackedRace.java | 4 ++-- .../sailing/xmlexport/LeaderboardData.java | 5 +++-- 27 files changed, 94 insertions(+), 91 deletions(-) diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/DetailType.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/DetailType.java index c357e8dbdf1..c18af5db66b 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/DetailType.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/DetailType.java @@ -24,9 +24,9 @@ public enum DetailType implements Serializable { AVERAGE_ABSOLUTE_CROSS_TRACK_ERROR_IN_METERS(0, ASCENDING), AVERAGE_SIGNED_CROSS_TRACK_ERROR_IN_METERS(0, ASCENDING), RACE_DISTANCE_TRAVELED(0, ASCENDING), RACE_DISTANCE_TRAVELED_INCLUDING_GATE_START(0, ASCENDING), RACE_AVERAGE_SPEED_OVER_GROUND_IN_KNOTS(2, DESCENDING), RACE_GAP_TO_LEADER_IN_SECONDS(0, ASCENDING), - RACE_DISTANCE_TO_LEADER_IN_METERS(0, ASCENDING), RACE_AVERAGE_ABSOLUTE_CROSS_TRACK_ERROR_IN_METERS(0, ASCENDING), + RACE_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD_IN_METERS(0, ASCENDING), RACE_AVERAGE_ABSOLUTE_CROSS_TRACK_ERROR_IN_METERS(0, ASCENDING), RACE_AVERAGE_SIGNED_CROSS_TRACK_ERROR_IN_METERS(0, ASCENDING), - WINDWARD_DISTANCE_TO_OVERALL_LEADER(0, ASCENDING), START_TACK(0, ASCENDING), DISTANCE_TO_START_AT_RACE_START(1, ASCENDING), + WINDWARD_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD(0, ASCENDING), START_TACK(0, ASCENDING), DISTANCE_TO_START_AT_RACE_START(1, ASCENDING), TIME_BETWEEN_RACE_START_AND_COMPETITOR_START(1, ASCENDING), SPEED_OVER_GROUND_AT_RACE_START(1, DESCENDING), SPEED_OVER_GROUND_WHEN_PASSING_START(1, DESCENDING), DISTANCE_TO_STARBOARD_END_OF_STARTLINE_WHEN_PASSING_START_IN_METERS(1, ASCENDING), diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardEntryDTO.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardEntryDTO.java index 1e846807219..daf3b667df6 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardEntryDTO.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardEntryDTO.java @@ -42,7 +42,7 @@ public class LeaderboardEntryDTO implements Serializable { public boolean discarded; - public Double windwardDistanceToOverallLeaderInMeters; + public Double windwardDistanceToCompetitorFarthestAheadInMeters; public Double averageAbsoluteCrossTrackErrorInMeters; @@ -179,7 +179,7 @@ public class LeaderboardEntryDTO implements Serializable { result = prime * result + ((totalPoints == null) ? 0 : totalPoints.hashCode()); result = prime * result - + ((windwardDistanceToOverallLeaderInMeters == null) ? 0 : windwardDistanceToOverallLeaderInMeters + + ((windwardDistanceToCompetitorFarthestAheadInMeters == null) ? 0 : windwardDistanceToCompetitorFarthestAheadInMeters .hashCode()); return result; } @@ -297,10 +297,10 @@ public class LeaderboardEntryDTO implements Serializable { return false; } else if (!totalPoints.equals(other.totalPoints)) return false; - if (windwardDistanceToOverallLeaderInMeters == null) { - if (other.windwardDistanceToOverallLeaderInMeters != null) + if (windwardDistanceToCompetitorFarthestAheadInMeters == null) { + if (other.windwardDistanceToCompetitorFarthestAheadInMeters != null) return false; - } else if (!windwardDistanceToOverallLeaderInMeters.equals(other.windwardDistanceToOverallLeaderInMeters)) + } else if (!windwardDistanceToCompetitorFarthestAheadInMeters.equals(other.windwardDistanceToCompetitorFarthestAheadInMeters)) return false; return true; } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReachingLegTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReachingLegTest.java index 84245a09f93..483614af2a2 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReachingLegTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReachingLegTest.java @@ -194,8 +194,8 @@ public class ReachingLegTest extends TrackBasedTest { assertEquals(0., getTrackedRace().getTrack(plattner).getEstimatedPosition(timePointInReaching, /* extrapolate */false) .getDistance(windwardMarkPos).getMeters(), 0.00001); - Distance hungersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(hunger, timePointInReaching, WindPositionMode.LEG_MIDDLE); - Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(plattner, timePointInReaching, WindPositionMode.LEG_MIDDLE); + Distance hungersDistanceToLeader = getTrackedRace().getWindwardDistanceToCompetitorFarthestAhead(hunger, timePointInReaching, WindPositionMode.LEG_MIDDLE); + Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToCompetitorFarthestAhead(plattner, timePointInReaching, WindPositionMode.LEG_MIDDLE); assertEquals(0., hungersDistanceToLeader.getMeters(), 0.00001); assertEquals(distanceOfReachingLeg.getMeters(), plattnersDistanceToLeader.getMeters(), 0.001); } @@ -224,8 +224,8 @@ public class ReachingLegTest extends TrackBasedTest { assertEquals(0., getTrackedRace().getTrack(plattner).getEstimatedPosition(timePointInReaching, /* extrapolate */false) .getDistance(windwardMarkPos).getMeters(), 0.00001); - Distance hungersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(hunger, timePointInReaching, WindPositionMode.LEG_MIDDLE); - Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(plattner, timePointInReaching, WindPositionMode.LEG_MIDDLE); + Distance hungersDistanceToLeader = getTrackedRace().getWindwardDistanceToCompetitorFarthestAhead(hunger, timePointInReaching, WindPositionMode.LEG_MIDDLE); + Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToCompetitorFarthestAhead(plattner, timePointInReaching, WindPositionMode.LEG_MIDDLE); assertEquals(0., hungersDistanceToLeader.getMeters(), 0.00001); assertEquals(distanceOfReachingLeg.getMeters(), plattnersDistanceToLeader.getMeters(), 0.001); } @@ -254,8 +254,8 @@ public class ReachingLegTest extends TrackBasedTest { assertEquals(0., getTrackedRace().getTrack(plattner).getEstimatedPosition(timePointInReaching, /* extrapolate */false) .getDistance(windwardMarkPos).getMeters(), 0.00001); - Distance hungersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(hunger, timePointInReaching, WindPositionMode.LEG_MIDDLE); - Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(plattner, timePointInReaching, WindPositionMode.LEG_MIDDLE); + Distance hungersDistanceToLeader = getTrackedRace().getWindwardDistanceToCompetitorFarthestAhead(hunger, timePointInReaching, WindPositionMode.LEG_MIDDLE); + Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToCompetitorFarthestAhead(plattner, timePointInReaching, WindPositionMode.LEG_MIDDLE); assertEquals(0., hungersDistanceToLeader.getMeters(), 0.00001); assertEquals(distanceOfReachingLeg.getMeters(), plattnersDistanceToLeader.getMeters(), 0.001); } @@ -289,8 +289,8 @@ public class ReachingLegTest extends TrackBasedTest { assertEquals(0., getTrackedRace().getTrack(plattner).getEstimatedPosition(timePointToConsider, /* extrapolate */false) .getDistance(leewardPos).getMeters(), 0.00001); - Distance hungersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(hunger, timePointToConsider, WindPositionMode.LEG_MIDDLE); - Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(plattner, timePointToConsider, WindPositionMode.LEG_MIDDLE); + Distance hungersDistanceToLeader = getTrackedRace().getWindwardDistanceToCompetitorFarthestAhead(hunger, timePointToConsider, WindPositionMode.LEG_MIDDLE); + Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToCompetitorFarthestAhead(plattner, timePointToConsider, WindPositionMode.LEG_MIDDLE); assertEquals(0., hungersDistanceToLeader.getMeters(), 0.00001); assertEquals(distanceOfReachingLeg.getMeters()+windwardDistanceOfUpwindLeg.getMeters(), plattnersDistanceToLeader.getMeters(), 0.001); } @@ -333,8 +333,8 @@ public class ReachingLegTest extends TrackBasedTest { assertEquals(0., getTrackedRace().getTrack(plattner).getEstimatedPosition(timePointToConsider, /* extrapolate */false) .getDistance(leewardPos).getMeters(), 0.00001); - Distance schomaekersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(schomaeker, timePointToConsider, WindPositionMode.LEG_MIDDLE); - Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(plattner, timePointToConsider, WindPositionMode.LEG_MIDDLE); + Distance schomaekersDistanceToLeader = getTrackedRace().getWindwardDistanceToCompetitorFarthestAhead(schomaeker, timePointToConsider, WindPositionMode.LEG_MIDDLE); + Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToCompetitorFarthestAhead(plattner, timePointToConsider, WindPositionMode.LEG_MIDDLE); assertEquals(0., schomaekersDistanceToLeader.getMeters(), 0.00001); // distance to leading Schomaeker expected to be the entire upwind distance plus the offset distance plus half the downwind assertEquals(distanceOfReachingLeg.getMeters()+windwardDistanceOfUpwindLeg.getMeters()*1.5, plattnersDistanceToLeader.getMeters(), 0.001); @@ -374,7 +374,7 @@ public class ReachingLegTest extends TrackBasedTest { getTrackedRace().getTrack(plattner).getEstimatedPosition(timePointToConsider, /* extrapolate */ false)).getMeters(), 0.00001); // however, projected onto the leg their distance should be 0 - Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(plattner, timePointToConsider, WindPositionMode.LEG_MIDDLE); + Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToCompetitorFarthestAhead(plattner, timePointToConsider, WindPositionMode.LEG_MIDDLE); assertEquals(0., plattnersDistanceToLeader.getMeters(), 0.00001); } } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java index c76c88397ae..facfd3e3f28 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java @@ -565,7 +565,7 @@ public class MockedTrackedRace implements DynamicTrackedRace { } @Override - public Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode) { + public Distance getWindwardDistanceToCompetitorFarthestAhead(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode) { return null; } @@ -936,7 +936,7 @@ public class MockedTrackedRace implements DynamicTrackedRace { } @Override - public Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, + public Distance getWindwardDistanceToCompetitorFarthestAhead(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) { return null; } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java index 007efbaa6d7..fc669816f33 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java @@ -346,7 +346,7 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace { } @Override - public Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode) { + public Distance getWindwardDistanceToCompetitorFarthestAhead(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode) { return null; } @@ -612,7 +612,7 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace { } @Override - public Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, + public Distance getWindwardDistanceToCompetitorFarthestAhead(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) { return null; } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java index 4eb21116aec..8c67eda8eef 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java @@ -1392,8 +1392,8 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race RaceDetails raceDetails = getRaceDetails(trackedRace, competitor, timePoint, waitForLatestAnalyses, legRanksCache, rankingInfo, cache); entryDTO.legDetails = raceDetails.getLegDetails(); - entryDTO.windwardDistanceToOverallLeaderInMeters = raceDetails.getWindwardDistanceToOverallLeader() == null ? null - : raceDetails.getWindwardDistanceToOverallLeader().getMeters(); + entryDTO.windwardDistanceToCompetitorFarthestAheadInMeters = raceDetails.getWindwardDistanceToCompetitorFarthestAhead() == null ? null + : raceDetails.getWindwardDistanceToCompetitorFarthestAhead().getMeters(); entryDTO.gapToLeaderInOwnTime = trackedRace.getRankingMetric().getGapToLeaderInOwnTime(rankingInfo, competitor, cache); entryDTO.averageAbsoluteCrossTrackErrorInMeters = raceDetails.getAverageAbsoluteCrossTrackError() == null ? null : raceDetails.getAverageAbsoluteCrossTrackError().getMeters(); @@ -1481,20 +1481,20 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race private static class RaceDetails { private final List legDetails; - private final Distance windwardDistanceToOverallLeader; + private final Distance windwardDistanceToCompetitorFarthestAhead; private final Distance averageAbsoluteCrossTrackError; private final Distance averageSignedCrossTrackError; private final Duration gapToLeaderInOwnTime; private final Duration correctedTime; private final Duration correctedTimeAtEstimatedArrivalAtCompetitorFarthestAhead; - public RaceDetails(List legDetails, Distance windwardDistanceToOverallLeader, + public RaceDetails(List legDetails, Distance windwardDistanceToCompetitorFarthestAhead, Distance averageAbsoluteCrossTrackError, Distance averageSignedCrossTrackError, Duration gapToLeaderInOwnTime, Duration correctedTime, Duration correctedTimeAtEstimatedArrivalAtCompetitorFarthestAhead) { super(); this.legDetails = legDetails; - this.windwardDistanceToOverallLeader = windwardDistanceToOverallLeader; + this.windwardDistanceToCompetitorFarthestAhead = windwardDistanceToCompetitorFarthestAhead; this.averageAbsoluteCrossTrackError = averageAbsoluteCrossTrackError; this.averageSignedCrossTrackError = averageSignedCrossTrackError; this.gapToLeaderInOwnTime = gapToLeaderInOwnTime; @@ -1504,8 +1504,8 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race public List getLegDetails() { return legDetails; } - public Distance getWindwardDistanceToOverallLeader() { - return windwardDistanceToOverallLeader; + public Distance getWindwardDistanceToCompetitorFarthestAhead() { + return windwardDistanceToCompetitorFarthestAhead; } public Distance getAverageAbsoluteCrossTrackError() { return averageAbsoluteCrossTrackError; @@ -1599,8 +1599,8 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race } legDetails.add(legEntry); } - final Distance windwardDistanceToOverallLeader = trackedRace == null ? null : trackedRace - .getWindwardDistanceToOverallLeader(competitor, timePoint, WindPositionMode.LEG_MIDDLE, rankingInfo, cache); + final Distance windwardDistanceToCompetitorFarthestAhead = trackedRace == null ? null : trackedRace + .getWindwardDistanceToCompetitorFarthestAhead(competitor, timePoint, WindPositionMode.LEG_MIDDLE, rankingInfo, cache); Distance averageAbsoluteCrossTrackError; try { averageAbsoluteCrossTrackError = trackedRace == null ? null : trackedRace.getAverageAbsoluteCrossTrackError( @@ -1617,7 +1617,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race // without wind information, use null meaning "unknown" averageSignedCrossTrackError = null; } - return new RaceDetails(legDetails, windwardDistanceToOverallLeader, averageAbsoluteCrossTrackError, averageSignedCrossTrackError, + return new RaceDetails(legDetails, windwardDistanceToCompetitorFarthestAhead, averageAbsoluteCrossTrackError, averageSignedCrossTrackError, trackedRace.getRankingMetric().getGapToLeaderInOwnTime(rankingInfo, competitor, cache), trackedRace.getRankingMetric().getCorrectedTime(competitor, timePoint), rankingInfo.getCompetitorRankingInfo().apply(competitor).getCorrectedTimeAtEstimatedArrivalAtCompetitorFarthestAhead()); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedLegOfCompetitor.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedLegOfCompetitor.java index 107b584152b..d856219aab4 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedLegOfCompetitor.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedLegOfCompetitor.java @@ -236,14 +236,14 @@ public interface TrackedLegOfCompetitor extends Serializable { * * @param rankingInfo materialized ranking information that is pre-calculated to avoid expensive redundant work */ - Distance getWindwardDistanceToOverallLeader(TimePoint timePoint, WindPositionMode windPositionMode, RankingInfo rankingInfo); + Distance getWindwardDistanceToCompetitorFarthestAhead(TimePoint timePoint, WindPositionMode windPositionMode, RankingInfo rankingInfo); /** - * Same as {@link #getWindwardDistanceToOverallLeader(TimePoint, WindPositionMode, RankingInfo)}, only that a cache for leg type + * Same as {@link #getWindwardDistanceToCompetitorFarthestAhead(TimePoint, WindPositionMode, RankingInfo)}, only that a cache for leg type * calculation is passed. * @param rankingInfo TODO */ - Distance getWindwardDistanceToOverallLeader(TimePoint timePoint, WindPositionMode windPositionMode, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache); + Distance getWindwardDistanceToCompetitorFarthestAhead(TimePoint timePoint, WindPositionMode windPositionMode, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache); /** * Computes the average absolute cross track error for this leg. The cross track error for each fix is taken to be a diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java index 18847ed51d7..c98280a45e8 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java @@ -516,20 +516,21 @@ public interface TrackedRace extends Serializable { Distance getDistanceTraveledIncludingGateStart(Competitor competitor, TimePoint timePoint); /** - * See {@link TrackedLegOfCompetitor#getWindwardDistanceToOverallLeader(TimePoint, WindPositionMode, RankingInfo)} + * See {@link TrackedLegOfCompetitor#getWindwardDistanceToCompetitorFarthestAhead(TimePoint, WindPositionMode, RankingInfo)} */ - Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode); + Distance getWindwardDistanceToCompetitorFarthestAhead(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode); /** - * Same as {@link #getWindwardDistanceToOverallLeader(Competitor, TimePoint, WindPositionMode)}, only with an + * Same as {@link #getWindwardDistanceToCompetitorFarthestAhead(Competitor, TimePoint, WindPositionMode)}, only with an * additional cache to speed up wind and leg type and leg bearing calculations in case of multiple similar look-ups * for the same time point. * * @param rankingInfo * materialized ranking information that is expensive to calculate, avoiding redundant calculations */ - Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache); - + Distance getWindwardDistanceToCompetitorFarthestAhead(Competitor competitor, TimePoint timePoint, + WindPositionMode windPositionMode, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache); + /** * Calls {@link #getWindWithConfidence(Position, TimePoint, Iterable)} and excludes those wind sources listed in * {@link #getWindSourcesToExclude}. diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedLegOfCompetitorImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedLegOfCompetitorImpl.java index 65b7b54f330..b0bdde607a6 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedLegOfCompetitorImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedLegOfCompetitorImpl.java @@ -407,17 +407,17 @@ public class TrackedLegOfCompetitorImpl implements TrackedLegOfCompetitor { } @Override - public Distance getWindwardDistanceToOverallLeader(TimePoint timePoint, WindPositionMode windPositionMode, final RankingInfo rankingInfo) { - return getWindwardDistanceToOverallLeader(timePoint, windPositionMode, rankingInfo, new LeaderboardDTOCalculationReuseCache(timePoint)); + public Distance getWindwardDistanceToCompetitorFarthestAhead(TimePoint timePoint, WindPositionMode windPositionMode, final RankingInfo rankingInfo) { + return getWindwardDistanceToCompetitorFarthestAhead(timePoint, windPositionMode, rankingInfo, new LeaderboardDTOCalculationReuseCache(timePoint)); } @Override - public Distance getWindwardDistanceToOverallLeader(TimePoint timePoint, WindPositionMode windPositionMode, final RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) { + public Distance getWindwardDistanceToCompetitorFarthestAhead(TimePoint timePoint, WindPositionMode windPositionMode, final RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) { // FIXME bug 607 it seems the following fetches the leader of this leg, not the overall leader; validate!!! Use getTrackedRace().getRanks() instead - Competitor leader = getTrackedRace().getOverallLeader(timePoint, cache); - TrackedLegOfCompetitor leaderLeg = getTrackedRace().getCurrentLeg(leader, timePoint); + Competitor competitorFarthestAhead = rankingInfo.getCompetitorFarthestAhead(); + TrackedLegOfCompetitor leaderLeg = getTrackedRace().getCurrentLeg(competitorFarthestAhead, timePoint); Distance result = null; - Position leaderPosition = getTrackedRace().getTrack(leader).getEstimatedPosition(timePoint, /* extrapolate */ false); + Position leaderPosition = getTrackedRace().getTrack(competitorFarthestAhead).getEstimatedPosition(timePoint, /* extrapolate */ false); Position currentPosition = getTrackedRace().getTrack(getCompetitor()).getEstimatedPosition(timePoint, /* extrapolate */ false); if (leaderPosition != null && currentPosition != null) { result = Distance.NULL; diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java index b29da580d62..d95cc59003c 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java @@ -2870,17 +2870,17 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl } @Override - public Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode) { + public Distance getWindwardDistanceToCompetitorFarthestAhead(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode) { final TrackedLegOfCompetitor trackedLeg = getTrackedLeg(competitor, timePoint); - return trackedLeg == null ? null : trackedLeg.getWindwardDistanceToOverallLeader(timePoint, windPositionMode, + return trackedLeg == null ? null : trackedLeg.getWindwardDistanceToCompetitorFarthestAhead(timePoint, windPositionMode, getRankingMetric().getRankingInfo(timePoint)); } @Override - public Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, + public Distance getWindwardDistanceToCompetitorFarthestAhead(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) { final TrackedLegOfCompetitor trackedLeg = getTrackedLeg(competitor, timePoint); - return trackedLeg == null ? null : trackedLeg.getWindwardDistanceToOverallLeader(timePoint, windPositionMode, rankingInfo, cache); + return trackedLeg == null ? null : trackedLeg.getWindwardDistanceToCompetitorFarthestAhead(timePoint, windPositionMode, rankingInfo, cache); } @Override diff --git a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java index 28cf967bdf7..a0f40d5a6b6 100755 --- a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java +++ b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java @@ -373,7 +373,7 @@ public class MockedTrackedRace implements DynamicTrackedRace { } @Override - public Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode) { + public Distance getWindwardDistanceToCompetitorFarthestAhead(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode) { return null; } @@ -744,7 +744,7 @@ public class MockedTrackedRace implements DynamicTrackedRace { } @Override - public Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, + public Distance getWindwardDistanceToCompetitorFarthestAhead(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) { return null; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/DetailTypeFormatter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/DetailTypeFormatter.java index 28d96586320..d831258f29c 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/DetailTypeFormatter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/DetailTypeFormatter.java @@ -60,16 +60,16 @@ public class DetailTypeFormatter { return stringMessages.averageSpeedInKnots(); case RACE_GAP_TO_LEADER_IN_SECONDS: return stringMessages.gapToLeaderInSeconds(); - case RACE_DISTANCE_TO_LEADER_IN_METERS: - return stringMessages.windwardDistanceToLeaderInMeters(); + case RACE_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD_IN_METERS: + return stringMessages.windwardDistanceToCompetitorFarthestAheadInMeters(); case RACE_AVERAGE_ABSOLUTE_CROSS_TRACK_ERROR_IN_METERS: return stringMessages.averageAbsoluteCrossTrackErrorInMeters(); case RACE_AVERAGE_SIGNED_CROSS_TRACK_ERROR_IN_METERS: return stringMessages.averageSignedCrossTrackErrorInMeters(); case START_TACK: return stringMessages.startTack(); - case WINDWARD_DISTANCE_TO_OVERALL_LEADER: - return stringMessages.windwardDistanceToLeaderInMeters(); + case WINDWARD_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD: + return stringMessages.windwardDistanceToCompetitorFarthestAheadInMeters(); case DISTANCE_TO_START_AT_RACE_START: return stringMessages.distanceToLineAtRaceStart(); case TIME_BETWEEN_RACE_START_AND_COMPETITOR_START: @@ -170,11 +170,11 @@ public class DetailTypeFormatter { case RACE_SPEED_OVER_GROUND_FIVE_SECONDS_BEFORE_START: return stringMessages.knotsUnit(); - case WINDWARD_DISTANCE_TO_OVERALL_LEADER: + case WINDWARD_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD: case WINDWARD_DISTANCE_TO_GO_IN_METERS: case DISTANCE_TRAVELED: case DISTANCE_TRAVELED_INCLUDING_GATE_START: - case RACE_DISTANCE_TO_LEADER_IN_METERS: + case RACE_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD_IN_METERS: case RACE_DISTANCE_TRAVELED: case RACE_DISTANCE_TRAVELED_INCLUDING_GATE_START: case AVERAGE_TACK_LOSS_IN_METERS: @@ -304,9 +304,9 @@ public class DetailTypeFormatter { return stringMessages.currentOrAverageSpeedOverGroundInKnotsTooltip(); case RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS: return stringMessages.currentSpeedOverGroundInKnotsTooltip(); - case RACE_DISTANCE_TO_LEADER_IN_METERS: + case RACE_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD_IN_METERS: return stringMessages.windwardDistanceToLeaderInMetersTooltip(); - case WINDWARD_DISTANCE_TO_OVERALL_LEADER: + case WINDWARD_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD: return stringMessages.windwardDistanceToLeaderInMetersTooltip(); case DISTANCE_TO_START_AT_RACE_START: return stringMessages.distanceToLineAtRaceStartTooltip(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java index b2eeaf09e4f..7d57509852e 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java @@ -93,7 +93,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c String gapToLeaderInSeconds(); String velocityMadeGoodInKnots(); String windwardDistanceToGoInMeters(); - String windwardDistanceToLeaderInMeters(); + String windwardDistanceToCompetitorFarthestAheadInMeters(); String name(); String leaveEmptyForDefault(); String trackNewEvent(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index c03a329f4d5..6d55741c6b5 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -91,8 +91,8 @@ velocityMadeGoodInKnots=VMG velocityMadeGoodInKnotsTooltip=The velocity made good, which is the windward/leeward speed for upwind/downwind legs, respectively, or the along-track speed for reaching legs. windwardDistanceToGoInMeters=Windward distance to go windwardDistanceToGoInMetersTooltip=Windward/leeward distance from the competitor''s current position to the end of the leg for upwind/downwind legs, respectively, or the along-track distance for reaching legs. -windwardDistanceToLeaderInMeters=Windward Distance To Leader -windwardDistanceToLeaderInMetersTooltip=Windward/leeward distance of the competitor to the leader for upwind/downwind legs, respectively, or the along-track distance for reaching legs. +windwardDistanceToCompetitorFarthestAheadInMeters=Windward Distance To Competitor Farthest Ahead +windwardDistanceToCompetitorFarthestAheadInMeters=Windward/leeward distance of the competitor to the competitor farthest ahead in the race for upwind/downwind legs, respectively, or the along-track distance for reaching legs.\nNote that the competitor that is farthest ahead is not necessarily leading the race if handicap ranking is in place. name=Name leaveEmptyForDefault=Leave empty for default trackNewEvent=Track New event diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_cn.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_cn.properties index 4d160534af8..3ff8bd0110c 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_cn.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_cn.properties @@ -812,7 +812,7 @@ papaRemoved=Start mode flag - one minute till start showDiagram=显示图表 dontoverwrite=Don''t overwrite storedData=Stored data -windwardDistanceToLeaderInMeters=迎风航段时离开上风第一名的平行距离 +windwardDistanceToCompetitorFarthestAheadInMeters=迎风航段时离开上风第一名的平行距离 hostname=Hostname distanceIncludingGateStartInMeters=距离(起航门标) valueForCompetitorAt={0} at {1}: {2} @@ -827,7 +827,7 @@ windChart=Wind Chart events=活动 racesAreLive=Races {0} are live operatorNotContains=Not Contains -windwardDistanceToLeaderInMetersTooltip=迎/顺风航段时离开上风/下风第一名的平行距离或横风时的实际距离name 名字 +windwardDistanceToCompetitorFarthestAheadInMetersTooltip=迎/顺风航段时离开上风/下风第一名的平行距离或横风时的实际距离name 名字 errorAddingResultImportUrl=Error adding result import URL: {0} noGrouperSelectedError=No grouper type is selected leaderboardsExceptFromSelectedGroup=Leaderboards (except those of selected group) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties index 5beec811b2d..c5f80d95265 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties @@ -91,8 +91,8 @@ velocityMadeGoodInKnots=VMG velocityMadeGoodInKnotsTooltip=Die effektive Geschwindigkeit zum Ziel; auf der Kreuz die windwärtige Geschwindigkeit; auf der Vorwindstrecke die leewärtige Geschwindigkeit windwardDistanceToGoInMeters=Abstand in Windrichtung zur nächsten Bahnmarke windwardDistanceToGoInMetersTooltip=Windwärtige / leewärtige Distanz des Teilnehmerns bis zum Ende des Schenkels auf Kreuz bzw. Vorwindstrecke; Strecke entlang des Schenkels bei Holeschlägen -windwardDistanceToLeaderInMeters=Abstand zum führenden Boot -windwardDistanceToLeaderInMetersTooltip=Windwärtige Distanz des Teilnehmers zum Führenden +windwardDistanceToCompetitorFarthestAheadInMeters=Windärtiger Abstand zum schnellsten Boot +windwardDistanceToCompetitorFarthestAheadInMeters=Windwärtiger Abstand zum Boot, das bisher am weitesten windwärts gesegelt ist.\nFür Handicap-Wertungen ist das nicht notwendigerweise der nach Verrechnung in Führung liegende Teilnehmer. name=Name leaveEmptyForDefault=Leer für Standardeinstellung trackNewEvent=Track New event diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties index bd92df88f18..78f874c5019 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties @@ -91,8 +91,8 @@ velocityMadeGoodInKnots=Скорость лавирования (VMG) velocityMadeGoodInKnotsTooltip=Скорость лавирования, представляет собой скорость продвижения на ветер/ по ветру для этапов движения против ветра/ по ветру соответственно, или скорость в направлении движения при лавировании по ветру windwardDistanceToGoInMeters=Расстояние, которое необходимо пройти на ветер windwardDistanceToGoInMetersTooltip=Расстояние движения на ветер/ по ветру от текущего положения участника до конца этапа для этапов движения против ветра/ по ветру соответственно, или скорость в направлении движения при лавировании по ветру. -windwardDistanceToLeaderInMeters=Расстояние на ветер до лидера -windwardDistanceToLeaderInMetersTooltip=Расстояние на ветер/ под ветер от участника до лидера для этапов движения против ветра/ по ветру соответственно или скорость в направлении движения при лавировании по ветру. +windwardDistanceToCompetitorFarthestAheadInMeters=Расстояние на ветер до лидера +windwardDistanceToCompetitorFarthestAheadInMeters=Расстояние на ветер/ под ветер от участника до лидера для этапов движения против ветра/ по ветру соответственно или скорость в направлении движения при лавировании по ветру. name=Имя leaveEmptyForDefault=Оставьте пустым по умолчанию. trackNewEvent=Отследить новое событие diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/AbstractCompetitorRaceChart.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/AbstractCompetitorRaceChart.java index a2d0ca9c751..28ed045dec9 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/AbstractCompetitorRaceChart.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/AbstractCompetitorRaceChart.java @@ -539,7 +539,7 @@ public abstract class AbstractCompetitorRaceChart() { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/MultiCompetitorRaceChartSettingsComponent.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/MultiCompetitorRaceChartSettingsComponent.java index 40b0e69edc0..fa00a8e87d6 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/MultiCompetitorRaceChartSettingsComponent.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/MultiCompetitorRaceChartSettingsComponent.java @@ -25,7 +25,7 @@ public class MultiCompetitorRaceChartSettingsComponent extends AbstractChartSett this.initialDetailType = settings.getDetailType(); availableDetailsTypes = new ArrayList(); - availableDetailsTypes.add(DetailType.WINDWARD_DISTANCE_TO_OVERALL_LEADER); + availableDetailsTypes.add(DetailType.WINDWARD_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD); availableDetailsTypes.add(DetailType.DISTANCE_TRAVELED); availableDetailsTypes.add(DetailType.DISTANCE_TRAVELED_INCLUDING_GATE_START); availableDetailsTypes.add(DetailType.VELOCITY_MADE_GOOD_IN_KNOTS); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java index d58c115ab70..57feed463eb 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java @@ -863,7 +863,7 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS DetailType.RACE_DISTANCE_TRAVELED, DetailType.RACE_DISTANCE_TRAVELED_INCLUDING_GATE_START, DetailType.RACE_TIME_TRAVELED, DetailType.RACE_CORRECTED_TIME_TRAVELED, DetailType.RACE_CORRECTED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD, - DetailType.RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS, DetailType.RACE_DISTANCE_TO_LEADER_IN_METERS, + DetailType.RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS, DetailType.RACE_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD_IN_METERS, DetailType.NUMBER_OF_MANEUVERS, DetailType.DISPLAY_LEGS, DetailType.CURRENT_LEG, DetailType.RACE_AVERAGE_ABSOLUTE_CROSS_TRACK_ERROR_IN_METERS, DetailType.RACE_AVERAGE_SIGNED_CROSS_TRACK_ERROR_IN_METERS, @@ -939,8 +939,8 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS result.put(DetailType.RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS, new FormattedDoubleDetailTypeColumn(DetailType.RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS, new CurrentSpeedOverGroundInKnots(), LEG_COLUMN_HEADER_STYLE, LEG_COLUMN_STYLE, LeaderboardPanel.this)); - result.put(DetailType.RACE_DISTANCE_TO_LEADER_IN_METERS, - new FormattedDoubleDetailTypeColumn(DetailType.RACE_DISTANCE_TO_LEADER_IN_METERS, new RaceDistanceToLeaderInMeters(), + result.put(DetailType.RACE_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD_IN_METERS, + new FormattedDoubleDetailTypeColumn(DetailType.RACE_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD_IN_METERS, new RaceDistanceToCompetitorFarthestAheadInMeters(), LEG_COLUMN_HEADER_STYLE, LEG_COLUMN_STYLE, LeaderboardPanel.this)); result.put(DetailType.RACE_AVERAGE_ABSOLUTE_CROSS_TRACK_ERROR_IN_METERS, new FormattedDoubleDetailTypeColumn(DetailType.RACE_AVERAGE_ABSOLUTE_CROSS_TRACK_ERROR_IN_METERS, new RaceAverageAbsoluteCrossTrackErrorInMeters(), @@ -1378,17 +1378,18 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS } /** - * Computes the windward distance to the overall leader in meters + * Computes the windward distance to the competitor farthest ahead in the race (not necessarily the leader with + * handicap scoring) in meters * * @author Axel Uhl (D043530) */ - private class RaceDistanceToLeaderInMeters implements LegDetailField { + private class RaceDistanceToCompetitorFarthestAheadInMeters implements LegDetailField { @Override public Double get(LeaderboardRowDTO row) { Double result = null; LeaderboardEntryDTO fieldsForRace = row.fieldsByRaceColumnName.get(getRaceColumnName()); - if (fieldsForRace != null && fieldsForRace.windwardDistanceToOverallLeaderInMeters != null) { - result = fieldsForRace.windwardDistanceToOverallLeaderInMeters; + if (fieldsForRace != null && fieldsForRace.windwardDistanceToCompetitorFarthestAheadInMeters != null) { + result = fieldsForRace.windwardDistanceToCompetitorFarthestAheadInMeters; } return result; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardSettingsFactory.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardSettingsFactory.java index f4036493976..2420a5c2d3f 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardSettingsFactory.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardSettingsFactory.java @@ -67,7 +67,7 @@ public class LeaderboardSettingsFactory { List raceDetails = new ArrayList(); raceDetails.add(DetailType.RACE_DISTANCE_TRAVELED); raceDetails.add(DetailType.RACE_AVERAGE_SPEED_OVER_GROUND_IN_KNOTS); - raceDetails.add(DetailType.RACE_DISTANCE_TO_LEADER_IN_METERS); + raceDetails.add(DetailType.RACE_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD_IN_METERS); raceDetails.add(DetailType.NUMBER_OF_MANEUVERS); raceDetails.add(DetailType.DISPLAY_LEGS); final List overallDetails = createOverallDetailsForShowRegattaRank(showRegattaRank); 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 c158f4bdbff..1478706e9dd 100755 --- 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 @@ -2726,10 +2726,10 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S result = gapToLeaderInOwnTime == null ? null : gapToLeaderInOwnTime.asSeconds(); } break; - case WINDWARD_DISTANCE_TO_OVERALL_LEADER: + case WINDWARD_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD: if (trackedLeg != null) { final RankingInfo rankingInfo = trackedRace.getRankingMetric().getRankingInfo(timePoint); - Distance distanceToLeader = trackedLeg.getWindwardDistanceToOverallLeader(timePoint, WindPositionMode.LEG_MIDDLE, rankingInfo); + Distance distanceToLeader = trackedLeg.getWindwardDistanceToCompetitorFarthestAhead(timePoint, WindPositionMode.LEG_MIDDLE, rankingInfo); result = (distanceToLeader == null) ? null : distanceToLeader.getMeters(); } break; diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java index 1ca9d529ce0..6db76168f62 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java @@ -996,11 +996,11 @@ public class RegattasResource extends AbstractSailingServerResource { jsonCompetitorInLeg.put("gapToLeader-s", roundDouble(gapToLeader.asSeconds(), 2)); } - Distance windwardDistanceToOverallLeader = currentLegOfCompetitor - .getWindwardDistanceToOverallLeader(timePoint, WindPositionMode.LEG_MIDDLE, rankingInfo); - if (windwardDistanceToOverallLeader != null) { + Distance windwardDistanceToCompetitorFarthestAhead = currentLegOfCompetitor + .getWindwardDistanceToCompetitorFarthestAhead(timePoint, WindPositionMode.LEG_MIDDLE, rankingInfo); + if (windwardDistanceToCompetitorFarthestAhead != null) { jsonCompetitorInLeg.put("gapToLeader-m", - roundDouble(windwardDistanceToOverallLeader.getMeters(), 2)); + roundDouble(windwardDistanceToCompetitorFarthestAhead.getMeters(), 2)); } jsonCompetitorInLeg.put("finished", false); } else { diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy).launch b/java/com.sap.sailing.server/SailingServer (No Proxy).launch index b2ce1901af2..7614e7a8e9a 100644 --- a/java/com.sap.sailing.server/SailingServer (No Proxy).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy).launch @@ -17,7 +17,7 @@ - + diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java index 37417c80a82..e0218afdb82 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java @@ -340,7 +340,7 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials { } @Override - public Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode) { + public Distance getWindwardDistanceToCompetitorFarthestAhead(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode) { return null; } @@ -597,7 +597,7 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials { } @Override - public Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, + public Distance getWindwardDistanceToCompetitorFarthestAhead(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) { return null; } diff --git a/java/com.sap.sailing.xmlexport/src/com/sap/sailing/xmlexport/LeaderboardData.java b/java/com.sap.sailing.xmlexport/src/com/sap/sailing/xmlexport/LeaderboardData.java index 7adcb3094ec..916d2e7d9a1 100644 --- a/java/com.sap.sailing.xmlexport/src/com/sap/sailing/xmlexport/LeaderboardData.java +++ b/java/com.sap.sailing.xmlexport/src/com/sap/sailing/xmlexport/LeaderboardData.java @@ -655,8 +655,9 @@ public class LeaderboardData extends ExportAction { } addNamedElementWithValue(competitorLegDataElement, "time_spend_in_this_leg_as_millis", timeSpentInThisLeg != null ? timeSpentInThisLeg.asMillis() : new MillisecondsDurationImpl(0).asMillis()); addNamedElementWithValue(competitorLegDataElement, "gap_to_leader_at_finish_in_seconds", competitorLeg.getGapToLeader(legFinishTime, rankingMetricAtLegFinishTime, WindPositionMode.LEG_MIDDLE).asSeconds()); - Distance windwardDistanceToOverallLeader = competitorLeg.getWindwardDistanceToOverallLeader(legFinishTime, WindPositionMode.LEG_MIDDLE, rankingMetricAtLegFinishTime); - addNamedElementWithValue(competitorLegDataElement, "windward_distance_to_overall_leader_that_has_finished_this_leg_in_meters", windwardDistanceToOverallLeader != null ? windwardDistanceToOverallLeader.getMeters() : 0); + Distance windwardDistanceToCompetitorFarthestAhead = competitorLeg.getWindwardDistanceToCompetitorFarthestAhead(legFinishTime, WindPositionMode.LEG_MIDDLE, rankingMetricAtLegFinishTime); + // TODO bug1018 decide whether the following field should be renamed to express that it's not the distance to the "leader" but the competitor farthest ahead; discussed with Simon on 2015-05-28; Simon says we leave it like this for now + addNamedElementWithValue(competitorLegDataElement, "windward_distance_to_overall_leader_that_has_finished_this_leg_in_meters", windwardDistanceToCompetitorFarthestAhead != null ? windwardDistanceToCompetitorFarthestAhead.getMeters() : 0); addNamedElementWithValue(competitorLegDataElement, "distance_traveled_in_meters", competitorLeg.getDistanceTraveled(legFinishTime).getMeters()); addNamedElementWithValue(competitorLegDataElement, "average_speed_over_ground_in_knots", competitorLeg.getAverageSpeedOverGround(legFinishTime).getKnots()); From 53f1e1b7d69213623335db2744880696682a6137 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 28 May 2015 19:28:33 +0200 Subject: [PATCH 46/72] fixed windward distance so it's not to the leader but to the boat farthest ahead --- .../gwt/ui/client/DetailTypeFormatter.java | 4 ++-- .../sailing/gwt/ui/client/StringMessages.java | 2 +- .../gwt/ui/client/StringMessages.properties | 2 +- .../ui/client/StringMessages_de.properties | 2 +- .../ui/client/StringMessages_ru.properties | 2 +- .../gwt/ui/client/shared/racemap/RaceMap.java | 24 +++++++++++++------ .../gwt/ui/leaderboard/LeaderboardPanel.java | 3 +-- .../gwt/ui/server/QuickRanksLiveCache.java | 22 ++++++++--------- .../gwt/ui/server/SailingServiceImpl.java | 20 ++++++++++------ .../gwt/ui/shared/CompactRaceMapDataDTO.java | 24 ++++++++++++++++--- .../sailing/gwt/ui/shared/RaceMapDataDTO.java | 1 + .../sailing/server/RacingEventService.java | 3 +++ .../server/impl/RacingEventServiceImpl.java | 11 +++++++++ 13 files changed, 84 insertions(+), 36 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/DetailTypeFormatter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/DetailTypeFormatter.java index d831258f29c..3550db359ce 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/DetailTypeFormatter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/DetailTypeFormatter.java @@ -305,9 +305,9 @@ public class DetailTypeFormatter { case RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS: return stringMessages.currentSpeedOverGroundInKnotsTooltip(); case RACE_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD_IN_METERS: - return stringMessages.windwardDistanceToLeaderInMetersTooltip(); + return stringMessages.windwardDistanceToCompetitorFarthestAheadInMetersTooltip(); case WINDWARD_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD: - return stringMessages.windwardDistanceToLeaderInMetersTooltip(); + return stringMessages.windwardDistanceToCompetitorFarthestAheadInMetersTooltip(); case DISTANCE_TO_START_AT_RACE_START: return stringMessages.distanceToLineAtRaceStartTooltip(); case TIME_BETWEEN_RACE_START_AND_COMPETITOR_START: diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java index 7d57509852e..8ed18a44888 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java @@ -509,7 +509,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c String penaltyCircleTooltip(); String raceAverageSpeedInKnotsTooltip(); String currentSpeedOverGroundInKnotsTooltip(); - String windwardDistanceToLeaderInMetersTooltip(); + String windwardDistanceToCompetitorFarthestAheadInMetersTooltip(); String raceDistanceTraveledTooltip(); String rankTooltip(); String rankGainTooltip(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index 6d55741c6b5..09c4cbb1591 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -92,7 +92,7 @@ velocityMadeGoodInKnotsTooltip=The velocity made good, which is the windward/lee windwardDistanceToGoInMeters=Windward distance to go windwardDistanceToGoInMetersTooltip=Windward/leeward distance from the competitor''s current position to the end of the leg for upwind/downwind legs, respectively, or the along-track distance for reaching legs. windwardDistanceToCompetitorFarthestAheadInMeters=Windward Distance To Competitor Farthest Ahead -windwardDistanceToCompetitorFarthestAheadInMeters=Windward/leeward distance of the competitor to the competitor farthest ahead in the race for upwind/downwind legs, respectively, or the along-track distance for reaching legs.\nNote that the competitor that is farthest ahead is not necessarily leading the race if handicap ranking is in place. +windwardDistanceToCompetitorFarthestAheadInMetersTooltip=Windward/leeward distance of the competitor to the competitor farthest ahead in the race for upwind/downwind legs, respectively, or the along-track distance for reaching legs.\nNote that the competitor that is farthest ahead is not necessarily leading the race if handicap ranking is in place. name=Name leaveEmptyForDefault=Leave empty for default trackNewEvent=Track New event diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties index c5f80d95265..7e760b7db21 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties @@ -92,7 +92,7 @@ velocityMadeGoodInKnotsTooltip=Die effektive Geschwindigkeit zum Ziel; auf der K windwardDistanceToGoInMeters=Abstand in Windrichtung zur nächsten Bahnmarke windwardDistanceToGoInMetersTooltip=Windwärtige / leewärtige Distanz des Teilnehmerns bis zum Ende des Schenkels auf Kreuz bzw. Vorwindstrecke; Strecke entlang des Schenkels bei Holeschlägen windwardDistanceToCompetitorFarthestAheadInMeters=Windärtiger Abstand zum schnellsten Boot -windwardDistanceToCompetitorFarthestAheadInMeters=Windwärtiger Abstand zum Boot, das bisher am weitesten windwärts gesegelt ist.\nFür Handicap-Wertungen ist das nicht notwendigerweise der nach Verrechnung in Führung liegende Teilnehmer. +windwardDistanceToCompetitorFarthestAheadInMetersTooltip=Windwärtiger Abstand zum Boot, das bisher am weitesten windwärts gesegelt ist.\nFür Handicap-Wertungen ist das nicht notwendigerweise der nach Verrechnung in Führung liegende Teilnehmer. name=Name leaveEmptyForDefault=Leer für Standardeinstellung trackNewEvent=Track New event diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties index 78f874c5019..4f23a78e306 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties @@ -92,7 +92,7 @@ velocityMadeGoodInKnotsTooltip=Скорость лавирования, пред windwardDistanceToGoInMeters=Расстояние, которое необходимо пройти на ветер windwardDistanceToGoInMetersTooltip=Расстояние движения на ветер/ по ветру от текущего положения участника до конца этапа для этапов движения против ветра/ по ветру соответственно, или скорость в направлении движения при лавировании по ветру. windwardDistanceToCompetitorFarthestAheadInMeters=Расстояние на ветер до лидера -windwardDistanceToCompetitorFarthestAheadInMeters=Расстояние на ветер/ под ветер от участника до лидера для этапов движения против ветра/ по ветру соответственно или скорость в направлении движения при лавировании по ветру. +windwardDistanceToCompetitorFarthestAheadInMetersTooltip=Расстояние на ветер/ под ветер от участника до лидера для этапов движения против ветра/ по ветру соответственно или скорость в направлении движения при лавировании по ветру. name=Имя leaveEmptyForDefault=Оставьте пустым по умолчанию. trackNewEvent=Отследить новое событие diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java index 3dae1691e7e..f6837809fb4 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java @@ -315,6 +315,13 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe * the last {@link #timeChanged(Date, Date)} event. Therefore, the ranks listed here correspond to the {@link #timer}'s time. */ private LinkedHashMap quickRanks; + + /** + * Taken from {@link RaceMapDataDTO#competitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber}; tells the + * windward distances traveled and the leg numbers in which the respective competitor is. + */ + private LinkedHashMap competitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber; + private final CombinedWindPanel combinedWindPanel; @@ -844,6 +851,8 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe public void onSuccess(RaceMapDataDTO raceMapDataDTO) { if (map != null && raceMapDataDTO != null) { quickRanks = raceMapDataDTO.quickRanks; + competitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber = + raceMapDataDTO.competitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber; if (showViewSimulation && settings.isShowSimulationOverlay()) { lastLegNumber = raceMapDataDTO.coursePositions.currentLegNumber; simulationOverlay.updateLeg(Math.max(lastLegNumber,1), /* clearCanvas */ false, raceMapDataDTO.simulationResultVersion); @@ -1153,15 +1162,16 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe /** * Returns a pair whose first component is the leg number (one-based) of the competitor returned as the second component. */ - private com.sap.sse.common.Util.Pair getLeadingVisibleCompetitorWithOneBasedLegNumber( + private com.sap.sse.common.Util.Pair getFarthestAheadVisibleCompetitorWithOneBasedLegNumber( Iterable competitorsToShow) { CompetitorDTO leadingCompetitorDTO = null; int legOfLeaderCompetitor = -1; // this only works because the quickRanks are sorted - for (QuickRankDTO quickRank : quickRanks.values()) { - if (Util.contains(competitorsToShow, quickRank.competitor)) { - leadingCompetitorDTO = quickRank.competitor; - legOfLeaderCompetitor = quickRank.legNumberOneBased; + for (Entry competitorsByWindwardDistanceTraveledAndOneBasedLegNumber : + competitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber.entrySet()) { + if (Util.contains(competitorsToShow, competitorsByWindwardDistanceTraveledAndOneBasedLegNumber.getKey())) { + leadingCompetitorDTO = competitorsByWindwardDistanceTraveledAndOneBasedLegNumber.getKey(); + legOfLeaderCompetitor = competitorsByWindwardDistanceTraveledAndOneBasedLegNumber.getValue(); return new com.sap.sse.common.Util.Pair(legOfLeaderCompetitor, leadingCompetitorDTO); } } @@ -1173,7 +1183,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe boolean drawAdvantageLine = false; if (settings.getHelpLinesSettings().isVisible(HelpLineTypes.ADVANTAGELINE)) { // find competitor with highest rank - com.sap.sse.common.Util.Pair visibleLeaderInfo = getLeadingVisibleCompetitorWithOneBasedLegNumber(competitorsToShow); + com.sap.sse.common.Util.Pair visibleLeaderInfo = getFarthestAheadVisibleCompetitorWithOneBasedLegNumber(competitorsToShow); // the boat fix may be null; may mean that no positions were loaded yet for the leading visible boat; // don't show anything GPSFixDTO lastBoatFix = null; @@ -1374,7 +1384,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe private void showStartAndFinishLines(final CoursePositionsDTO courseDTO) { if (map != null && courseDTO != null && lastRaceTimesInfo != null) { - com.sap.sse.common.Util.Pair leadingVisibleCompetitorInfo = getLeadingVisibleCompetitorWithOneBasedLegNumber(getCompetitorsToShow()); + com.sap.sse.common.Util.Pair leadingVisibleCompetitorInfo = getFarthestAheadVisibleCompetitorWithOneBasedLegNumber(getCompetitorsToShow()); int legOfLeadingCompetitor = leadingVisibleCompetitorInfo == null ? -1 : leadingVisibleCompetitorInfo.getA(); int numberOfLegs = lastRaceTimesInfo.legInfos.size(); // draw the start line diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java index 57feed463eb..01a598f57a8 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java @@ -873,8 +873,7 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS DetailType.SPEED_OVER_GROUND_WHEN_PASSING_START, DetailType.DISTANCE_TO_STARBOARD_END_OF_STARTLINE_WHEN_PASSING_START_IN_METERS, DetailType.START_TACK, - DetailType.RACE_RATIO_BETWEEN_TIME_SINCE_LAST_POSITION_FIX_AND_AVERAGE_SAMPLING_INTERVAL, - DetailType.RACE_CORRECTED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD}; + DetailType.RACE_RATIO_BETWEEN_TIME_SINCE_LAST_POSITION_FIX_AND_AVERAGE_SAMPLING_INTERVAL}; } public static DetailType[] getAvailableOverallDetailColumnTypes() { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/QuickRanksLiveCache.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/QuickRanksLiveCache.java index f39269e5d8b..321ad0e4756 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/QuickRanksLiveCache.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/QuickRanksLiveCache.java @@ -4,7 +4,6 @@ import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; @@ -13,6 +12,7 @@ import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.domain.tracking.impl.AbstractRaceChangeListener; import com.sap.sailing.gwt.ui.shared.QuickRankDTO; +import com.sap.sailing.gwt.ui.shared.QuickRanksDTO; import com.sap.sailing.server.masterdata.DummyTrackedRace; import com.sap.sse.util.SmartFutureCache; import com.sap.sse.util.SmartFutureCache.AbstractCacheUpdater; @@ -50,7 +50,7 @@ public class QuickRanksLiveCache { private final WeakReference stopRef = new WeakReference(dummyTrackedRace); - private final SmartFutureCache, CalculateOrPurge> cache; + private final SmartFutureCache cache; private final SailingServiceImpl service; @@ -72,19 +72,19 @@ public class QuickRanksLiveCache { public QuickRanksLiveCache(final SailingServiceImpl service) { this.service = service; - cache = new SmartFutureCache, CalculateOrPurge>( - new AbstractCacheUpdater, CalculateOrPurge>() { + cache = new SmartFutureCache( + new AbstractCacheUpdater() { @Override - public List computeCacheUpdate(RegattaAndRaceIdentifier key, + public QuickRanksDTO computeCacheUpdate(RegattaAndRaceIdentifier key, CalculateOrPurge updateInterval) throws Exception { logger.fine("Computing cache update for live QuickRanks of race "+key); - final List result; + final QuickRanksDTO quickRanks; if (updateInterval == CalculateOrPurge.PURGE) { - result = null; + quickRanks = null; } else { - result = service.computeQuickRanks(key, /* time point; null means live */ null); + quickRanks = service.computeQuickRanks(key, /* time point; null means live */ null); } - return result; + return quickRanks; } }, getClass().getName()); fromRefToRaceIdentifier = new HashMap<>(); @@ -118,8 +118,8 @@ public class QuickRanksLiveCache { dummyTrackedRace = null; // release the dummy tracked race, causing the stopRef to be enqueued } - public List get(RegattaAndRaceIdentifier raceIdentifier) { - List result = cache.get(raceIdentifier, false); + public QuickRanksDTO get(RegattaAndRaceIdentifier raceIdentifier) { + QuickRanksDTO result = cache.get(raceIdentifier, false); if (result == null) { TrackedRace trackedRace = service.getExistingTrackedRace(raceIdentifier); if (trackedRace != null) { 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 1478706e9dd..dee60bce5c3 100755 --- 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 @@ -304,6 +304,7 @@ import com.sap.sailing.gwt.ui.shared.MarkPassingTimesDTO; import com.sap.sailing.gwt.ui.shared.MarkpassingManeuverDTO; import com.sap.sailing.gwt.ui.shared.PathDTO; import com.sap.sailing.gwt.ui.shared.QuickRankDTO; +import com.sap.sailing.gwt.ui.shared.QuickRanksDTO; import com.sap.sailing.gwt.ui.shared.RaceCourseDTO; import com.sap.sailing.gwt.ui.shared.RaceGroupDTO; import com.sap.sailing.gwt.ui.shared.RaceGroupSeriesDTO; @@ -1571,7 +1572,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S fromPerCompetitorIdAsString, toPerCompetitorIdAsString, extrapolate); final CoursePositionsDTO coursePositions = getCoursePositions(raceIdentifier, date); final List courseSidelines = getCourseSidelines(raceIdentifier, date); - final List quickRanks = getQuickRanks(raceIdentifier, date); + final QuickRanksDTO quickRanks = getQuickRanks(raceIdentifier, date); int simulationResultVersion = 0; if (simulationLegIdentifier != null) { SimulationService simulationService = getService().getSimulationService(); @@ -2030,9 +2031,10 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S * null means "live" and is then replaced by "now" minus the tracked race's * {@link TrackedRace#getDelayToLiveInMillis() delay}. */ - public List computeQuickRanks(RegattaAndRaceIdentifier raceIdentifier, TimePoint timePoint) + public QuickRanksDTO computeQuickRanks(RegattaAndRaceIdentifier raceIdentifier, TimePoint timePoint) throws NoWindException { - List result = new ArrayList(); + final List result = new ArrayList<>(); + final List competitorDTOsInOrderOfWindwardDistanceTraveledFarthestFirst; TrackedRace trackedRace = getExistingTrackedRace(raceIdentifier); if (trackedRace != null) { final TimePoint actualTimePoint; @@ -2053,12 +2055,16 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } rank++; } + final Iterable competitorsInOrderOfWindwardDistanceTraveledFarthestFirst = getService().getCompetitorInOrderOfWindwardDistanceTraveledFarthestFirst(trackedRace, timePoint); + competitorDTOsInOrderOfWindwardDistanceTraveledFarthestFirst = convertToCompetitorDTOs(competitorsInOrderOfWindwardDistanceTraveledFarthestFirst); + } else { + competitorDTOsInOrderOfWindwardDistanceTraveledFarthestFirst = Collections.emptyList(); } - return result; + return new QuickRanksDTO(result, competitorDTOsInOrderOfWindwardDistanceTraveledFarthestFirst); } - private List getQuickRanks(RegattaAndRaceIdentifier raceIdentifier, Date date) throws NoWindException { - final List result; + private QuickRanksDTO getQuickRanks(RegattaAndRaceIdentifier raceIdentifier, Date date) throws NoWindException { + final QuickRanksDTO result; if (date == null) { result = quickRanksLiveCache.get(raceIdentifier); } else { @@ -2092,7 +2098,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S Map windTrackInfoDTOs = new HashMap(); result.windTrackInfoByWindSource = windTrackInfoDTOs; - for(WindSource windSource: trackedRace.getWindSources()) { + for (WindSource windSource: trackedRace.getWindSources()) { windTrackInfoDTOs.put(windSource, new WindTrackInfoDTO()); } windTrackInfoDTOs.put(new WindSourceImpl(WindSourceType.COMBINED), new WindTrackInfoDTO()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/CompactRaceMapDataDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/CompactRaceMapDataDTO.java index 5d70be2d170..f4496999ed2 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/CompactRaceMapDataDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/CompactRaceMapDataDTO.java @@ -5,10 +5,12 @@ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import com.google.gwt.user.client.rpc.IsSerializable; import com.sap.sailing.domain.common.dto.CompetitorDTO; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; +import com.sap.sse.common.Util; /** * A compact representation of a {@link RaceMapDataDTO} that represents competitors by their ID only instead of a @@ -25,23 +27,32 @@ public class CompactRaceMapDataDTO implements IsSerializable { private CoursePositionsDTO coursePositions; private List courseSidelines; private List quickRanks; + private LinkedHashMap competitorsInOrderOfWindwardDistanceTraveledFarthestFirstIdAsStringAndOneBasedLegNumber; private int simulationResultVersion; CompactRaceMapDataDTO() {} public CompactRaceMapDataDTO(Map> boatPositions, CoursePositionsDTO coursePositions, - List courseSidelines, List quickRanks, int simulationResultVersion) { + List courseSidelines, QuickRanksDTO quickRanks, int simulationResultVersion) { this.boatPositionsByCompetitorIdAsString = new HashMap>(); for (Map.Entry> e : boatPositions.entrySet()) { this.boatPositionsByCompetitorIdAsString.put(e.getKey().getIdAsString(), e.getValue()); } - this.quickRanks = new ArrayList(quickRanks == null ? 0 : quickRanks.size()); + this.quickRanks = new ArrayList(quickRanks == null ? 0 : Util.size(quickRanks.getQuickRanks())); + Map competitorIdAsStringToOneBasedLegNumber = new HashMap<>(); if (quickRanks != null) { - for (QuickRankDTO quickRank : quickRanks) { + for (QuickRankDTO quickRank : quickRanks.getQuickRanks()) { this.quickRanks.add(new CompactQuickRankDTO(quickRank.competitor.getIdAsString(), quickRank.rank, quickRank.legNumberOneBased)); + competitorIdAsStringToOneBasedLegNumber.put(quickRank.competitor.getIdAsString(), quickRank.legNumberOneBased); } } + this.competitorsInOrderOfWindwardDistanceTraveledFarthestFirstIdAsStringAndOneBasedLegNumber = new LinkedHashMap<>(); + for (CompetitorDTO competitorInOrderOfWindwardDistanceTraveled : quickRanks.getCompetitorsInOrderOfWindwardDistanceTraveledFarthestFirst()) { + this.competitorsInOrderOfWindwardDistanceTraveledFarthestFirstIdAsStringAndOneBasedLegNumber.put( + competitorInOrderOfWindwardDistanceTraveled.getIdAsString(), + competitorIdAsStringToOneBasedLegNumber.get(competitorInOrderOfWindwardDistanceTraveled.getIdAsString())); + } this.courseSidelines = courseSidelines; this.coursePositions = coursePositions; this.simulationResultVersion = simulationResultVersion; @@ -70,6 +81,13 @@ public class CompactRaceMapDataDTO implements IsSerializable { result.boatPositions.put(competitor, e.getValue()); } } + result.competitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber = new LinkedHashMap<>(); + for (Entry i : competitorsInOrderOfWindwardDistanceTraveledFarthestFirstIdAsStringAndOneBasedLegNumber.entrySet()) { + CompetitorDTO c = competitorsByIdAsString.get(i.getKey()); + if (c != null) { + result.competitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber.put(c, i.getValue()); + } + } result.simulationResultVersion = simulationResultVersion; return result; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RaceMapDataDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RaceMapDataDTO.java index 99b1c143aec..78c702ebf85 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RaceMapDataDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RaceMapDataDTO.java @@ -12,5 +12,6 @@ public class RaceMapDataDTO implements IsSerializable { public CoursePositionsDTO coursePositions; public List courseSidelines; public LinkedHashMap quickRanks; + public LinkedHashMap competitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber; public int simulationResultVersion; } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java index d6b9c3c0bbc..f0aa9d9f5d6 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java @@ -16,6 +16,7 @@ import java.util.concurrent.ConcurrentHashMap; import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLogStartTimeEvent; +import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CompetitorStore; import com.sap.sailing.domain.base.CourseArea; import com.sap.sailing.domain.base.DomainFactory; @@ -606,4 +607,6 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch ClassLoader getCombinedMasterDataClassLoader(); + Iterable getCompetitorInOrderOfWindwardDistanceTraveledFarthestFirst(TrackedRace trackedRace, TimePoint timePoint); + } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java index 484bfb7ab97..f552e85fe26 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java @@ -132,6 +132,7 @@ import com.sap.sailing.domain.racelog.RaceLogIdentifier; import com.sap.sailing.domain.racelog.RaceLogStore; import com.sap.sailing.domain.racelog.tracking.GPSFixStore; import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; +import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo; import com.sap.sailing.domain.ranking.RankingMetricConstructor; import com.sap.sailing.domain.regattalike.IsRegattaLike; import com.sap.sailing.domain.regattalike.LeaderboardThatHasRegattaLike; @@ -3161,4 +3162,14 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes setPolarDataService(null); } } + + @Override + public Iterable getCompetitorInOrderOfWindwardDistanceTraveledFarthestFirst(TrackedRace trackedRace, TimePoint timePoint) { + final RankingInfo rankingInfo = trackedRace.getRankingMetric().getRankingInfo(timePoint); + final List result = new ArrayList<>(); + Util.addAll(trackedRace.getRace().getCompetitors(), result); + result.sort((c1, c2) -> rankingInfo.getCompetitorRankingInfo().apply(c2).getWindwardDistanceSailed().compareTo( + rankingInfo.getCompetitorRankingInfo().apply(c1).getWindwardDistanceSailed())); + return result; + } } From 3089970d78f9cc4e773928ce181e8ad56e9c41a3 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Fri, 29 May 2015 08:21:57 +0200 Subject: [PATCH 47/72] Adapted current version of main.gss --- .../gwt/common/client/SharedResources.java | 11 ++++++ .../com/sap/sailing/gwt/home/main.gss | 33 +++++++++++++++++ .../client/resources/ThemeResources.java | 11 ++++++ .../sse/gwt/theme/client/resources/main.gss | 35 ++++++++++++++++++- 4 files changed, 89 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/SharedResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/SharedResources.java index ebc7a3526a9..56056fa0c74 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/SharedResources.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/SharedResources.java @@ -48,6 +48,17 @@ public interface SharedResources extends ClientBundle { String spacermedium(); String spacermediumbig(); String spacerbig(); + String spacermargin(); + String spacermargintopsmall(); + String spacermargintopmediumsmall(); + String spacermargintopmedium(); + String spacermargintopmediumbig(); + String spacermargintopbig(); + String spacermarginbottomsmall(); + String spacermarginbottommediumsmall(); + String spacermarginbottommedium(); + String spacermarginbottommediumbig(); + String spacermarginbottombig(); String stickyheader(); String slideto(); String slidetonav(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/main.gss b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/main.gss index c4676e7abbf..e09d28752bc 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/main.gss +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/main.gss @@ -429,6 +429,39 @@ figcaption { .spacerbig { height: 5.333333333333333em; } +.spacermargin { + font-size: inherit; +} +.spacermargintopsmall { + margin-top: 1em; +} +.spacermargintopmediumsmall { + margin-top: 1.333333333333333em; +} +.spacermargintopmedium { + margin-top: 2em; +} +.spacermargintopmediumbig { + margin-top: 4em; +} +.spacermargintopbig { + margin-top: 5.333333333333333em; +} +.spacermarginbottomsmall { + margin-bottom: 1em; +} +.spacermarginbottommediumsmall { + margin-bottom: 1.333333333333333em; +} +.spacermarginbottommedium { + margin-bottom: 2em; +} +.spacermarginbottommediumbig { + margin-bottom: 4em; +} +.spacermarginbottombig { + margin-bottom: 5.333333333333333em; +} .stickyheader { background: inherit; } diff --git a/java/com.sap.sse.gwt.theme/src/main/java/com/sap/sse/gwt/theme/client/resources/ThemeResources.java b/java/com.sap.sse.gwt.theme/src/main/java/com/sap/sse/gwt/theme/client/resources/ThemeResources.java index d31ec3e9c54..de02ba3ead6 100644 --- a/java/com.sap.sse.gwt.theme/src/main/java/com/sap/sse/gwt/theme/client/resources/ThemeResources.java +++ b/java/com.sap.sse.gwt.theme/src/main/java/com/sap/sse/gwt/theme/client/resources/ThemeResources.java @@ -48,6 +48,17 @@ public interface ThemeResources extends ClientBundle { String spacermedium(); String spacermediumbig(); String spacerbig(); + String spacermargin(); + String spacermargintopsmall(); + String spacermargintopmediumsmall(); + String spacermargintopmedium(); + String spacermargintopmediumbig(); + String spacermargintopbig(); + String spacermarginbottomsmall(); + String spacermarginbottommediumsmall(); + String spacermarginbottommedium(); + String spacermarginbottommediumbig(); + String spacermarginbottombig(); String stickyheader(); String slideto(); String slidetonav(); diff --git a/java/com.sap.sse.gwt.theme/src/main/java/com/sap/sse/gwt/theme/client/resources/main.gss b/java/com.sap.sse.gwt.theme/src/main/java/com/sap/sse/gwt/theme/client/resources/main.gss index 8e7fe2b07bf..e09d28752bc 100644 --- a/java/com.sap.sse.gwt.theme/src/main/java/com/sap/sse/gwt/theme/client/resources/main.gss +++ b/java/com.sap.sse.gwt.theme/src/main/java/com/sap/sse/gwt/theme/client/resources/main.gss @@ -44,7 +44,7 @@ h2 { font-size: 1.466666666666667em; font-weight: bold; color: #008fcc; - margin-top: 0; + margin-top: 0.7em; margin-bottom: 0.7em; } h3 { @@ -429,6 +429,39 @@ figcaption { .spacerbig { height: 5.333333333333333em; } +.spacermargin { + font-size: inherit; +} +.spacermargintopsmall { + margin-top: 1em; +} +.spacermargintopmediumsmall { + margin-top: 1.333333333333333em; +} +.spacermargintopmedium { + margin-top: 2em; +} +.spacermargintopmediumbig { + margin-top: 4em; +} +.spacermargintopbig { + margin-top: 5.333333333333333em; +} +.spacermarginbottomsmall { + margin-bottom: 1em; +} +.spacermarginbottommediumsmall { + margin-bottom: 1.333333333333333em; +} +.spacermarginbottommedium { + margin-bottom: 2em; +} +.spacermarginbottommediumbig { + margin-bottom: 4em; +} +.spacermarginbottombig { + margin-bottom: 5.333333333333333em; +} .stickyheader { background: inherit; } From 01f3c3050bec33eb577af1bf8b6e495d055b5244 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 29 May 2015 09:14:58 +0200 Subject: [PATCH 48/72] added missing file QuickRanksDTO --- .../sailing/gwt/ui/shared/QuickRanksDTO.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100755 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/QuickRanksDTO.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/QuickRanksDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/QuickRanksDTO.java new file mode 100755 index 00000000000..bff0c8c32d5 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/QuickRanksDTO.java @@ -0,0 +1,39 @@ +package com.sap.sailing.gwt.ui.shared; + +import com.sap.sailing.domain.common.dto.CompetitorDTO; + +/** + * Combines a list of {@link QuickRankDTO} objects telling about the (calculated, according to any handicap ranking metric + * in place)) ranks of the competitors with an information about the boat farthest ahead in the race. The latter is useful, + * e.g., to draw an advantage line on this boat leading the race without considering any handicap ranking metric. + * + * @author Axel Uhl (D043530) + * + */ +public class QuickRanksDTO { + /** + * Lists the competitors in the order of estimated calculated time when reaching the competitor farthest ahead. + * This is the prediction for the ultimate calculated ranking. + */ + private final Iterable quickRanksAfterCalculatedTime; + + /** + * Lists the competitors according to their windward distance traveled. The first boat (rank 1) is the + * competitor farthest ahead. + */ + private final Iterable competitorsInOrderOfWindwardDistanceTraveledFarthestFirst; + + public QuickRanksDTO(Iterable quickRanks, Iterable competitorsInOrderOfWindwardDistanceTraveledFarthestFirst) { + super(); + this.quickRanksAfterCalculatedTime = quickRanks; + this.competitorsInOrderOfWindwardDistanceTraveledFarthestFirst = competitorsInOrderOfWindwardDistanceTraveledFarthestFirst; + } + + public Iterable getQuickRanks() { + return quickRanksAfterCalculatedTime; + } + + public Iterable getCompetitorsInOrderOfWindwardDistanceTraveledFarthestFirst() { + return competitorsInOrderOfWindwardDistanceTraveledFarthestFirst; + } +} From 137c6cf9c9c944ceaadad28db4a3d3f715253c4a Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Fri, 29 May 2015 12:19:03 +0200 Subject: [PATCH 49/72] Adjusted RegattaOverview style to save vertical space --- .../client/RegattaRaceStatesComponent.java | 1 + .../client/RegattaRaceStatesTable.css | 187 +++++++++--------- .../RegattaRaceStatesTableResources.java | 46 ++--- 3 files changed, 123 insertions(+), 111 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java index 6aca3ff8098..9760e171076 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java @@ -569,6 +569,7 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component tooltip); } }; + flagColumn.setCellStyleNames(tableRes.cellTableStyle().flagColumn()); boatClass = new TextColumn() { @Override public String getValue(RegattaOverviewEntryDTO entryDTO) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesTable.css b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesTable.css index 7a8e30b3821..a6f1aec3b8e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesTable.css +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesTable.css @@ -1,90 +1,99 @@ -.cellTableWidget { - border-spacing: 0px; - font-size:16px; -} -.cellTableWidget a { - - text-decoration: underline; - cursor: pointer; -} - - -/** v-align images in the table header - * grey background for table header - */ -.cellTableHeader { - position: relative; - vertical-align: bottom; - background-color: #f2f2f2; - background-color: #fff; - padding: 20px 5px; - text-align: left; - border-bottom: 1px solid black; - text-shadow: none; - font-size: 16px; -} - -.cellTableHeader:FOCUS { - outline: none; -} - -.cellTableFirstColumnHeader { - -} - -.cellTableLastColumnHeader { - -} - -.cellTableHeader>span>img:first-child { - position: relative; - vertical-align: middle; -} - -.cellTableEvenRow { - background-color: #fafafa; -} - -.cellTableEvenRowCell { - border: none; - border-bottom: 1px solid #dedede; - padding: 20px 5px 20px 10px; - vertical-align: top; - -} - -.cellTableOddRow { - background-color: #fdfdfd; -} - -.cellTableOddRowCell { - border: none; - border-bottom: 1px solid #dedede; - padding: 20px 5px 20px 10px; - vertical-align: top; - -} - -.cellTableHoveredRow { - background-color: rgba(229, 242, 249, 0.5); - border-bottom: 1px solid #e5e5e5; -} - -.cellTableSelectedRow { - color: #000000; - background-color: rgba(229, 242, 249, 0.5); -} - -.cellTableSelectedRowCell { - border-top: 2px solid #21a0e4 !important; - border-bottom: 2px solid #21a0e4 !important; -} - -.cellTableRaceNameColumnHeader { - background-color: #e0e0e0; - padding: 5px 20px; -} - -.cellTableRaceNameColumn { - background-color: #e0e0e0 !important; +.cellTableWidget { + border-spacing: 0px; + font-size:16px; +} +.cellTableWidget a { + + text-decoration: underline; + cursor: pointer; +} + + +/** v-align images in the table header + * grey background for table header + */ +.cellTableHeader { + position: relative; + vertical-align: bottom; + background-color: #f2f2f2; + background-color: #fff; + padding: 20px 5px; + text-align: left; + border-bottom: 1px solid black; + text-shadow: none; + font-size: 16px; +} + +.cellTableHeader:FOCUS { + outline: none; +} + +.cellTableFirstColumnHeader { + +} + +.cellTableLastColumnHeader { + +} + +.cellTableHeader>span>img:first-child { + position: relative; + vertical-align: middle; +} + +.cellTableEvenRow { + background-color: #fafafa; +} + +.cellTableEvenRowCell { + border: none; + border-bottom: 1px solid #dedede; + padding: 20px 5px 20px 10px; + vertical-align: top; + +} + +.cellTableOddRow { + background-color: #fdfdfd; +} + +.cellTableOddRowCell { + border: none; + border-bottom: 1px solid #dedede; + padding: 20px 5px 20px 10px; + vertical-align: top; + +} + +.cellTableHoveredRow { + background-color: rgba(229, 242, 249, 0.5); + border-bottom: 1px solid #e5e5e5; +} + +.cellTableSelectedRow { + color: #000000; + background-color: rgba(229, 242, 249, 0.5); +} + +.cellTableSelectedRowCell { + border-top: 2px solid #21a0e4 !important; + border-bottom: 2px solid #21a0e4 !important; +} + +.cellTableRaceNameColumnHeader { + background-color: #e0e0e0; + padding: 5px 20px; +} + +.cellTableRaceNameColumn { + background-color: #e0e0e0 !important; +} + +.flagColumn { + padding-top: 0; + padding-bottom: 0; + vertical-align: middle; +} +.flagColumn>div { + display: inline-block; } \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesTableResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesTableResources.java index c702221bec3..0b01dfce1c1 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesTableResources.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesTableResources.java @@ -1,22 +1,24 @@ -package com.sap.sailing.gwt.regattaoverview.client; - -import com.google.gwt.user.cellview.client.CellTable; - -public interface RegattaRaceStatesTableResources extends CellTable.Resources { - interface AdminConsoleTableStyle extends CellTable.Style { - /** - * Applied to header cells of race columns - */ - String cellTableRaceNameColumnHeader(); - - /** - * Applied to the totals columns - */ - String cellTableRaceNameColumn(); - - } - - @Override - @Source({ CellTable.Style.DEFAULT_CSS, "RegattaRaceStatesTable.css" }) - AdminConsoleTableStyle cellTableStyle(); -} +package com.sap.sailing.gwt.regattaoverview.client; + +import com.google.gwt.user.cellview.client.CellTable; + +public interface RegattaRaceStatesTableResources extends CellTable.Resources { + interface AdminConsoleTableStyle extends CellTable.Style { + /** + * Applied to header cells of race columns + */ + String cellTableRaceNameColumnHeader(); + + /** + * Applied to the totals columns + */ + String cellTableRaceNameColumn(); + + String flagColumn(); + + } + + @Override + @Source({ CellTable.Style.DEFAULT_CSS, "RegattaRaceStatesTable.css" }) + AdminConsoleTableStyle cellTableStyle(); +} From c835c70275e143940948fe50eeaa5d590c36cd4d Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 29 May 2015 13:11:25 +0200 Subject: [PATCH 50/72] fix attempt for bug 2922: deadlock due to TrackedRaceImpl.getMarkPassing locking the competitor mark passing collection; the updateMarkPassing method locks competitor mark passings first, then the waypoint mark passings, while holding on to the competitor mark passing collection's lock. Therefore, acquiring the competitor mark passing collection's lock is more dangerous in "inner" methods that don't require more locks because callers may already hold on to the waypoint mark passing lock, causing a deadlock with updateMarkPassing. --- .../com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java index 6492f3de69c..81ba50a86d6 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java @@ -1322,12 +1322,12 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl @Override public MarkPassing getMarkPassing(Competitor competitor, Waypoint waypoint) { - final NavigableSet markPassings = getMarkPassings(competitor); + final Iterable markPassings = getMarkPassingsInOrder(waypoint); if (markPassings != null) { lockForRead(markPassings); try { for (MarkPassing markPassing : markPassings) { - if (markPassing.getWaypoint() == waypoint) { + if (markPassing.getCompetitor() == competitor) { return markPassing; } } From d46e71b2393bbb516be9f4d1c631da71f6f0aabd Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Fri, 29 May 2015 13:20:33 +0200 Subject: [PATCH 51/72] Optimized row height of RegattaOverview --- .../gwt/regattaoverview/client/RegattaRaceStatesTable.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesTable.css b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesTable.css index a6f1aec3b8e..77c87e9b86a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesTable.css +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesTable.css @@ -17,7 +17,7 @@ vertical-align: bottom; background-color: #f2f2f2; background-color: #fff; - padding: 20px 5px; + padding: 15px 5px; text-align: left; border-bottom: 1px solid black; text-shadow: none; @@ -48,7 +48,7 @@ .cellTableEvenRowCell { border: none; border-bottom: 1px solid #dedede; - padding: 20px 5px 20px 10px; + padding: 15px 5px 15px 10px; vertical-align: top; } @@ -60,7 +60,7 @@ .cellTableOddRowCell { border: none; border-bottom: 1px solid #dedede; - padding: 20px 5px 20px 10px; + padding: 15px 5px 15px 10px; vertical-align: top; } From 0dbfaba524e45c546424302751ab8a6910c48972 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 29 May 2015 14:17:58 +0200 Subject: [PATCH 52/72] fixed live time for getQuickRanks(); added several null checks for cases where competitors haven't started their legs yet --- .../domain/ranking/AbstractRankingMetric.java | 10 +++++-- .../TimeOnTimeAndDistanceRankingMetric.java | 30 +++++++++++-------- .../gwt/ui/server/SailingServiceImpl.java | 3 +- .../gwt/ui/shared/CompactRaceMapDataDTO.java | 12 ++++---- 4 files changed, 32 insertions(+), 23 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java index 767f2a8094f..30504b26178 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java @@ -161,13 +161,17 @@ public abstract class AbstractRankingMetric implements RankingMetric { final Duration result; final TrackedLegOfCompetitor tloc = getTrackedRace().getTrackedLeg(competitor, getTimePoint()); final Duration raceDurationAtTimePoint = getTrackedRace().getStartOfRace().until(getTimePoint()); - if (tloc.hasStartedLeg(getTimePoint())) { + if (tloc != null && tloc.hasStartedLeg(getTimePoint())) { final Competitor competitorFarthestAheadInLeg = getCompetitorFarthestAheadInLeg(leg, getTimePoint(), cache); final TrackedLegOfCompetitor tlocOfCompetitorFarthestAheadInLeg = tloc.getTrackedLeg().getTrackedLeg(competitorFarthestAheadInLeg); final Duration predictedDurationFromTimePointToReachFarthestAheadInLeg = getPredictedDurationToReachWindwardPositionOf( tloc, tlocOfCompetitorFarthestAheadInLeg, getTimePoint(), cache); - final Duration cDurationFromRaceStartToReachFarthestInLeg = raceDurationAtTimePoint.plus(predictedDurationFromTimePointToReachFarthestAheadInLeg); - result = cDurationFromRaceStartToReachFarthestInLeg; + if (predictedDurationFromTimePointToReachFarthestAheadInLeg == null) { + result = null; + } else { + final Duration cDurationFromRaceStartToReachFarthestInLeg = raceDurationAtTimePoint.plus(predictedDurationFromTimePointToReachFarthestAheadInLeg); + result = cDurationFromRaceStartToReachFarthestInLeg; + } } else { result = null; } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java index c341f8a3f11..2c76600b098 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java @@ -325,19 +325,23 @@ public class TimeOnTimeAndDistanceRankingMetric extends AbstractRankingMetric { result = null; } else { final Competitor farthestAheadOrEarliestLegFinisher = getCompetitorFarthestAheadInLeg(trackedLegOfCompetitor.getTrackedLeg(), timePoint, cache); - final TrackedLegOfCompetitor tlocOfFarthestAhead = trackedLegOfCompetitor.getTrackedLeg().getTrackedLeg(farthestAheadOrEarliestLegFinisher); - final boolean farthestAheadAlreadyFinishedLeg = tlocOfFarthestAhead.hasFinishedLeg(timePoint); - final Distance windwardDistanceFarthestTraveledUntilFinishingLeg = getWindwardDistanceTraveled(farthestAheadOrEarliestLegFinisher, - farthestAheadAlreadyFinishedLeg ? tlocOfFarthestAhead.getFinishTime() : timePoint, cache); - // Consider all competitors, regardless of whether they have started the leg or not; a competitor in a previous - // leg may well be the race leader. However, if a competitor has finished the leg already, use the finishing time - // point for that competitor. - // leader in the leg is now the competitor with the least corrected time to reach the competitor farthest ahead in the leg - final Competitor legLeader = rankingInfo.getLeaderInLegByCalculatedTime(trackedLegOfCompetitor.getTrackedLeg().getLeg(), cache); - result = getGapToCompetitorInOwnTime(trackedLegOfCompetitor.getCompetitor(), legLeader, - rankingInfo.getActualTimeFromRaceStartToReachFarthestAheadInLeg(trackedLegOfCompetitor.getCompetitor(), leg, cache), - rankingInfo.getActualTimeFromRaceStartToReachFarthestAheadInLeg(legLeader, leg, cache), - windwardDistanceFarthestTraveledUntilFinishingLeg); + if (farthestAheadOrEarliestLegFinisher == null) { + result = null; + } else { + final TrackedLegOfCompetitor tlocOfFarthestAhead = trackedLegOfCompetitor.getTrackedLeg().getTrackedLeg(farthestAheadOrEarliestLegFinisher); + final boolean farthestAheadAlreadyFinishedLeg = tlocOfFarthestAhead.hasFinishedLeg(timePoint); + final Distance windwardDistanceFarthestTraveledUntilFinishingLeg = getWindwardDistanceTraveled(farthestAheadOrEarliestLegFinisher, + farthestAheadAlreadyFinishedLeg ? tlocOfFarthestAhead.getFinishTime() : timePoint, cache); + // Consider all competitors, regardless of whether they have started the leg or not; a competitor in a previous + // leg may well be the race leader. However, if a competitor has finished the leg already, use the finishing time + // point for that competitor. + // leader in the leg is now the competitor with the least corrected time to reach the competitor farthest ahead in the leg + final Competitor legLeader = rankingInfo.getLeaderInLegByCalculatedTime(trackedLegOfCompetitor.getTrackedLeg().getLeg(), cache); + result = getGapToCompetitorInOwnTime(trackedLegOfCompetitor.getCompetitor(), legLeader, + rankingInfo.getActualTimeFromRaceStartToReachFarthestAheadInLeg(trackedLegOfCompetitor.getCompetitor(), leg, cache), + rankingInfo.getActualTimeFromRaceStartToReachFarthestAheadInLeg(legLeader, leg, cache), + windwardDistanceFarthestTraveledUntilFinishingLeg); + } } return result; } 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 dee60bce5c3..d844433ae36 100755 --- 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 @@ -2055,7 +2055,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } rank++; } - final Iterable competitorsInOrderOfWindwardDistanceTraveledFarthestFirst = getService().getCompetitorInOrderOfWindwardDistanceTraveledFarthestFirst(trackedRace, timePoint); + final Iterable competitorsInOrderOfWindwardDistanceTraveledFarthestFirst = getService() + .getCompetitorInOrderOfWindwardDistanceTraveledFarthestFirst(trackedRace, actualTimePoint); competitorDTOsInOrderOfWindwardDistanceTraveledFarthestFirst = convertToCompetitorDTOs(competitorsInOrderOfWindwardDistanceTraveledFarthestFirst); } else { competitorDTOsInOrderOfWindwardDistanceTraveledFarthestFirst = Collections.emptyList(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/CompactRaceMapDataDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/CompactRaceMapDataDTO.java index f4496999ed2..6b03faa0e68 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/CompactRaceMapDataDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/CompactRaceMapDataDTO.java @@ -39,6 +39,7 @@ public class CompactRaceMapDataDTO implements IsSerializable { this.boatPositionsByCompetitorIdAsString.put(e.getKey().getIdAsString(), e.getValue()); } this.quickRanks = new ArrayList(quickRanks == null ? 0 : Util.size(quickRanks.getQuickRanks())); + this.competitorsInOrderOfWindwardDistanceTraveledFarthestFirstIdAsStringAndOneBasedLegNumber = new LinkedHashMap<>(); Map competitorIdAsStringToOneBasedLegNumber = new HashMap<>(); if (quickRanks != null) { for (QuickRankDTO quickRank : quickRanks.getQuickRanks()) { @@ -46,12 +47,11 @@ public class CompactRaceMapDataDTO implements IsSerializable { quickRank.legNumberOneBased)); competitorIdAsStringToOneBasedLegNumber.put(quickRank.competitor.getIdAsString(), quickRank.legNumberOneBased); } - } - this.competitorsInOrderOfWindwardDistanceTraveledFarthestFirstIdAsStringAndOneBasedLegNumber = new LinkedHashMap<>(); - for (CompetitorDTO competitorInOrderOfWindwardDistanceTraveled : quickRanks.getCompetitorsInOrderOfWindwardDistanceTraveledFarthestFirst()) { - this.competitorsInOrderOfWindwardDistanceTraveledFarthestFirstIdAsStringAndOneBasedLegNumber.put( - competitorInOrderOfWindwardDistanceTraveled.getIdAsString(), - competitorIdAsStringToOneBasedLegNumber.get(competitorInOrderOfWindwardDistanceTraveled.getIdAsString())); + for (CompetitorDTO competitorInOrderOfWindwardDistanceTraveled : quickRanks.getCompetitorsInOrderOfWindwardDistanceTraveledFarthestFirst()) { + this.competitorsInOrderOfWindwardDistanceTraveledFarthestFirstIdAsStringAndOneBasedLegNumber.put( + competitorInOrderOfWindwardDistanceTraveled.getIdAsString(), + competitorIdAsStringToOneBasedLegNumber.get(competitorInOrderOfWindwardDistanceTraveled.getIdAsString())); + } } this.courseSidelines = courseSidelines; this.coursePositions = coursePositions; From 3f354f64175fd84eaa4343904e1302770c6ecde0 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 29 May 2015 14:22:35 +0200 Subject: [PATCH 53/72] fixed column list, fixing RACE_CALCULATED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD --- .../sap/sailing/domain/common/DetailType.java | 2 +- .../common/dto/LeaderboardEntryDTO.java | 20 +++++++++---------- .../impl/AbstractSimpleLeaderboardImpl.java | 4 ++-- .../SailingGWT sdm.launch | 5 +---- java/com.sap.sailing.gwt.ui/SailingGWT.launch | 2 +- .../gwt/ui/client/DetailTypeFormatter.java | 12 +++++------ .../gwt/ui/leaderboard/LeaderboardPanel.java | 18 ++++++++--------- 7 files changed, 30 insertions(+), 33 deletions(-) diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/DetailType.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/DetailType.java index c18af5db66b..cc8c7806dac 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/DetailType.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/DetailType.java @@ -43,7 +43,7 @@ public enum DetailType implements Serializable { RACE_TOTAL_POINTS(2, ASCENDING), REGATTA_TOTAL_POINTS(2, ASCENDING), REGATTA_TOTAL_POINTS_SUM(2, ASCENDING), RACE_RATIO_BETWEEN_TIME_SINCE_LAST_POSITION_FIX_AND_AVERAGE_SAMPLING_INTERVAL(1, ASCENDING), RACE_DISTANCE_TO_START_FIVE_SECONDS_BEFORE_RACE_START(1, ASCENDING), RACE_SPEED_OVER_GROUND_FIVE_SECONDS_BEFORE_START(2, DESCENDING), - RACE_CORRECTED_TIME_TRAVELED(0, ASCENDING), RACE_CORRECTED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD(0, ASCENDING), + RACE_CALCULATED_TIME_TRAVELED(0, ASCENDING), RACE_CALCULATED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD(0, ASCENDING), RACE_TIME_TRAVELED(0, ASCENDING), RACE_TIME_TRAVELED_UPWIND(0, ASCENDING), RACE_TIME_TRAVELED_DOWNWIND(0, ASCENDING), RACE_TIME_TRAVELED_REACHING(0, ASCENDING), DISTANCE_TO_START_LINE(0, ASCENDING), BEAT_ANGLE(0, ASCENDING), COURSE_OVER_GROUND_TRUE_DEGREES(0, ASCENDING); diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardEntryDTO.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardEntryDTO.java index daf3b667df6..7df1e2403a2 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardEntryDTO.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardEntryDTO.java @@ -104,14 +104,14 @@ public class LeaderboardEntryDTO implements Serializable { * The corrected time spent in the race; usually based on the current time and distance, calculated by the {@link RankingMetric}. * For one-design classes this equals the time spent in the race. */ - public Duration correctedTime; + public Duration calculatedTime; /** * The corrections applied to the time and distance sailed when the competitor would have reached the * competitor farthest ahead, based on average VMG on the current leg and equal performance to the boat * farthest ahead for all subsequent legs. */ - public Duration correctedTimeAtEstimatedArrivalAtCompetitorFarthestAhead; + public Duration calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead; /** * If null, no leg details are known yet, the race is not being tracked or the details @@ -142,9 +142,9 @@ public class LeaderboardEntryDTO implements Serializable { result = prime * result + ((gapToLeaderInOwnTime == null) ? 0 : gapToLeaderInOwnTime.hashCode()); result = prime * result - + ((correctedTime == null) ? 0 : correctedTime.hashCode()); + + ((calculatedTime == null) ? 0 : calculatedTime.hashCode()); result = prime * result - + ((correctedTimeAtEstimatedArrivalAtCompetitorFarthestAhead == null) ? 0 : correctedTimeAtEstimatedArrivalAtCompetitorFarthestAhead.hashCode()); + + ((calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead == null) ? 0 : calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead.hashCode()); result = prime * result + ((averageSignedCrossTrackErrorInMeters == null) ? 0 : averageSignedCrossTrackErrorInMeters.hashCode()); result = prime * result + (discarded ? 1231 : 1237); @@ -198,15 +198,15 @@ public class LeaderboardEntryDTO implements Serializable { return false; } else if (!gapToLeaderInOwnTime.equals(other.gapToLeaderInOwnTime)) return false; - if (correctedTime == null) { - if (other.correctedTime != null) + if (calculatedTime == null) { + if (other.calculatedTime != null) return false; - } else if (!correctedTime.equals(other.correctedTime)) + } else if (!calculatedTime.equals(other.calculatedTime)) return false; - if (correctedTimeAtEstimatedArrivalAtCompetitorFarthestAhead == null) { - if (other.correctedTimeAtEstimatedArrivalAtCompetitorFarthestAhead != null) + if (calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead == null) { + if (other.calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead != null) return false; - } else if (!correctedTimeAtEstimatedArrivalAtCompetitorFarthestAhead.equals(other.correctedTimeAtEstimatedArrivalAtCompetitorFarthestAhead)) + } else if (!calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead.equals(other.calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead)) return false; if (averageAbsoluteCrossTrackErrorInMeters == null) { if (other.averageAbsoluteCrossTrackErrorInMeters != null) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java index 8c67eda8eef..9f545a222a3 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java @@ -1399,8 +1399,8 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race : raceDetails.getAverageAbsoluteCrossTrackError().getMeters(); entryDTO.averageSignedCrossTrackErrorInMeters = raceDetails.getAverageSignedCrossTrackError() == null ? null : raceDetails.getAverageSignedCrossTrackError().getMeters(); - entryDTO.correctedTime = raceDetails.getCorrectedTime(); - entryDTO.correctedTimeAtEstimatedArrivalAtCompetitorFarthestAhead = raceDetails.getCorrectedTimeAtEstimatedArrivalAtCompetitorFarthestAhead(); + entryDTO.calculatedTime = raceDetails.getCorrectedTime(); + entryDTO.calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead = raceDetails.getCorrectedTimeAtEstimatedArrivalAtCompetitorFarthestAhead(); entryDTO.gapToLeaderInOwnTime = raceDetails.getGapToLeaderInOwnTime(); final TimePoint startOfRace = trackedRace.getStartOfRace(); if (startOfRace != null) { diff --git a/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch b/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch index 92a6a72d15c..677d09971e9 100755 --- a/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch +++ b/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch @@ -4,9 +4,6 @@ - - - @@ -59,7 +56,7 @@ - + diff --git a/java/com.sap.sailing.gwt.ui/SailingGWT.launch b/java/com.sap.sailing.gwt.ui/SailingGWT.launch index f08010aaad9..69c31ce2fe9 100755 --- a/java/com.sap.sailing.gwt.ui/SailingGWT.launch +++ b/java/com.sap.sailing.gwt.ui/SailingGWT.launch @@ -69,7 +69,7 @@ - + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/DetailTypeFormatter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/DetailTypeFormatter.java index 3550db359ce..45df1c68a12 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/DetailTypeFormatter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/DetailTypeFormatter.java @@ -128,9 +128,9 @@ public class DetailTypeFormatter { return stringMessages.speedOverGroundFiveSecondsBeforeStart(); case RACE_TIME_TRAVELED: return stringMessages.time(); - case RACE_CORRECTED_TIME_TRAVELED: + case RACE_CALCULATED_TIME_TRAVELED: return stringMessages.calculatedTimeTraveled(); - case RACE_CORRECTED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD: + case RACE_CALCULATED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD: return stringMessages.raceCalculatedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSeconds(); case RACE_TIME_TRAVELED_DOWNWIND: return stringMessages.timeDownwind(); @@ -200,13 +200,13 @@ public class DetailTypeFormatter { case ESTIMATED_TIME_TO_NEXT_WAYPOINT_IN_SECONDS: case TIME_TRAVELED: case CORRECTED_TIME_TRAVELED: - case RACE_CORRECTED_TIME_TRAVELED: + case RACE_CALCULATED_TIME_TRAVELED: case RACE_TIME_TRAVELED: case RACE_TIME_TRAVELED_DOWNWIND: case RACE_TIME_TRAVELED_REACHING: case RACE_TIME_TRAVELED_UPWIND: case TIME_BETWEEN_RACE_START_AND_COMPETITOR_START: - case RACE_CORRECTED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD: + case RACE_CALCULATED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD: return stringMessages.secondsUnit(); case TIME_ON_DISTANCE_ALLOWANCE_IN_SECONDS_PER_NAUTICAL_MILE: @@ -326,9 +326,9 @@ public class DetailTypeFormatter { return stringMessages.raceDistanceTraveledIncludingGateStartTooltip(); case RACE_GAP_TO_LEADER_IN_SECONDS: return stringMessages.gapToLeaderInSecondsTooltip(); - case RACE_CORRECTED_TIME_TRAVELED: + case RACE_CALCULATED_TIME_TRAVELED: return stringMessages.calculatedTimeTraveledTooltip(); - case RACE_CORRECTED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD: + case RACE_CALCULATED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD: return stringMessages.raceCalculatedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSecondsTooltip(); case RACE_RANK: return stringMessages.rankTooltip(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java index 01a598f57a8..b6004fbcc90 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java @@ -861,8 +861,8 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS return new DetailType[] { DetailType.RACE_GAP_TO_LEADER_IN_SECONDS, DetailType.RACE_AVERAGE_SPEED_OVER_GROUND_IN_KNOTS, DetailType.RACE_DISTANCE_TRAVELED, DetailType.RACE_DISTANCE_TRAVELED_INCLUDING_GATE_START, - DetailType.RACE_TIME_TRAVELED, DetailType.RACE_CORRECTED_TIME_TRAVELED, - DetailType.RACE_CORRECTED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD, + DetailType.RACE_TIME_TRAVELED, DetailType.RACE_CALCULATED_TIME_TRAVELED, + DetailType.RACE_CALCULATED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD, DetailType.RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS, DetailType.RACE_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD_IN_METERS, DetailType.NUMBER_OF_MANEUVERS, DetailType.DISPLAY_LEGS, DetailType.CURRENT_LEG, DetailType.RACE_AVERAGE_ABSOLUTE_CROSS_TRACK_ERROR_IN_METERS, @@ -977,11 +977,11 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS result.put(DetailType.RACE_TIME_TRAVELED, new TimeTraveledRaceColumn(getLeaderboardPanel(), this, stringMessages, LEG_COLUMN_HEADER_STYLE, LEG_COLUMN_STYLE, LEG_DETAIL_COLUMN_HEADER_STYLE, LEG_DETAIL_COLUMN_STYLE)); - result.put(DetailType.RACE_CORRECTED_TIME_TRAVELED, - new FormattedDoubleDetailTypeColumn(DetailType.RACE_CORRECTED_TIME_TRAVELED, new RaceCorrectedTimeTraveledInSeconds(), + result.put(DetailType.RACE_CALCULATED_TIME_TRAVELED, + new FormattedDoubleDetailTypeColumn(DetailType.RACE_CALCULATED_TIME_TRAVELED, new RaceCorrectedTimeTraveledInSeconds(), LEG_COLUMN_HEADER_STYLE, LEG_COLUMN_STYLE, LeaderboardPanel.this)); - result.put(DetailType.RACE_CORRECTED_TIME_TRAVELED, new FormattedDoubleDetailTypeColumn( - DetailType.RACE_CORRECTED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD, + result.put(DetailType.RACE_CALCULATED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD, new FormattedDoubleDetailTypeColumn( + DetailType.RACE_CALCULATED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD, new RaceCorrectedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSeconds(), LEG_COLUMN_HEADER_STYLE, LEG_COLUMN_STYLE, LeaderboardPanel.this)); return result; @@ -1285,7 +1285,7 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS Double result = null; LeaderboardEntryDTO fieldsForRace = row.fieldsByRaceColumnName.get(getRaceColumnName()); if (fieldsForRace != null) { - result = fieldsForRace.correctedTime == null ? null : fieldsForRace.correctedTime.asSeconds(); + result = fieldsForRace.calculatedTime == null ? null : fieldsForRace.calculatedTime.asSeconds(); } return result; } @@ -1297,8 +1297,8 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS Double result = null; LeaderboardEntryDTO fieldsForRace = row.fieldsByRaceColumnName.get(getRaceColumnName()); if (fieldsForRace != null) { - result = fieldsForRace.correctedTimeAtEstimatedArrivalAtCompetitorFarthestAhead == null ? null - : fieldsForRace.correctedTimeAtEstimatedArrivalAtCompetitorFarthestAhead.asSeconds(); + result = fieldsForRace.calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead == null ? null + : fieldsForRace.calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead.asSeconds(); } return result; } From 6a3c4e1bae45539451cda2545b349a7cff827a1b Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 29 May 2015 14:47:22 +0200 Subject: [PATCH 54/72] added more null safety for unstarted races Conflicts: mobile/github-advrecyclerview_lib/.settings/org.eclipse.jdt.core.prefs --- .../domain/ranking/AbstractRankingMetric.java | 2 +- .../TimeOnTimeAndDistanceRankingMetric.java | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java index 30504b26178..ed0ef1b9d7d 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java @@ -224,7 +224,7 @@ public abstract class AbstractRankingMetric implements RankingMetric { (c1, c2) -> durationComparatorNullsLast.compare( competitorRankingInfo.get(c1).getCorrectedTimeAtEstimatedArrivalAtCompetitorFarthestAhead(), competitorRankingInfo.get(c2).getCorrectedTimeAtEstimatedArrivalAtCompetitorFarthestAhead())). - findFirst().get(); + findFirst().orElse(null); } @Override diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java index 2c76600b098..e4c3e8bd728 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java @@ -252,13 +252,19 @@ public class TimeOnTimeAndDistanceRankingMetric extends AbstractRankingMetric { */ @Override public Duration getGapToLeaderInOwnTime(RankingMetric.RankingInfo rankingInfo, Competitor competitor, WindLegTypeAndLegBearingCache cache) { + final Duration result; // actual times and common distance: final Competitor leaderByCorrectedEstimatedTimeToCompetitorFarthestAhead = rankingInfo.getLeaderByCorrectedEstimatedTimeToCompetitorFarthestAhead(); - final Duration t_k = rankingInfo.getCompetitorRankingInfo().apply(leaderByCorrectedEstimatedTimeToCompetitorFarthestAhead). - getEstimatedActualDurationFromRaceStartToCompetitorFarthestAhead(); - final Duration t_i = rankingInfo.getCompetitorRankingInfo().apply(competitor).getEstimatedActualDurationFromRaceStartToCompetitorFarthestAhead(); - final Distance d = rankingInfo.getCompetitorRankingInfo().apply(rankingInfo.getCompetitorFarthestAhead()).getWindwardDistanceSailed(); - return getGapToCompetitorInOwnTime(competitor, leaderByCorrectedEstimatedTimeToCompetitorFarthestAhead, t_i, t_k, d); + if (leaderByCorrectedEstimatedTimeToCompetitorFarthestAhead == null) { + result = null; + } else { + final Duration t_k = rankingInfo.getCompetitorRankingInfo().apply(leaderByCorrectedEstimatedTimeToCompetitorFarthestAhead). + getEstimatedActualDurationFromRaceStartToCompetitorFarthestAhead(); + final Duration t_i = rankingInfo.getCompetitorRankingInfo().apply(competitor).getEstimatedActualDurationFromRaceStartToCompetitorFarthestAhead(); + final Distance d = rankingInfo.getCompetitorRankingInfo().apply(rankingInfo.getCompetitorFarthestAhead()).getWindwardDistanceSailed(); + result = getGapToCompetitorInOwnTime(competitor, leaderByCorrectedEstimatedTimeToCompetitorFarthestAhead, t_i, t_k, d); + } + return result; } /** From 0c7a5acf66cc06ccd240c04c64f5957b874e44ab Mon Sep 17 00:00:00 2001 From: "Christopher Ronnewinkel (D036654)" Date: Fri, 29 May 2015 15:16:28 +0200 Subject: [PATCH 55/72] formatting of simulation-legend; --- java/com.sap.sailing.gwt.ui/RaceBoard.css | 12 +++++++++++- .../gwt/ui/client/shared/racemap/RaceMap.java | 2 +- .../gwt/ui/shared/racemap/RaceSimulationOverlay.java | 4 ++-- .../gwt/ui/simulator/PathLegendCanvasOverlay.java | 2 +- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/RaceBoard.css b/java/com.sap.sailing.gwt.ui/RaceBoard.css index 7bd795faf0c..38d843046f5 100644 --- a/java/com.sap.sailing.gwt.ui/RaceBoard.css +++ b/java/com.sap.sailing.gwt.ui/RaceBoard.css @@ -66,11 +66,21 @@ table { padding-left: 10px; } -.MapSimulationLegendParentDiv { +.TrueNorthIndicatorPanelParentDiv { padding-top: 10px; padding-left: 10px; } +.MapSimulationLegendParentDiv { + padding-bottom: 10px; + padding-left: 10px; + pointer-events: none; +} + +.MapSimulationLegend { + pointer-events: all; +} + .RaceMap-HeaderPanel { height: 60px; width: 100%; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java index 3dae1691e7e..726af3f8829 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java @@ -504,7 +504,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe map.setControls(ControlPosition.LEFT_TOP, combinedWindPanel); combinedWindPanel.getParent().addStyleName("CombinedWindPanelParentDiv"); map.setControls(ControlPosition.LEFT_TOP, trueNorthIndicatorPanel); - trueNorthIndicatorPanel.getParent().addStyleName("CombinedWindPanelParentDiv"); + trueNorthIndicatorPanel.getParent().addStyleName("TrueNorthIndicatorPanelParentDiv"); RaceMap.this.raceMapImageManager.loadMapIcons(map); map.setSize("100%", "100%"); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/RaceSimulationOverlay.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/RaceSimulationOverlay.java index 8bbec2b38fb..4708aec29fa 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/RaceSimulationOverlay.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/RaceSimulationOverlay.java @@ -41,7 +41,7 @@ public class RaceSimulationOverlay extends FullCanvasOverlay { public static final String GET_SIMULATION_CATEGORY = "getSimulation"; private final String textColor = "Black"; - private final String textFont = "10pt OpenSansRegular"; + private final String textFont = "10pt 'Open Sans'"; private String algorithmTimedOutText = "out-of-bounds"; private String mixedLegText = "ambiguous wind"; private int xOffset = 0; @@ -115,7 +115,7 @@ public class RaceSimulationOverlay extends FullCanvasOverlay { new SettingsDialog(component, stringMessages).show(); } });*/ - map.setControls(ControlPosition.LEFT_TOP, simulationLegend); + map.setControls(ControlPosition.RIGHT_BOTTOM, simulationLegend); simulationLegend.getParent().addStyleName("MapSimulationLegendParentDiv"); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/simulator/PathLegendCanvasOverlay.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/simulator/PathLegendCanvasOverlay.java index 39c00a6c558..43b0aa7834d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/simulator/PathLegendCanvasOverlay.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/simulator/PathLegendCanvasOverlay.java @@ -39,7 +39,7 @@ public class PathLegendCanvasOverlay extends FullCanvasOverlay { private double rectHeight = 20; private String textColor = "Black"; - private String textFont = "10pt OpenSansRegular"; + private String textFont = "10pt 'Open Sans'"; private String algorithmTimedOutText = "out-of-bounds"; private String mixedLegText = "ambiguous wind"; From 3ffd736edf610b09a78740026c1a75a92e24f233 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 29 May 2015 15:22:35 +0200 Subject: [PATCH 56/72] fixed case where a competitor was identified as farthest ahead but hasn't started a leg for which a comparator is requested --- .../ranking/TimeOnTimeAndDistanceRankingMetric.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java index e4c3e8bd728..bc893cd3516 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java @@ -104,8 +104,10 @@ public class TimeOnTimeAndDistanceRankingMetric extends AbstractRankingMetric { // competitors that have not yet started the leg will get a duration based on Long.MAX_VALUE final Map correctedTimesToReachFastestBoatsPositionAtTimePointOrEndOfLegMeasuredFromStartOfRace = new HashMap<>(); final Competitor fastestCompetitorInLeg = getCompetitorFarthestAheadInLeg(trackedLeg, timePoint, cache); + final boolean fastestCompetitorHasStartedLeg; if (fastestCompetitorInLeg != null) { final TrackedLegOfCompetitor trackedLegOfFastestCompetitorInLeg = trackedLeg.getTrackedLeg(fastestCompetitorInLeg); + fastestCompetitorHasStartedLeg = trackedLegOfFastestCompetitorInLeg.hasStartedLeg(timePoint); final Distance totalWindwardDistanceLegLeaderTraveledUpToTimePointOrLegEnd; final TimePoint startOfRace = getTrackedRace().getStartOfRace(); final Position positionOfFastestBoatInLegAtTimePointOrLegEnd; @@ -152,10 +154,12 @@ public class TimeOnTimeAndDistanceRankingMetric extends AbstractRankingMetric { } correctedTimesToReachFastestBoatsPositionAtTimePointOrEndOfLegMeasuredFromStartOfRace.put(competitor, correctedTime); } + } else { + fastestCompetitorHasStartedLeg = false; } - return (tloc1, tloc2) -> fastestCompetitorInLeg==null ? 0 : + return (tloc1, tloc2) -> fastestCompetitorHasStartedLeg ? correctedTimesToReachFastestBoatsPositionAtTimePointOrEndOfLegMeasuredFromStartOfRace.get(tloc1.getCompetitor()). - compareTo(correctedTimesToReachFastestBoatsPositionAtTimePointOrEndOfLegMeasuredFromStartOfRace.get(tloc2.getCompetitor())); + compareTo(correctedTimesToReachFastestBoatsPositionAtTimePointOrEndOfLegMeasuredFromStartOfRace.get(tloc2.getCompetitor())) : 0; } @Override From 1cfcfba100ca191f31521071342b82e5e773e569 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 29 May 2015 17:04:15 +0200 Subject: [PATCH 57/72] renamed classes for calculated times from "Corrected" to "Calculated" --- java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch | 14 +------------- java/com.sap.sailing.gwt.ui/SailingGWT.launch | 2 +- .../gwt/ui/leaderboard/LeaderboardPanel.java | 4 ++-- 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch b/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch index 7d6fc297515..3829ba7e648 100755 --- a/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch +++ b/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch @@ -4,18 +4,6 @@ - - - - - - - - - - - - @@ -68,7 +56,7 @@ - + diff --git a/java/com.sap.sailing.gwt.ui/SailingGWT.launch b/java/com.sap.sailing.gwt.ui/SailingGWT.launch index ae72a466d25..417fbc4052f 100755 --- a/java/com.sap.sailing.gwt.ui/SailingGWT.launch +++ b/java/com.sap.sailing.gwt.ui/SailingGWT.launch @@ -69,7 +69,7 @@ - + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java index b6004fbcc90..a6f097230f7 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java @@ -982,7 +982,7 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS LEG_COLUMN_HEADER_STYLE, LEG_COLUMN_STYLE, LeaderboardPanel.this)); result.put(DetailType.RACE_CALCULATED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD, new FormattedDoubleDetailTypeColumn( DetailType.RACE_CALCULATED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD, - new RaceCorrectedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSeconds(), + new RaceCalculatedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSeconds(), LEG_COLUMN_HEADER_STYLE, LEG_COLUMN_STYLE, LeaderboardPanel.this)); return result; } @@ -1291,7 +1291,7 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS } } - private class RaceCorrectedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSeconds implements LegDetailField { + private class RaceCalculatedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSeconds implements LegDetailField { @Override public Double get(LeaderboardRowDTO row) { Double result = null; From 62eb098b0b1dc081213164016174a15267326107 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 29 May 2015 17:11:44 +0200 Subject: [PATCH 58/72] fixed another name from "Corrected" to "Calculated" --- .../com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java index a6f097230f7..b7221912f0e 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java @@ -978,7 +978,7 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS stringMessages, LEG_COLUMN_HEADER_STYLE, LEG_COLUMN_STYLE, LEG_DETAIL_COLUMN_HEADER_STYLE, LEG_DETAIL_COLUMN_STYLE)); result.put(DetailType.RACE_CALCULATED_TIME_TRAVELED, - new FormattedDoubleDetailTypeColumn(DetailType.RACE_CALCULATED_TIME_TRAVELED, new RaceCorrectedTimeTraveledInSeconds(), + new FormattedDoubleDetailTypeColumn(DetailType.RACE_CALCULATED_TIME_TRAVELED, new RaceCalculatedTimeTraveledInSeconds(), LEG_COLUMN_HEADER_STYLE, LEG_COLUMN_STYLE, LeaderboardPanel.this)); result.put(DetailType.RACE_CALCULATED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD, new FormattedDoubleDetailTypeColumn( DetailType.RACE_CALCULATED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD, @@ -1279,7 +1279,7 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS } } - private class RaceCorrectedTimeTraveledInSeconds implements LegDetailField { + private class RaceCalculatedTimeTraveledInSeconds implements LegDetailField { @Override public Double get(LeaderboardRowDTO row) { Double result = null; From 80c8e3be9b79031da9ca711fdf9b6149b6851260 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 29 May 2015 17:12:28 +0200 Subject: [PATCH 59/72] fixed SailingGWT launches to design2015 branch's state --- .../SailingGWT sdm.launch | 124 +++++++-------- java/com.sap.sailing.gwt.ui/SailingGWT.launch | 150 +++++++++--------- 2 files changed, 137 insertions(+), 137 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch b/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch index 3829ba7e648..d3056dba67a 100755 --- a/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch +++ b/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch @@ -1,62 +1,62 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.gwt.ui/SailingGWT.launch b/java/com.sap.sailing.gwt.ui/SailingGWT.launch index 417fbc4052f..7dd136f9a96 100755 --- a/java/com.sap.sailing.gwt.ui/SailingGWT.launch +++ b/java/com.sap.sailing.gwt.ui/SailingGWT.launch @@ -1,75 +1,75 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 56ac918faf8aabb76958b4acb76429f7ef9ceb4c Mon Sep 17 00:00:00 2001 From: fmittag Date: Fri, 29 May 2015 18:27:38 +0300 Subject: [PATCH 60/72] fixed missing utf-8 encoding of 4 race committee app servlets --- .../sailing/server/gateway/impl/rc/CourseJsonExportServlet.java | 2 +- .../server/gateway/impl/rc/MarkPositionsJsonExportServlet.java | 2 +- .../sailing/server/gateway/impl/rc/MarksJsonExportServlet.java | 2 +- .../server/gateway/impl/rc/RaceGroupJsonExportServlet.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/CourseJsonExportServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/CourseJsonExportServlet.java index f75a4505233..f0db237c5a2 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/CourseJsonExportServlet.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/CourseJsonExportServlet.java @@ -87,7 +87,7 @@ public class CourseJsonExportServlet extends AbstractJsonHttpServlet { result = new JSONObject(); } + setJsonResponseHeader(response); result.writeJSONString(response.getWriter()); - response.setContentType("application/json"); } } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/MarkPositionsJsonExportServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/MarkPositionsJsonExportServlet.java index ff5cf988a06..04912c301cf 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/MarkPositionsJsonExportServlet.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/MarkPositionsJsonExportServlet.java @@ -98,8 +98,8 @@ public class MarkPositionsJsonExportServlet extends AbstractJsonHttpServlet { } } + setJsonResponseHeader(response); result.writeJSONString(response.getWriter()); - response.setContentType("application/json"); } @SuppressWarnings("unused") //unused since course area has no position yet diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/MarksJsonExportServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/MarksJsonExportServlet.java index 189084e79e5..8b108f5c4fb 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/MarksJsonExportServlet.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/MarksJsonExportServlet.java @@ -80,8 +80,8 @@ public class MarksJsonExportServlet extends AbstractJsonHttpServlet { } } + setJsonResponseHeader(response); result.writeJSONString(response.getWriter()); - response.setContentType("application/json"); } private UUID toUUID(String value) { diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/RaceGroupJsonExportServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/RaceGroupJsonExportServlet.java index 024f7890e7f..91487d6bc84 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/RaceGroupJsonExportServlet.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/RaceGroupJsonExportServlet.java @@ -78,8 +78,8 @@ public class RaceGroupJsonExportServlet extends AbstractJsonHttpServlet { } } + setJsonResponseHeader(response); result.writeJSONString(response.getWriter()); - response.setContentType("application/json"); } private UUID toUUID(String value) { From d19b8531525d20c543ff78dd5c8a086c507c9d29 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 29 May 2015 17:27:40 +0200 Subject: [PATCH 61/72] fixed SailingGWT sdm.launch regarding regatta overview --- .../domain/ranking/AbstractRankingMetric.java | 6 +- .../ORCPerformanceCurveRankingMetric.java | 2 +- .../ranking/OneDesignRankingMetric.java | 2 +- .../TimeOnTimeAndDistanceRankingMetric.java | 6 +- .../SailingGWT sdm.launch | 139 ++++++++++-------- 5 files changed, 85 insertions(+), 70 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java index ed0ef1b9d7d..9fc41899bfd 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java @@ -313,14 +313,14 @@ public abstract class AbstractRankingMetric implements RankingMetric { final Duration totalEstimatedDurationSinceRaceStartToCompetitorFarthestAhead = predictedDurationToReachWindwardPositionOfCompetitorFarthestAhead == null ? null : actualRaceDuration.plus(predictedDurationToReachWindwardPositionOfCompetitorFarthestAhead); final Duration correctedEstimatedTimeWhenReachingCompetitorFarthestAhead = totalEstimatedDurationSinceRaceStartToCompetitorFarthestAhead == null ? null - : getCorrectedTime( + : getCalculatedTime( competitor, () -> getTrackedRace().getTrackedLeg(competitorFarthestAhead, timePoint).getLeg(), () -> getTrackedRace().getTrack(competitorFarthestAhead).getEstimatedPosition( timePoint, /* extrapolate */true), totalEstimatedDurationSinceRaceStartToCompetitorFarthestAhead, totalWindwardDistanceTraveled); - final Duration correctedTime = getCorrectedTime(competitor, + final Duration correctedTime = getCalculatedTime(competitor, () -> getTrackedRace().getCurrentLeg(competitor, timePoint).getLeg(), () -> getTrackedRace() .getTrack(competitor).getEstimatedPosition(timePoint, /* extrapolated */true), actualRaceDuration, totalWindwardDistanceTraveled); @@ -356,7 +356,7 @@ public abstract class AbstractRankingMetric implements RankingMetric { * competitor has sailed. As others may not need it at all, the parameter is declared as a * {@link Supplier} which delays evaluation until it is needed or avoids it altogether. */ - protected abstract Duration getCorrectedTime(Competitor who, Supplier leg, + protected abstract Duration getCalculatedTime(Competitor who, Supplier leg, Supplier estimatedPosition, Duration totalDurationSinceRaceStart, Distance totalWindwardDistanceTraveled); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/ORCPerformanceCurveRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/ORCPerformanceCurveRankingMetric.java index 6f06916ceba..1b8dfe31edc 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/ORCPerformanceCurveRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/ORCPerformanceCurveRankingMetric.java @@ -51,7 +51,7 @@ public class ORCPerformanceCurveRankingMetric extends AbstractRankingMetric { } @Override - protected Duration getCorrectedTime(Competitor who, Supplier leg, Supplier estimatedPosition, + protected Duration getCalculatedTime(Competitor who, Supplier leg, Supplier estimatedPosition, Duration totalDurationSinceRaceStart, Distance totalWindwardDistanceTraveled) { // TODO Auto-generated method stub return null; diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/OneDesignRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/OneDesignRankingMetric.java index e776d9ae64f..6971565d580 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/OneDesignRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/OneDesignRankingMetric.java @@ -62,7 +62,7 @@ public class OneDesignRankingMetric extends AbstractRankingMetric { } @Override - protected Duration getCorrectedTime(Competitor who, Supplier leg, Supplier estimatedPosition, + protected Duration getCalculatedTime(Competitor who, Supplier leg, Supplier estimatedPosition, Duration totalDurationSinceRaceStart, Distance totalWindwardDistanceTraveled) { return totalDurationSinceRaceStart; } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java index bc893cd3516..a2fad4f4589 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java @@ -144,7 +144,7 @@ public class TimeOnTimeAndDistanceRankingMetric extends AbstractRankingMetric { final Duration timeToReachFastest = getPredictedDurationToEndOfLegOrTo(timePoint, competitorLeg, trackedLegOfFastestCompetitorInLeg, cache); final Duration totalDurationSinceRaceStart = startOfRace.until(timePoint).plus(timeToReachFastest); - correctedTime = getCorrectedTime(competitor, () -> trackedLeg.getLeg(), + correctedTime = getCalculatedTime(competitor, () -> trackedLeg.getLeg(), () -> positionOfFastestBoatInLegAtTimePointOrLegEnd, totalDurationSinceRaceStart, totalWindwardDistanceLegLeaderTraveledUpToTimePointOrLegEnd); } else { // competitor hasn't started the leg yet; they all get MAX_VALUE as the corrected duration, @@ -166,7 +166,7 @@ public class TimeOnTimeAndDistanceRankingMetric extends AbstractRankingMetric { public Duration getCorrectedTime(Competitor competitor, TimePoint timePoint, WindLegTypeAndLegBearingCache cache) { final Duration timeActuallySpent = getActualTimeSinceStartOfRace(competitor, timePoint); final Distance windwardDistanceSailed = getWindwardDistanceTraveled(competitor, timePoint, cache); - return getCorrectedTime(competitor, ()->getTrackedRace().getCurrentLeg(competitor, timePoint).getLeg(), + return getCalculatedTime(competitor, ()->getTrackedRace().getCurrentLeg(competitor, timePoint).getLeg(), ()->getTrackedRace().getTrack(competitor).getEstimatedPosition(timePoint, /* extrapolate */true), timeActuallySpent, windwardDistanceSailed); } @@ -180,7 +180,7 @@ public class TimeOnTimeAndDistanceRankingMetric extends AbstractRankingMetric { } @Override - protected Duration getCorrectedTime(Competitor who, Supplier leg, Supplier estimatedPosition, + protected Duration getCalculatedTime(Competitor who, Supplier leg, Supplier estimatedPosition, Duration totalDurationSinceRaceStart, Distance totalWindwardDistanceTraveled) { final Duration timeOnDistanceFactorInSecondsPerNauticalMile = getTimeOnDistanceFactorInSecondsPerNauticalMile(who); return totalDurationSinceRaceStart == null ? null : diff --git a/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch b/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch index d3056dba67a..1998d3bf97e 100755 --- a/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch +++ b/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch @@ -1,62 +1,77 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From d7a3fca6eb27b135b636d022cd18f180674f49b0 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 29 May 2015 17:54:56 +0200 Subject: [PATCH 62/72] moved assertion where it belongs: don't compare windward distances when one competitor has already finished the leg; the marks may move, hence giving different windward distances for different time points for the same leg --- .../com/sap/sailing/domain/ranking/AbstractRankingMetric.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java index 9fc41899bfd..e52ffc1a773 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java @@ -493,8 +493,6 @@ public abstract class AbstractRankingMetric implements RankingMetric { WindLegTypeAndLegBearingCache cache) { assert legWho.hasStartedLeg(timePoint); assert legTo.hasStartedLeg(timePoint); - assert getWindwardDistanceTraveled(legTo.getCompetitor(), legTo.hasFinishedLeg(timePoint)?legTo.getFinishTime():timePoint, cache).compareTo( - getWindwardDistanceTraveled(legWho.getCompetitor(), legWho.hasFinishedLeg(timePoint)?legWho.getFinishTime():timePoint, cache)) >= 0; final Duration toEndOfLegOrTo; if (legTo.hasFinishedLeg(timePoint)) { // calculate actual time it takes who to reach the end of the leg starting at timePoint: @@ -503,6 +501,8 @@ public abstract class AbstractRankingMetric implements RankingMetric { // who's leg finishing time is known; we don't need to extrapolate toEndOfLegOrTo = timePoint.until(whosLegFinishTime); } else { + assert getWindwardDistanceTraveled(legTo.getCompetitor(), legTo.hasFinishedLeg(timePoint)?legTo.getFinishTime():timePoint, cache).compareTo( + getWindwardDistanceTraveled(legWho.getCompetitor(), legWho.hasFinishedLeg(timePoint)?legWho.getFinishTime():timePoint, cache)) >= 0; // estimate who's leg finishing time by extrapolating with the average VMG (if available) or the current VMG // (if no average VMG can currently be computed, e.g., because the time point is exactly at the leg start) final Position windwardPositionToReachInWhosCurrentLeg = From 65776efe1d73ed1b3dfc485f9785bafba628deba Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 29 May 2015 18:30:26 +0200 Subject: [PATCH 63/72] working towards a solution for bug 2923 by centralizing the fetching of competitors for the ranking metric; however, we don't have the leaderboard available where we need it --- .../domain/ranking/AbstractRankingMetric.java | 21 ++++++++++++------- .../TimeOnTimeAndDistanceRankingMetric.java | 2 +- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java index e52ffc1a773..d0e50c3bd1c 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java @@ -285,7 +285,7 @@ public abstract class AbstractRankingMetric implements RankingMetric { */ private Comparator getWindwardDistanceTraveledComparator(final TimePoint timePoint, final WindLegTypeAndLegBearingCache cache) { final Map windwardDistanceTraveledPerCompetitor = new HashMap<>(); - for (final Competitor competitor : getTrackedRace().getRace().getCompetitors()) { + for (final Competitor competitor : getCompetitors()) { windwardDistanceTraveledPerCompetitor.put(competitor, getWindwardDistanceTraveled(competitor, timePoint, cache)); } final Comparator nullsFirstDistanceComparator = Comparator.nullsFirst(Comparator.naturalOrder()); @@ -293,12 +293,19 @@ public abstract class AbstractRankingMetric implements RankingMetric { windwardDistanceTraveledPerCompetitor.get(c2), windwardDistanceTraveledPerCompetitor.get(c1)); } + + /** + * Fetches the competitors to consider for this ranking + */ + protected Iterable getCompetitors() { + return getTrackedRace().getRace().getCompetitors(); + } public RankingMetric.RankingInfo getRankingInfo(TimePoint timePoint, WindLegTypeAndLegBearingCache cache) { Map result = new HashMap<>(); Comparator oneDesignComparator = getWindwardDistanceTraveledComparator(timePoint, cache); Competitor competitorFarthestAhead = StreamSupport - .stream(getTrackedRace().getRace().getCompetitors().spliterator(), /* parallel */true). + .stream(getCompetitors().spliterator(), /* parallel */true). sorted(oneDesignComparator).findFirst().get(); final Distance totalWindwardDistanceTraveled = getWindwardDistanceTraveled(competitorFarthestAhead, timePoint, cache); final TimePoint startOfRace = getTrackedRace().getStartOfRace(); @@ -307,12 +314,12 @@ public abstract class AbstractRankingMetric implements RankingMetric { actualRaceDuration = null; } else { actualRaceDuration = startOfRace.until(timePoint); - for (Competitor competitor : getTrackedRace().getRace().getCompetitors()) { + for (Competitor competitor : getCompetitors()) { final Duration predictedDurationToReachWindwardPositionOfCompetitorFarthestAhead = getPredictedDurationToReachWindwardPositionOf( competitor, competitorFarthestAhead, timePoint, cache); final Duration totalEstimatedDurationSinceRaceStartToCompetitorFarthestAhead = predictedDurationToReachWindwardPositionOfCompetitorFarthestAhead == null ? null : actualRaceDuration.plus(predictedDurationToReachWindwardPositionOfCompetitorFarthestAhead); - final Duration correctedEstimatedTimeWhenReachingCompetitorFarthestAhead = totalEstimatedDurationSinceRaceStartToCompetitorFarthestAhead == null ? null + final Duration calculatedEstimatedTimeWhenReachingCompetitorFarthestAhead = totalEstimatedDurationSinceRaceStartToCompetitorFarthestAhead == null ? null : getCalculatedTime( competitor, () -> getTrackedRace().getTrackedLeg(competitorFarthestAhead, timePoint).getLeg(), @@ -320,14 +327,14 @@ public abstract class AbstractRankingMetric implements RankingMetric { timePoint, /* extrapolate */true), totalEstimatedDurationSinceRaceStartToCompetitorFarthestAhead, totalWindwardDistanceTraveled); - final Duration correctedTime = getCalculatedTime(competitor, + final Duration calculatedTime = getCalculatedTime(competitor, () -> getTrackedRace().getCurrentLeg(competitor, timePoint).getLeg(), () -> getTrackedRace() .getTrack(competitor).getEstimatedPosition(timePoint, /* extrapolated */true), actualRaceDuration, totalWindwardDistanceTraveled); RankingMetric.CompetitorRankingInfo rankingInfo = new CompetitorRankingInfoImpl(timePoint, competitor, - getWindwardDistanceTraveled(competitor, timePoint, cache), actualRaceDuration, correctedTime, + getWindwardDistanceTraveled(competitor, timePoint, cache), actualRaceDuration, calculatedTime, predictedDurationToReachWindwardPositionOfCompetitorFarthestAhead, - correctedEstimatedTimeWhenReachingCompetitorFarthestAhead); + calculatedEstimatedTimeWhenReachingCompetitorFarthestAhead); result.put(competitor, rankingInfo); } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java index a2fad4f4589..b4021e69b3f 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java @@ -137,7 +137,7 @@ public class TimeOnTimeAndDistanceRankingMetric extends AbstractRankingMetric { totalWindwardDistanceLegLeaderTraveledUpToTimePointOrLegEnd = getWindwardDistanceTraveled( fastestCompetitorInLeg, timePoint, cache); } - for (Competitor competitor : getTrackedRace().getRace().getCompetitors()) { + for (Competitor competitor : getCompetitors()) { final TrackedLegOfCompetitor competitorLeg = trackedLeg.getTrackedLeg(competitor); final Duration correctedTime; if (competitorLeg != null && competitorLeg.hasStartedLeg(timePoint)) { From 044ae48875e28f84a83f5c3805b0cf243c1d8d86 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Sat, 30 May 2015 06:33:28 +0200 Subject: [PATCH 64/72] added some null-safety to polar service --- .../sap/sailing/polars/mining/GPSFixMovingWithPolarContext.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/GPSFixMovingWithPolarContext.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/GPSFixMovingWithPolarContext.java index 2e750ef5f2c..0f9f4dc12ab 100644 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/GPSFixMovingWithPolarContext.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/GPSFixMovingWithPolarContext.java @@ -77,7 +77,7 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe TrackedLegOfCompetitor currentLeg = race.getCurrentLeg(competitor, fix.getTimePoint()); if (currentLeg != null) { Bearing realBearing = currentLeg.getBeatAngle(fix.getTimePoint()); - bearing = new DegreeBearingImpl(Math.abs(realBearing.getDegrees())); + bearing = realBearing == null ? null : new DegreeBearingImpl(Math.abs(realBearing.getDegrees())); } } catch (NoWindException e) { bearing = null; From e13d2232a281cccd181e3735cf55e801dbe25c98 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 22 May 2015 19:15:29 +0200 Subject: [PATCH 65/72] added MediaType enum literal case statements for image and unknown; my impression is that so far, MediaType was primarily for video source identification, not for images; this may be a mismatch Conflicts: java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaType.java --- .../domain/base/impl/DomainFactoryImpl.java | 40 +++++++++++-------- .../client/media/MediaManagementControl.java | 12 ++++++ 2 files changed, 35 insertions(+), 17 deletions(-) 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 42c5adcf81c..5ff93bdfbb8 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 @@ -165,58 +165,64 @@ public class DomainFactoryImpl extends SharedDomainFactoryImpl implements Domain public TrackedRaceStatisticsDTO createTrackedRaceStatisticsDTO(TrackedRace trackedRace, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet, Collection mediaTracks) { TrackedRaceStatisticsDTO statisticsDTO = new TrackedRaceStatisticsDTO(); - // GPS data statisticsDTO.hasGPSData = trackedRace.hasGPSData(); - Competitor leaderOrWinner = null; TimePoint now = MillisecondsTimePoint.now(); try { - if(trackedRace.isLive(now)) { + if (trackedRace.isLive(now)) { leaderOrWinner = trackedRace.getOverallLeader(now); } else if (trackedRace.getEndOfRace() != null) { - for(Competitor competitor: leaderboard.getCompetitorsFromBestToWorst(raceColumn, now)) { + for (Competitor competitor : leaderboard.getCompetitorsFromBestToWorst(raceColumn, now)) { Fleet fleetOfCompetitor = raceColumn.getFleetOfCompetitor(competitor); - if(fleetOfCompetitor != null && fleetOfCompetitor.equals(fleet)) { + if (fleetOfCompetitor != null && fleetOfCompetitor.equals(fleet)) { leaderOrWinner = competitor; break; } } - } - if(leaderOrWinner != null) { + } + if (leaderOrWinner != null) { statisticsDTO.hasLeaderOrWinnerData = true; statisticsDTO.leaderOrWinner = convertToCompetitorDTO(leaderOrWinner); GPSFixTrack track = trackedRace.getTrack(leaderOrWinner); - if(track != null) { + if (track != null) { statisticsDTO.averageGPSDataSampleInterval = track.getAverageIntervalBetweenFixes(); } } } catch (NoWindException e) { } - + // Measured wind sources data statisticsDTO.measuredWindSourcesCount = Util.size(trackedRace.getWindSources(WindSourceType.EXPEDITION)); - statisticsDTO.hasMeasuredWindData = statisticsDTO.measuredWindSourcesCount > 0; + statisticsDTO.hasMeasuredWindData = statisticsDTO.measuredWindSourcesCount > 0; // leg progress data RaceDefinition race = trackedRace.getRace(); - if(race.getCourse() != null) { + if (race.getCourse() != null) { statisticsDTO.hasLegProgressData = true; statisticsDTO.totalLegsCount = race.getCourse().getLegs().size(); statisticsDTO.currentLegNo = trackedRace.getLastLegStarted(MillisecondsTimePoint.now()); } - + // media data - if(mediaTracks != null) { - for(MediaTrack track: mediaTracks) { - switch(track.mimeType.mediaType) { + if (mediaTracks != null) { + for (MediaTrack track : mediaTracks) { + switch (track.mimeType.mediaType) { case audio: statisticsDTO.hasAudioData = true; - statisticsDTO.audioTracksCount = statisticsDTO.audioTracksCount == null ? 1 : statisticsDTO.audioTracksCount++; + statisticsDTO.audioTracksCount = statisticsDTO.audioTracksCount == null ? 1 + : statisticsDTO.audioTracksCount++; break; case video: statisticsDTO.hasVideoData = true; - statisticsDTO.videoTracksCount = statisticsDTO.videoTracksCount == null ? 1 : statisticsDTO.videoTracksCount++; + statisticsDTO.videoTracksCount = statisticsDTO.videoTracksCount == null ? 1 + : statisticsDTO.videoTracksCount++; + break; + case image: // TODO should this add to an image count? + break; + case unknown: // TODO should this add to an "unknown media" count? Probably not + break; + default: break; } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/MediaManagementControl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/MediaManagementControl.java index 50c4c302f09..ff0b33c47b8 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/MediaManagementControl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/MediaManagementControl.java @@ -123,6 +123,12 @@ public class MediaManagementControl extends AbstractMediaSelectionControl implem } else { reachableAudioTracks.add(mediaTrack); } + case image: // no image media tracks produced by an image + break; + case unknown: // we won't overlay an unknown media source + break; + default: + break; } } } @@ -144,6 +150,12 @@ public class MediaManagementControl extends AbstractMediaSelectionControl implem } else { reachableAudioTracks.add(mediaTrack); } + case image: // images don't play as video tracks + break; + case unknown: // unknown formats won't be played either + break; + default: + break; } } } From 5883d19681325679d279782c6d28e1429be8f520 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Sat, 30 May 2015 08:49:03 +0200 Subject: [PATCH 66/72] The fix for bug 2897 has slightly altered the timings; waiting 1s for tracked race to be assigned to the race column --- .../server/replication/test/TrackRaceReplicationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/TrackRaceReplicationTest.java b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/TrackRaceReplicationTest.java index 1cc657c1968..1110d087034 100755 --- a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/TrackRaceReplicationTest.java +++ b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/TrackRaceReplicationTest.java @@ -142,8 +142,8 @@ public class TrackRaceReplicationTest extends AbstractServerReplicationTest { master.apply(new ConnectTrackedRaceToLeaderboardColumn(leaderboardName, columnName, defaultFleet.getName(), new RegattaNameAndRaceName("Academy Tracking 2011 (STG)", "weym470may122011"))); startTracking(); - assertNotNull(masterColumn.getTrackedRace(defaultFleet)); // ensure the re-assignment worked on the master Thread.sleep(1000); + assertNotNull(masterColumn.getTrackedRace(defaultFleet)); // ensure the re-assignment worked on the master TrackedRace replicaTrackedRace = replica.getTrackedRace(raceIdentifier); assertNotNull(replicaTrackedRace); assertNotSame(masterTrackedRace, replicaTrackedRace); From 05cfaac4554d901581ed52d7ad221ccba174a603 Mon Sep 17 00:00:00 2001 From: fmittag Date: Sat, 30 May 2015 15:19:40 +0300 Subject: [PATCH 67/72] fixed broken launch config...grr --- .../SailingGWT sdm.launch | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch b/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch index cabb941e42b..d8a99614b75 100755 --- a/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch +++ b/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch @@ -4,18 +4,22 @@ - - - - - - - - - + + + + + + + + + + + + + @@ -68,7 +72,7 @@ - + From 429a1ace1d8d1ef03f046ab566ddcfb2241183c0 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Sun, 31 May 2015 13:19:13 +0200 Subject: [PATCH 68/72] added more null safety and guarded against 0.0 VMG --- .../domain/ranking/AbstractRankingMetric.java | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java index d0e50c3bd1c..a54bafa34ac 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java @@ -444,14 +444,18 @@ public abstract class AbstractRankingMetric implements RankingMetric { assert getTrackedRace().getRace().getCourse().getIndexOfWaypoint(legWho.getLeg().getFrom()) <= getTrackedRace() .getRace().getCourse().getIndexOfWaypoint(legTo.getLeg().getFrom()); final Duration toEndOfLegOrTo = getPredictedDurationToEndOfLegOrTo(timePoint, legWho, legWho.getTrackedLeg().getTrackedLeg(to), cache); - final Duration durationForSubsequentLegsToReachAtEqualPerformance; - if (legWho.getLeg() == legTo.getLeg()) { - durationForSubsequentLegsToReachAtEqualPerformance = Duration.NULL; + if (toEndOfLegOrTo == null) { + result = null; } else { - durationForSubsequentLegsToReachAtEqualPerformance = getDurationToReachAtEqualPerformance(who, to, - legWho.getLeg().getTo(), timePoint, cache); + final Duration durationForSubsequentLegsToReachAtEqualPerformance; + if (legWho.getLeg() == legTo.getLeg()) { + durationForSubsequentLegsToReachAtEqualPerformance = Duration.NULL; + } else { + durationForSubsequentLegsToReachAtEqualPerformance = getDurationToReachAtEqualPerformance(who, to, + legWho.getLeg().getTo(), timePoint, cache); + } + result = toEndOfLegOrTo.plus(durationForSubsequentLegsToReachAtEqualPerformance); } - result = toEndOfLegOrTo.plus(durationForSubsequentLegsToReachAtEqualPerformance); } } return result; @@ -528,8 +532,9 @@ public abstract class AbstractRankingMetric implements RankingMetric { final TrackedLegOfCompetitor whosLeg, WindLegTypeAndLegBearingCache cache) { final Duration toEndOfLegOrTo; final Speed averageVMG = whosLeg.getAverageVelocityMadeGood(timePoint, cache); - final Speed vmg = Double.isNaN(averageVMG.getKnots()) ? /* default to current VMG */ whosLeg.getVelocityMadeGood(timePoint, WindPositionMode.EXACT, cache) : averageVMG; - toEndOfLegOrTo = vmg.getDuration( + final Speed vmg = averageVMG == null || Double.isNaN(averageVMG.getKnots()) ? + /* default to current VMG */ whosLeg.getVelocityMadeGood(timePoint, WindPositionMode.EXACT, cache) : averageVMG; + toEndOfLegOrTo = vmg == null || vmg.getKnots() == 0.0 ? null : vmg.getDuration( whosLeg.getTrackedLeg().getWindwardDistance( getTrackedRace().getTrack(whosLeg.getCompetitor()).getEstimatedPosition(timePoint, /* extrapolate */true), windwardPositionToReachInWhosCurrentLeg, timePoint, WindPositionMode.LEG_MIDDLE)); @@ -603,16 +608,18 @@ public abstract class AbstractRankingMetric implements RankingMetric { if (trackedLegOfCompetitor.hasStartedLeg(timePoint)) { if (!trackedLegOfCompetitor.hasFinishedLeg(timePoint)) { // partial distance sailed: - final Distance windwardDistanceFromLegStart = trackedLeg.getWindwardDistanceFromLegStart( - getTrackedRace().getTrack(competitor).getEstimatedPosition(timePoint, /* extrapolate */ true), cache); - final Distance legWindwardDistance = trackedLeg.getWindwardDistance(cache); - if (legWindwardDistance.compareTo(windwardDistanceFromLegStart) < 0) { - d = d.add(legWindwardDistance); - } else { - // if the competitor is currently at the mark rounding, the windward distance within the leg may - // be negative; don't reduce the distance in this case - if (windwardDistanceFromLegStart.getMeters() > 0) { - d = d.add(windwardDistanceFromLegStart); + final Position estimatedPosition = getTrackedRace().getTrack(competitor).getEstimatedPosition(timePoint, /* extrapolate */ true); + if (estimatedPosition != null) { + final Distance windwardDistanceFromLegStart = trackedLeg.getWindwardDistanceFromLegStart(estimatedPosition, cache); + final Distance legWindwardDistance = trackedLeg.getWindwardDistance(cache); + if (legWindwardDistance.compareTo(windwardDistanceFromLegStart) < 0) { + d = d.add(legWindwardDistance); + } else { + // if the competitor is currently at the mark rounding, the windward distance within the leg may + // be negative; don't reduce the distance in this case + if (windwardDistanceFromLegStart.getMeters() > 0) { + d = d.add(windwardDistanceFromLegStart); + } } } break; From 37544c75dc76a1451ba5a4bcef38eefb6247c9ff Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Sun, 31 May 2015 13:36:09 +0200 Subject: [PATCH 69/72] more null safety; allow null durations in leg comparator for time-on-time ranking metric --- .../ranking/TimeOnTimeAndDistanceRankingMetric.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java index b4021e69b3f..7b7821f117c 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java @@ -143,7 +143,8 @@ public class TimeOnTimeAndDistanceRankingMetric extends AbstractRankingMetric { if (competitorLeg != null && competitorLeg.hasStartedLeg(timePoint)) { final Duration timeToReachFastest = getPredictedDurationToEndOfLegOrTo(timePoint, competitorLeg, trackedLegOfFastestCompetitorInLeg, cache); - final Duration totalDurationSinceRaceStart = startOfRace.until(timePoint).plus(timeToReachFastest); + final Duration totalDurationSinceRaceStart = timeToReachFastest == null ? null : + startOfRace.until(timePoint).plus(timeToReachFastest); correctedTime = getCalculatedTime(competitor, () -> trackedLeg.getLeg(), () -> positionOfFastestBoatInLegAtTimePointOrLegEnd, totalDurationSinceRaceStart, totalWindwardDistanceLegLeaderTraveledUpToTimePointOrLegEnd); @@ -157,9 +158,12 @@ public class TimeOnTimeAndDistanceRankingMetric extends AbstractRankingMetric { } else { fastestCompetitorHasStartedLeg = false; } + final Comparator durationComparatorNullsLast = Comparator.nullsLast(Comparator.naturalOrder()); return (tloc1, tloc2) -> fastestCompetitorHasStartedLeg ? - correctedTimesToReachFastestBoatsPositionAtTimePointOrEndOfLegMeasuredFromStartOfRace.get(tloc1.getCompetitor()). - compareTo(correctedTimesToReachFastestBoatsPositionAtTimePointOrEndOfLegMeasuredFromStartOfRace.get(tloc2.getCompetitor())) : 0; + durationComparatorNullsLast.compare( + correctedTimesToReachFastestBoatsPositionAtTimePointOrEndOfLegMeasuredFromStartOfRace.get(tloc1.getCompetitor()), + correctedTimesToReachFastestBoatsPositionAtTimePointOrEndOfLegMeasuredFromStartOfRace.get(tloc2.getCompetitor())) + : 0; } @Override From d58da9df132880a1f948250c723a9c8af4b86972 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Sun, 31 May 2015 16:15:16 +0200 Subject: [PATCH 70/72] fixed test case which now requires a valid VMG for which two fixes per competitor are required --- .../TestSimpleTimeOnTimeRankingWithOneUpwindLeg.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/ranking/TestSimpleTimeOnTimeRankingWithOneUpwindLeg.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/ranking/TestSimpleTimeOnTimeRankingWithOneUpwindLeg.java index ae69c51bc6f..87040eed61f 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/ranking/TestSimpleTimeOnTimeRankingWithOneUpwindLeg.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/ranking/TestSimpleTimeOnTimeRankingWithOneUpwindLeg.java @@ -116,6 +116,12 @@ public class TestSimpleTimeOnTimeRankingWithOneUpwindLeg { c2, Arrays. asList(new MarkPassingImpl(startOfRace, trackedRace.getRace().getCourse() .getFirstWaypoint(), c2))); + trackedRace.getTrack(c1).add( + new GPSFixMovingImpl(new DegreePosition(0.0, 0), startOfRace, new KnotSpeedWithBearingImpl(12, + new DegreeBearingImpl(45)))); + trackedRace.getTrack(c2).add( + new GPSFixMovingImpl(new DegreePosition(0.0, 0), startOfRace, new KnotSpeedWithBearingImpl(12, + new DegreeBearingImpl(315)))); trackedRace.getTrack(c1).add( new GPSFixMovingImpl(new DegreePosition(0.5, 0), middleOfFirstLeg, new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(45)))); From f9b7cf936a17a98ee42c7f1bb961a195e02007d8 Mon Sep 17 00:00:00 2001 From: Frederik Petersen Date: Mon, 1 Jun 2015 10:58:10 +0200 Subject: [PATCH 71/72] Fixed downwind sign in polar data service --- .../src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java index 678eeaf7be1..6913ca6b081 100755 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java @@ -66,7 +66,8 @@ public class PolarDataServiceImpl implements PolarDataService { LegType legType, Tack tack, boolean useRegressionForSpeed) throws NotEnoughDataHasBeenAddedException { SpeedWithBearingWithConfidence averageSpeedAndCourseOverGround = polarDataMiner .getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType, useRegressionForSpeed); - if ((tack == Tack.PORT && legType == LegType.UPWIND) || (tack == Tack.STARBOARD && legType == LegType.DOWNWIND)) { + if (tack == Tack.PORT) { + //Negative twa DegreeBearingImpl bearing = new DegreeBearingImpl(-averageSpeedAndCourseOverGround.getObject().getBearing() .getDegrees()); KnotSpeedWithBearingImpl speed = new KnotSpeedWithBearingImpl(averageSpeedAndCourseOverGround.getObject() From e85a5426097e54c8694bb6cdf427e7131b2f768a Mon Sep 17 00:00:00 2001 From: "Christopher Ronnewinkel (D036654)" Date: Mon, 1 Jun 2015 11:03:27 +0200 Subject: [PATCH 72/72] separate colors for left and right 1-turner; --- .../sailing/gwt/ui/simulator/util/ColorPaletteGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/simulator/util/ColorPaletteGenerator.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/simulator/util/ColorPaletteGenerator.java index f2c85b4dfd6..935a9582eed 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/simulator/util/ColorPaletteGenerator.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/simulator/util/ColorPaletteGenerator.java @@ -3,7 +3,7 @@ package com.sap.sailing.gwt.ui.simulator.util; public class ColorPaletteGenerator implements ColorPalette { //private String[] colors = {"Green","Red","Blue","Yellow","Black"}; - private String[] colors = {"#00ED00","#FFBB00","#FFEA00","#0bf","#0bf","#808080","Blue","Blue","Yellow","Black"}; + private String[] colors = {"#00ED00","#FFBB00","#FFEA00","#0bf","#00e6ff","#808080","Blue","Blue","Yellow","Black"}; private int currentIndex = -1; public ColorPaletteGenerator() {