mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-24 13:03:55 +00:00
Merge remote-tracking branch 'origin/master' into ribdashboard
This commit is contained in:
commit
ce2e6e7e5b
37 files changed
+814
-179
No files matched your search
+2
-1
@@ -56,4 +56,5 @@ NumberOfPenaltyCircles=Anzahl der Straf-Kreise
|
||||
RankGainsOrLosses=Positions-Verluste oder -Gewinne
|
||||
DistanceToStarboardSideAtStart=Distanz zur Steuerbordseite (% der Länge)
|
||||
NumberOfPodiumFinish=Azahl der Podium-Siege
|
||||
NumberOfWins=Anzahl der Siege
|
||||
NumberOfWins=Anzahl der Siege
|
||||
RankGainsOrLossesBetweenFirstMarkAndFinish=Positions-Verluste oder -Gewinne (1ter Wegpunkt -> Ziel)
|
||||
+2
-1
@@ -56,4 +56,5 @@ NumberOfPenaltyCircles=Number of Penalty Circles
|
||||
RankGainsOrLosses=Rank Gains or Losses
|
||||
DistanceToStarboardSideAtStart=Distance to Starboard Side (% of Length)
|
||||
NumberOfPodiumFinish=Number of Podium Finishes
|
||||
NumberOfWins=Number of Wins
|
||||
NumberOfWins=Number of Wins
|
||||
RankGainsOrLossesBetweenFirstMarkAndFinish=Rank Gains or Losses (1st Mark -> Finish)
|
||||
+2
-2
@@ -38,7 +38,7 @@ public interface HasRaceOfCompetitorContext {
|
||||
@Statistic(messageKey="NumberOfPenaltyCircles", resultDecimals=2, ordinal=7)
|
||||
public Double getNumberOfPenaltyCircles();
|
||||
|
||||
@Statistic(messageKey="RankGainsOrLosses", resultDecimals=2, ordinal=8)
|
||||
public Double getRankGainsOrLosses();
|
||||
@Statistic(messageKey="RankGainsOrLossesBetweenFirstMarkAndFinish", resultDecimals=2, ordinal=8)
|
||||
public Double getRankGainsOrLossesBetweenFirstMarkAndFinish();
|
||||
|
||||
}
|
||||
+1
-1
@@ -88,7 +88,7 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getRankGainsOrLosses() {
|
||||
public Double getRankGainsOrLossesBetweenFirstMarkAndFinish() {
|
||||
Double rankAtFirstMark = getRankAtFirstMark();
|
||||
Double rankAtFinish = getRankAtFinish();
|
||||
return rankAtFirstMark - rankAtFinish;
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ public class RaceLogImpl extends AbstractLogImpl<RaceLogEvent, RaceLogEventVisit
|
||||
|
||||
@Override
|
||||
public int getCurrentPassId() {
|
||||
//return pass id of last event, as pass is the top-level sorting criterion in RaceLogeventComparator
|
||||
//return pass id of last event, as pass is the top-level sorting criterion in RaceLogEventComparator
|
||||
if (! getUnrevokedEvents().isEmpty()) {
|
||||
return getUnrevokedEvents().last().getPassId();
|
||||
} else {
|
||||
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
package com.sap.sailing.domain.test;
|
||||
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.isNull;
|
||||
import static org.mockito.Matchers.same;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.WindImpl;
|
||||
import com.sap.sailing.domain.tracking.WindWithConfidence;
|
||||
import com.sap.sailing.domain.tracking.impl.ShortTimeWindCache;
|
||||
import com.sap.sailing.domain.tracking.impl.TrackedRaceImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.WindWithConfidenceImpl;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
/**
|
||||
* See also bug 3195
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class ShortTimeWindCacheTest {
|
||||
private static final long CACHE_ENTRY_LIFETIME_IN_MILLIS = /* preserveHowManyMilliseconds */ 100;
|
||||
|
||||
public static class MyShortTimeWindCache extends ShortTimeWindCache {
|
||||
public MyShortTimeWindCache(TrackedRaceImpl trackedRace, long preserveHowManyMilliseconds) {
|
||||
super(trackedRace, preserveHowManyMilliseconds);
|
||||
}
|
||||
|
||||
public WindWithConfidence<com.sap.sse.common.Util.Pair<Position, TimePoint>> getWindWithConfidence(Position p,
|
||||
TimePoint at, Set<WindSource> windSourcesToExclude) {
|
||||
return super.getWindWithConfidence(p, at, windSourcesToExclude);
|
||||
}
|
||||
}
|
||||
|
||||
private MyShortTimeWindCache cache;
|
||||
private TrackedRaceImpl trackedRace;
|
||||
private TimePoint now;
|
||||
private WindWithConfidence<Pair<Position, TimePoint>> result;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Before
|
||||
public void setUp() {
|
||||
now = MillisecondsTimePoint.now();
|
||||
trackedRace = mock(TrackedRaceImpl.class);
|
||||
cache = new MyShortTimeWindCache(trackedRace, CACHE_ENTRY_LIFETIME_IN_MILLIS);
|
||||
result = new WindWithConfidenceImpl<Pair<Position, TimePoint>>(
|
||||
new WindImpl(new DegreePosition(54, 8), now, new KnotSpeedWithBearingImpl(12,
|
||||
new DegreeBearingImpl(123))), 0.123, new Pair<>(null, now), /* useSpeed */true);
|
||||
final RaceDefinition race = mock(RaceDefinition.class);
|
||||
when(race.getName()).thenReturn("Mocked Test Race");
|
||||
when(trackedRace.getRace()).thenReturn(race);
|
||||
when(trackedRace.getWindWithConfidenceUncached(/* position */ any(), same(now), (Iterable<WindSource>) isNull(Iterable.class))).thenAnswer(new Answer<WindWithConfidence<Pair<Position, TimePoint>>>() {
|
||||
@Override
|
||||
public WindWithConfidence<Pair<Position, TimePoint>> answer(InvocationOnMock invocation) throws Throwable {
|
||||
return result;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleSetupTest() throws InterruptedException {
|
||||
final Position p1 = null;
|
||||
final WindWithConfidence<Pair<Position, TimePoint>> firstResult = cache.getWindWithConfidence(p1, now, /* windSourcesToExclude */ null);
|
||||
assertSame(result, firstResult);
|
||||
Thread.sleep(CACHE_ENTRY_LIFETIME_IN_MILLIS/10); // wait a bit to make sure that the next cache entry will certainly not be removed by the timer removing the first entry
|
||||
final Position p2 = new DegreePosition(54, 8);
|
||||
final WindWithConfidence<Pair<Position, TimePoint>> secondResult = cache.getWindWithConfidence(p2, now, /* windSourcesToExclude */ null);
|
||||
assertSame(result, secondResult);
|
||||
Thread.sleep(CACHE_ENTRY_LIFETIME_IN_MILLIS/10); // wait a bit to make sure that the next cache entry will certainly not be removed by the timer removing the first entry
|
||||
final Position p3 = new DegreePosition(55, 9);
|
||||
final WindWithConfidence<Pair<Position, TimePoint>> thirdResult = cache.getWindWithConfidence(p3, now, /* windSourcesToExclude */ null);
|
||||
assertSame(result, thirdResult);
|
||||
final WindWithConfidence<Pair<Position, TimePoint>> oldResult = result;
|
||||
result = null; // this is the new response of trackedRace.getWindWithConfidenceUncached
|
||||
// assert that the trackedRace now responds with null
|
||||
assertNull(trackedRace.getWindWithConfidenceUncached(/* position */ null, now, /* windSourcesToExclude */ null));
|
||||
// assert that the cache still holds the cached values:
|
||||
final WindWithConfidence<Pair<Position, TimePoint>> firstResult_2 = cache.getWindWithConfidence(p1, now, /* windSourcesToExclude */ null);
|
||||
assertSame(oldResult, firstResult_2);
|
||||
final WindWithConfidence<Pair<Position, TimePoint>> secondResult_2 = cache.getWindWithConfidence(p2, now, /* windSourcesToExclude */ null);
|
||||
assertSame(oldResult, secondResult_2);
|
||||
final WindWithConfidence<Pair<Position, TimePoint>> thirdResult_2 = cache.getWindWithConfidence(p3, now, /* windSourcesToExclude */ null);
|
||||
assertSame(oldResult, thirdResult_2);
|
||||
|
||||
// now wait for the cache entries to be expired
|
||||
Thread.sleep(CACHE_ENTRY_LIFETIME_IN_MILLIS+1000l);
|
||||
final WindWithConfidence<Pair<Position, TimePoint>> firstResult_3 = cache.getWindWithConfidence(p1, now, /* windSourcesToExclude */ null);
|
||||
assertNull(firstResult_3); // this one even works with bug3195 unfixed because the first element is removed properly from "order" and "cache"
|
||||
final WindWithConfidence<Pair<Position, TimePoint>> secondResult_3 = cache.getWindWithConfidence(p2, now, /* windSourcesToExclude */ null);
|
||||
assertNull(secondResult_3); // this one fails with bug3195 unfixed because the entry was removed while "peeking" into "order" using a pollFirst() call
|
||||
// but the entry remained in "cache"
|
||||
final WindWithConfidence<Pair<Position, TimePoint>> thirdResult_3 = cache.getWindWithConfidence(p3, now, /* windSourcesToExclude */ null);
|
||||
assertNull(thirdResult_3);
|
||||
}
|
||||
}
|
||||
@@ -328,7 +328,8 @@ public interface TrackedRace extends Serializable, IsManagedByCache<SharedDomain
|
||||
|
||||
/**
|
||||
* Retrieves all wind sources known to this race, including those {@link #getWindSourcesToExclude() to exclude}.
|
||||
* Callers can freely iterate because a copied collection is returned.
|
||||
* Callers can freely iterate because a copied collection is returned. The {@link WindSourceType#COMBINED} wind source
|
||||
* is never part of the result.
|
||||
*/
|
||||
Set<WindSource> getWindSources();
|
||||
|
||||
|
||||
+11
-6
@@ -14,6 +14,7 @@ import com.sap.sailing.domain.tracking.WindWithConfidence;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.common.Util.Triple;
|
||||
import com.sap.sse.util.impl.ApproximateTime;
|
||||
|
||||
/**
|
||||
* Caches wind information across a short duration of a few seconds, based on position and time point. A separate timer
|
||||
@@ -49,7 +50,8 @@ public class ShortTimeWindCache {
|
||||
public void run() {
|
||||
long oldestToKeep = System.currentTimeMillis() - preserveHowManyMilliseconds;
|
||||
Pair<Long, Triple<Position, TimePoint, Set<WindSource>>> next;
|
||||
while ((next = order.pollFirst()) != null && next.getA() < oldestToKeep) {
|
||||
while ((next = order.peekFirst()) != null && next.getA() < oldestToKeep) {
|
||||
order.pollFirst();
|
||||
cache.remove(next.getB());
|
||||
}
|
||||
synchronized (order) {
|
||||
@@ -71,16 +73,19 @@ public class ShortTimeWindCache {
|
||||
|
||||
private void add(Triple<Position, TimePoint, Set<WindSource>> key, WindWithConfidence<com.sap.sse.common.Util.Pair<Position, TimePoint>> wind) {
|
||||
cache.put(key, wind);
|
||||
boolean orderEmpty = order.isEmpty();
|
||||
synchronized (order) {
|
||||
order.add(new Pair<Long, Triple<Position, TimePoint, Set<WindSource>>>(System.currentTimeMillis(), key));
|
||||
if (orderEmpty) {
|
||||
ensureTimerIsRunning();
|
||||
final long timestamp;
|
||||
if (preserveHowManyMilliseconds > 1000) {
|
||||
timestamp = ApproximateTime.approximateNow().asMillis();
|
||||
} else {
|
||||
timestamp = System.currentTimeMillis();
|
||||
}
|
||||
order.add(new Pair<Long, Triple<Position, TimePoint, Set<WindSource>>>(timestamp, key));
|
||||
ensureTimerIsRunning();
|
||||
}
|
||||
}
|
||||
|
||||
WindWithConfidence<com.sap.sse.common.Util.Pair<Position, TimePoint>> getWindWithConfidence(Position p,
|
||||
protected WindWithConfidence<com.sap.sse.common.Util.Pair<Position, TimePoint>> getWindWithConfidence(Position p,
|
||||
TimePoint at, Set<WindSource> windSourcesToExclude) {
|
||||
WindWithConfidence<com.sap.sse.common.Util.Pair<Position, TimePoint>> wind;
|
||||
final Triple<Position, TimePoint, Set<WindSource>> key = new Triple<Position, TimePoint, Set<WindSource>>(p, at, windSourcesToExclude);
|
||||
|
||||
@@ -25,6 +25,20 @@
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<!-- The following dependency needs re-declaration with the desired version because
|
||||
gwt-maps-api declares it with no version specifier which may be resolved to an
|
||||
incorrect version.
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>com.google.gwt</groupId>
|
||||
<artifactId>gwt-user</artifactId>
|
||||
<version>${gwt.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.gwt</groupId>
|
||||
<artifactId>gwt-dev</artifactId>
|
||||
<version>${gwt.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
|
||||
+3
@@ -1361,4 +1361,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
|
||||
String racesOverview();
|
||||
String empty();
|
||||
String runAQuery();
|
||||
String plainText();
|
||||
String columnChart();
|
||||
String choosePresentation();
|
||||
}
|
||||
+3
@@ -1328,3 +1328,6 @@ noFinishedRaces=There are no finished races yet
|
||||
racesOverview=Races overview
|
||||
empty=Empty
|
||||
runAQuery=Run a Query
|
||||
plainText=Plain Text
|
||||
columnChart=Column Chart
|
||||
choosePresentation=Choose Presentation
|
||||
+3
@@ -1318,3 +1318,6 @@ noFinishedRaces=Es wurden noch keine Wettfahrten beendet.
|
||||
racesOverview=Wettfahrtübersicht
|
||||
empty=Leer
|
||||
runAQuery=Führe eine Anfrage aus
|
||||
plainText=Einfacher Text
|
||||
columnChart=Säulendiagramm
|
||||
choosePresentation=Wähle Präsentation
|
||||
+3
@@ -1265,3 +1265,6 @@ noFinishedRaces=There are no finished races yet
|
||||
racesOverview=Races overview
|
||||
empty=Empty
|
||||
runAQuery=Run a Query
|
||||
plainText=Plain Text
|
||||
columnChart=Column Chart
|
||||
choosePresentation=Choose Presentation
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
package com.sap.sailing.gwt.ui.client.shared.panels;
|
||||
|
||||
import com.google.gwt.user.client.ui.RequiresResize;
|
||||
import com.google.gwt.user.client.ui.SimplePanel;
|
||||
|
||||
public abstract class ResizingSimplePanel extends SimplePanel implements RequiresResize {
|
||||
|
||||
}
|
||||
+2
@@ -7,6 +7,8 @@ public interface ResultsPresenter<ResultType> {
|
||||
|
||||
public Widget getWidget();
|
||||
|
||||
public QueryResult<ResultType> getCurrentResult();
|
||||
|
||||
public void showResult(QueryResult<ResultType> result);
|
||||
|
||||
public void showError(String error);
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package com.sap.sailing.gwt.ui.datamining;
|
||||
|
||||
public interface ResultsPresenterWithControls<ResultType> extends ResultsPresenter<ResultType>, WithControls {
|
||||
|
||||
}
|
||||
+1
-1
@@ -2,7 +2,7 @@ package com.sap.sailing.gwt.ui.datamining;
|
||||
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
|
||||
public interface DataMiningControls {
|
||||
public interface WithControls {
|
||||
|
||||
public void addControl(Widget controlWidget);
|
||||
|
||||
+6
@@ -91,5 +91,11 @@ public class PolarChart implements ResultsPresenter<Number> {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryResult<Number> getCurrentResult() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
package com.sap.sailing.gwt.ui.datamining.presentation;
|
||||
|
||||
import com.google.gwt.core.client.Scheduler;
|
||||
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
|
||||
import com.google.gwt.dom.client.Style.Unit;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.DockLayoutPanel;
|
||||
import com.google.gwt.user.client.ui.HTML;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.SimpleLayoutPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.datamining.ResultsPresenterWithControls;
|
||||
import com.sap.sse.datamining.shared.QueryResult;
|
||||
|
||||
public abstract class AbstractResultsPresenter<ResultType> implements ResultsPresenterWithControls<ResultType> {
|
||||
|
||||
private enum ResultsPresenterState { BUSY, ERROR, RESULT }
|
||||
|
||||
private final StringMessages stringMessages;
|
||||
private ResultsPresenterState state;
|
||||
|
||||
private final DockLayoutPanel mainPanel;
|
||||
private final HorizontalPanel controlsPanel;
|
||||
private final SimpleLayoutPanel presentationPanel;
|
||||
|
||||
private final HTML errorLabel;
|
||||
private final HTML labeledBusyIndicator;
|
||||
|
||||
private QueryResult<ResultType> currentResult;
|
||||
|
||||
public AbstractResultsPresenter(StringMessages stringMessages) {
|
||||
this.stringMessages = stringMessages;
|
||||
mainPanel = new DockLayoutPanel(Unit.PX);
|
||||
|
||||
controlsPanel = new HorizontalPanel();
|
||||
controlsPanel.setSpacing(5);
|
||||
mainPanel.addNorth(controlsPanel, 40);
|
||||
|
||||
Button exportButton = new Button("Export");
|
||||
exportButton.setEnabled(false);
|
||||
exportButton.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
// TODO Do the magic
|
||||
// Push the current result to the server
|
||||
// Call a servlet to download the previously pushed result as json file
|
||||
}
|
||||
});
|
||||
addControl(exportButton);
|
||||
|
||||
presentationPanel = new SimpleLayoutPanel();
|
||||
mainPanel.add(presentationPanel);
|
||||
|
||||
errorLabel = new HTML();
|
||||
errorLabel.setStyleName("chart-importantMessage");
|
||||
|
||||
labeledBusyIndicator = new HTML(stringMessages.runningQuery());
|
||||
labeledBusyIndicator.setStyleName("chart-busyMessage");
|
||||
|
||||
showError(getStringMessages().runAQuery());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addControl(Widget controlWidget) {
|
||||
controlsPanel.add(controlWidget);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showResult(QueryResult<ResultType> result) {
|
||||
if (result != null && !result.isEmpty()) {
|
||||
if (state != ResultsPresenterState.RESULT) {
|
||||
mainPanel.setWidgetHidden(controlsPanel, false);
|
||||
presentationPanel.setWidget(getPresentationWidget());
|
||||
state = ResultsPresenterState.RESULT;
|
||||
}
|
||||
|
||||
this.currentResult = result;
|
||||
internalShowResult();
|
||||
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
|
||||
@Override
|
||||
public void execute() {
|
||||
presentationPanel.onResize();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.currentResult = null;
|
||||
showError(getStringMessages().noDataFound() + ".");
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Widget getPresentationWidget();
|
||||
|
||||
protected abstract void internalShowResult();
|
||||
|
||||
@Override
|
||||
public void showError(String error) {
|
||||
if (state != ResultsPresenterState.ERROR) {
|
||||
mainPanel.setWidgetHidden(controlsPanel, true);
|
||||
errorLabel.setHTML(error);
|
||||
state = ResultsPresenterState.ERROR;
|
||||
}
|
||||
|
||||
currentResult = null;
|
||||
presentationPanel.setWidget(errorLabel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showError(String mainError, Iterable<String> detailedErrors) {
|
||||
StringBuilder errorBuilder = new StringBuilder(mainError + ":<br /><ul>");
|
||||
for (String detailedError : detailedErrors) {
|
||||
errorBuilder.append("<li>" + detailedError + "</li>");
|
||||
}
|
||||
errorBuilder.append("</ul>");
|
||||
showError(errorBuilder.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showBusyIndicator() {
|
||||
if (state != ResultsPresenterState.BUSY) {
|
||||
presentationPanel.setWidget(labeledBusyIndicator);
|
||||
state = ResultsPresenterState.BUSY;
|
||||
}
|
||||
|
||||
currentResult = null;
|
||||
}
|
||||
|
||||
protected StringMessages getStringMessages() {
|
||||
return stringMessages;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryResult<ResultType> getCurrentResult() {
|
||||
return currentResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Widget getWidget() {
|
||||
return mainPanel;
|
||||
}
|
||||
|
||||
}
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
package com.sap.sailing.gwt.ui.datamining.presentation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.core.client.Scheduler;
|
||||
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
|
||||
import com.google.gwt.event.logical.shared.ValueChangeEvent;
|
||||
import com.google.gwt.event.logical.shared.ValueChangeHandler;
|
||||
import com.google.gwt.user.client.ui.DeckLayoutPanel;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.ValueListBox;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.client.shared.controls.AbstractObjectRenderer;
|
||||
import com.sap.sailing.gwt.ui.datamining.ResultsPresenter;
|
||||
import com.sap.sailing.gwt.ui.datamining.ResultsPresenterWithControls;
|
||||
import com.sap.sse.datamining.shared.QueryResult;
|
||||
|
||||
public class MultiResultsPresenter implements ResultsPresenter<Number> {
|
||||
|
||||
private final StringMessages stringMessages;
|
||||
|
||||
private final DeckLayoutPanel presentersPanel;
|
||||
private final HorizontalPanel controlsPanel;
|
||||
private final ValueListBox<Descriptor> presentersListBox;
|
||||
private ResultsPresenter<Number> currentPresenter;
|
||||
|
||||
private List<Descriptor> availableDescriptors;
|
||||
|
||||
public MultiResultsPresenter(StringMessages stringMessages) {
|
||||
this.stringMessages = stringMessages;
|
||||
availableDescriptors = new ArrayList<>();
|
||||
availableDescriptors.add(new ColumnChartDescriptor());
|
||||
availableDescriptors.add(new PlainDescriptor());
|
||||
|
||||
presentersPanel = new DeckLayoutPanel();
|
||||
|
||||
controlsPanel = new HorizontalPanel();
|
||||
controlsPanel.setSpacing(5);
|
||||
controlsPanel.add(new Label(stringMessages.choosePresentation() + ":"));
|
||||
presentersListBox = new ValueListBox<>(new AbstractObjectRenderer<Descriptor>() {
|
||||
@Override
|
||||
protected String convertObjectToString(Descriptor nonNullObject) {
|
||||
return nonNullObject.getName();
|
||||
}
|
||||
});
|
||||
presentersListBox.addValueChangeHandler(new ValueChangeHandler<Descriptor>() {
|
||||
@Override
|
||||
public void onValueChange(ValueChangeEvent<Descriptor> event) {
|
||||
setCurrentPresenter(event.getValue().getPresenter());
|
||||
}
|
||||
});
|
||||
controlsPanel.add(presentersListBox);
|
||||
presentersListBox.setValue(availableDescriptors.get(0), false);
|
||||
presentersListBox.setAcceptableValues(availableDescriptors);
|
||||
|
||||
setCurrentPresenter(availableDescriptors.get(0).getPresenter());
|
||||
}
|
||||
|
||||
private void setCurrentPresenter(ResultsPresenterWithControls<Number> presenter) {
|
||||
controlsPanel.removeFromParent();
|
||||
presenter.addControl(controlsPanel);
|
||||
|
||||
currentPresenter = presenter;
|
||||
presentersPanel.setWidget(currentPresenter.getWidget());
|
||||
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
|
||||
@Override
|
||||
public void execute() {
|
||||
presentersPanel.onResize();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Widget getWidget() {
|
||||
return presentersPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryResult<Number> getCurrentResult() {
|
||||
return currentPresenter.getCurrentResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showResult(QueryResult<Number> result) {
|
||||
for (Descriptor descriptor : availableDescriptors) {
|
||||
descriptor.getPresenter().showResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showError(String error) {
|
||||
for (Descriptor descriptor : availableDescriptors) {
|
||||
descriptor.getPresenter().showError(error);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showError(String mainError, Iterable<String> detailedErrors) {
|
||||
for (Descriptor descriptor : availableDescriptors) {
|
||||
descriptor.getPresenter().showError(mainError, detailedErrors);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showBusyIndicator() {
|
||||
for (Descriptor descriptor : availableDescriptors) {
|
||||
descriptor.getPresenter().showBusyIndicator();
|
||||
}
|
||||
}
|
||||
|
||||
private interface Descriptor {
|
||||
|
||||
public String getName();
|
||||
|
||||
public ResultsPresenterWithControls<Number> getPresenter();
|
||||
|
||||
}
|
||||
|
||||
private class PlainDescriptor implements Descriptor {
|
||||
|
||||
private final AbstractResultsPresenter<Number> presenter;
|
||||
|
||||
public PlainDescriptor() {
|
||||
presenter = new PlainResultsPresenter(stringMessages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return stringMessages.plainText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractResultsPresenter<Number> getPresenter() {
|
||||
return presenter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ColumnChartDescriptor implements Descriptor {
|
||||
|
||||
private final ResultsChart presenter;
|
||||
|
||||
public ColumnChartDescriptor() {
|
||||
presenter = new ResultsChart(stringMessages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return stringMessages.columnChart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractResultsPresenter<Number> getPresenter() {
|
||||
return presenter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+28
-48
@@ -1,77 +1,57 @@
|
||||
package com.sap.sailing.gwt.ui.datamining.presentation;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gwt.user.client.ui.HTML;
|
||||
import com.google.gwt.user.client.ui.SimplePanel;
|
||||
import com.google.gwt.user.client.ui.ScrollPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.datamining.ResultsPresenter;
|
||||
import com.sap.sse.datamining.shared.GroupKey;
|
||||
import com.sap.sse.datamining.shared.QueryResult;
|
||||
import com.sap.sse.gwt.client.controls.busyindicator.BusyIndicator;
|
||||
import com.sap.sse.gwt.client.controls.busyindicator.SimpleBusyIndicator;
|
||||
|
||||
public class PlainResultsPresenter implements ResultsPresenter<Number> {
|
||||
public class PlainResultsPresenter extends AbstractResultsPresenter<Number> {
|
||||
|
||||
private final StringMessages stringMessages;
|
||||
|
||||
private final SimplePanel mainPanel;
|
||||
private final ScrollPanel scrollPanel;
|
||||
private final HTML resultsLabel;
|
||||
private final BusyIndicator busyIndicator;
|
||||
|
||||
public PlainResultsPresenter(StringMessages stringMessages) {
|
||||
this.stringMessages = stringMessages;
|
||||
super(stringMessages);
|
||||
|
||||
mainPanel = new SimplePanel();
|
||||
resultsLabel = new HTML();
|
||||
mainPanel.setWidget(resultsLabel);
|
||||
|
||||
busyIndicator = new SimpleBusyIndicator(true, 0.7f);
|
||||
scrollPanel = new ScrollPanel(resultsLabel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showResult(QueryResult<Number> result) {
|
||||
StringBuilder resultsBuilder = new StringBuilder("<b>" + result.getResultSignifier() + "</b></ br>");
|
||||
resultsBuilder.append(stringMessages.queryResultsChartSubtitle(result.getRetrievedDataAmount(), result.getCalculationTimeInSeconds()));
|
||||
protected void internalShowResult() {
|
||||
QueryResult<Number> result = getCurrentResult();
|
||||
Map<GroupKey, Number> resultValues = result.getResults();
|
||||
|
||||
resultsBuilder.append("<ul>");
|
||||
for (Entry<GroupKey, Number> resultEntry : result.getResults().entrySet()) {
|
||||
resultsBuilder.append("<li>");
|
||||
resultsBuilder.append("<b>" + resultEntry.getKey().toString() + "</b>: ");
|
||||
resultsBuilder.append(resultEntry.getValue().doubleValue());
|
||||
resultsBuilder.append("</li>");
|
||||
StringBuilder resultsBuilder = new StringBuilder("<b>" + result.getResultSignifier() + "</b></ br>");
|
||||
|
||||
resultsBuilder.append("<table>");
|
||||
for (GroupKey key : getSortedKeys(result)) {
|
||||
resultsBuilder.append("<tr>");
|
||||
resultsBuilder.append("<td><b>" + key.toString() + "</b>:</td>");
|
||||
resultsBuilder.append("<td>" + resultValues.get(key).doubleValue() + "</td>");
|
||||
resultsBuilder.append("</tr>");
|
||||
}
|
||||
resultsBuilder.append("</ul>");
|
||||
resultsBuilder.append("</table>");
|
||||
|
||||
resultsLabel.setHTML(resultsBuilder.toString());
|
||||
mainPanel.setWidget(resultsLabel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showError(String error) {
|
||||
resultsLabel.setHTML(error);
|
||||
mainPanel.setWidget(resultsLabel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showError(String mainError, Iterable<String> detailedErrors) {
|
||||
StringBuilder errorBuilder = new StringBuilder(mainError + ":<br /><ul>");
|
||||
for (String detailedError : detailedErrors) {
|
||||
errorBuilder.append("<li>" + detailedError + "</li>");
|
||||
}
|
||||
errorBuilder.append("</ul>");
|
||||
showError(errorBuilder.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showBusyIndicator() {
|
||||
mainPanel.setWidget(busyIndicator);
|
||||
private Iterable<GroupKey> getSortedKeys(QueryResult<Number> result) {
|
||||
List<GroupKey> sortedKeys = new ArrayList<>(result.getResults().keySet());
|
||||
Collections.sort(sortedKeys);
|
||||
return sortedKeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Widget getWidget() {
|
||||
return mainPanel;
|
||||
protected Widget getPresentationWidget() {
|
||||
return scrollPanel;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+39
-91
@@ -15,6 +15,7 @@ import org.moxieapps.gwt.highcharts.client.ChartSubtitle;
|
||||
import org.moxieapps.gwt.highcharts.client.ChartTitle;
|
||||
import org.moxieapps.gwt.highcharts.client.Color;
|
||||
import org.moxieapps.gwt.highcharts.client.Credits;
|
||||
import org.moxieapps.gwt.highcharts.client.Exporting;
|
||||
import org.moxieapps.gwt.highcharts.client.Point;
|
||||
import org.moxieapps.gwt.highcharts.client.Series;
|
||||
import org.moxieapps.gwt.highcharts.client.ToolTip;
|
||||
@@ -22,24 +23,19 @@ import org.moxieapps.gwt.highcharts.client.labels.AxisLabelsData;
|
||||
import org.moxieapps.gwt.highcharts.client.labels.AxisLabelsFormatter;
|
||||
import org.moxieapps.gwt.highcharts.client.labels.YAxisLabels;
|
||||
|
||||
import com.google.gwt.dom.client.Style.Unit;
|
||||
import com.google.gwt.event.logical.shared.ValueChangeEvent;
|
||||
import com.google.gwt.event.logical.shared.ValueChangeHandler;
|
||||
import com.google.gwt.text.shared.AbstractRenderer;
|
||||
import com.google.gwt.user.client.ui.DockLayoutPanel;
|
||||
import com.google.gwt.user.client.ui.HTML;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.SimpleLayoutPanel;
|
||||
import com.google.gwt.user.client.ui.ValueListBox;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.client.shared.panels.ResizingSimplePanel;
|
||||
import com.sap.sailing.gwt.ui.datamining.ResultsPresenter;
|
||||
import com.sap.sse.datamining.shared.GroupKey;
|
||||
import com.sap.sse.datamining.shared.QueryResult;
|
||||
import com.sap.sse.datamining.shared.impl.GenericGroupKey;
|
||||
|
||||
public class ResultsChart implements ResultsPresenter<Number> {
|
||||
public class ResultsChart extends AbstractResultsPresenter<Number> {
|
||||
|
||||
private final Comparator<GroupKey> standardKeyComparator = new Comparator<GroupKey>() {
|
||||
@Override
|
||||
@@ -48,20 +44,20 @@ public class ResultsChart implements ResultsPresenter<Number> {
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return stringMessages.group();
|
||||
return getStringMessages().group();
|
||||
};
|
||||
};
|
||||
private final Comparator<GroupKey> ascendingByValueKeyComparator = new Comparator<GroupKey>() {
|
||||
@Override
|
||||
public int compare(GroupKey key1, GroupKey key2) {
|
||||
Map<GroupKey, ? extends Number> resultData = currentResult.getResults();
|
||||
Map<GroupKey, ? extends Number> resultData = getCurrentResult().getResults();
|
||||
double doubleValue1 = resultData.get(key1).doubleValue();
|
||||
double doubleValue2 = resultData.get(key2).doubleValue();
|
||||
return Double.compare(doubleValue1, doubleValue2);
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return stringMessages.valueAscending();
|
||||
return getStringMessages().valueAscending();
|
||||
};
|
||||
};
|
||||
private final Comparator<GroupKey> descendingByValueKeyComparator = new Comparator<GroupKey>() {
|
||||
@@ -71,31 +67,21 @@ public class ResultsChart implements ResultsPresenter<Number> {
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return stringMessages.valueDescending();
|
||||
return getStringMessages().valueDescending();
|
||||
};
|
||||
};
|
||||
|
||||
private final StringMessages stringMessages;
|
||||
private final DockLayoutPanel mainPanel;
|
||||
|
||||
private final HorizontalPanel sortByPanel;
|
||||
private final ValueListBox<Comparator<GroupKey>> keyComparatorListBox;
|
||||
|
||||
private final ResizingSimplePanel presentationPanel;
|
||||
private final SimpleLayoutPanel chartPanel;
|
||||
private final Chart chart;
|
||||
private final HTML errorLabel;
|
||||
private final HTML labeledBusyIndicator;
|
||||
|
||||
private Map<GroupKey, Series> seriesMappedByGroupKey;
|
||||
private final GroupKey simpleResultSeriesKey;
|
||||
private QueryResult<? extends Number> currentResult;
|
||||
private Map<GroupKey, Integer> mainKeyToXValueMap;
|
||||
|
||||
public ResultsChart(StringMessages stringMessages) {
|
||||
super();
|
||||
this.stringMessages = stringMessages;
|
||||
|
||||
mainPanel = new DockLayoutPanel(Unit.PX);
|
||||
super(stringMessages);
|
||||
|
||||
sortByPanel = new HorizontalPanel();
|
||||
sortByPanel.setSpacing(5);
|
||||
@@ -114,87 +100,55 @@ public class ResultsChart implements ResultsPresenter<Number> {
|
||||
}
|
||||
});
|
||||
sortByPanel.add(keyComparatorListBox);
|
||||
mainPanel.addNorth(sortByPanel, 40);
|
||||
mainPanel.setWidgetHidden(sortByPanel, true);
|
||||
sortByPanel.setVisible(false);
|
||||
addControl(sortByPanel);
|
||||
|
||||
presentationPanel = new ResizingSimplePanel() {
|
||||
chartPanel = new SimpleLayoutPanel() {
|
||||
@Override
|
||||
public void onResize() {
|
||||
chart.setSizeToMatchContainer();
|
||||
chart.redraw();
|
||||
}
|
||||
};
|
||||
mainPanel.add(presentationPanel);
|
||||
|
||||
chart = createChart();
|
||||
chartPanel.setWidget(chart);
|
||||
|
||||
seriesMappedByGroupKey = new HashMap<GroupKey, Series>();
|
||||
simpleResultSeriesKey = new GenericGroupKey<String>(stringMessages.results());
|
||||
|
||||
errorLabel = new HTML();
|
||||
errorLabel.setStyleName("chart-importantMessage");
|
||||
|
||||
labeledBusyIndicator = new HTML(stringMessages.runningQuery());
|
||||
labeledBusyIndicator.setStyleName("chart-busyMessage");
|
||||
|
||||
showError(this.stringMessages.invalidSelection());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showError(String error) {
|
||||
currentResult = null;
|
||||
errorLabel.setHTML(error);
|
||||
presentationPanel.setWidget(errorLabel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showError(String mainError, Iterable<String> detailedErrors) {
|
||||
StringBuilder errorBuilder = new StringBuilder(mainError + ":<br /><ul>");
|
||||
for (String detailedError : detailedErrors) {
|
||||
errorBuilder.append("<li>" + detailedError + "</li>");
|
||||
}
|
||||
errorBuilder.append("</ul>");
|
||||
showError(errorBuilder.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showBusyIndicator() {
|
||||
currentResult = null;
|
||||
presentationPanel.setWidget(labeledBusyIndicator);
|
||||
protected Widget getPresentationWidget() {
|
||||
return chartPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showResult(QueryResult<Number> result) {
|
||||
if (result != null && !result.isEmpty()) {
|
||||
currentResult = result;
|
||||
updateKeyComparatorListBox();
|
||||
resetChartSeries();
|
||||
updateYAxisLabels();
|
||||
updateChartSubtitleAndSetChartAsWidget();
|
||||
showResultData();
|
||||
} else {
|
||||
showError(stringMessages.noDataFound() + ".");
|
||||
}
|
||||
protected void internalShowResult() {
|
||||
updateKeyComparatorListBox();
|
||||
resetChartSeries();
|
||||
updateYAxisLabels();
|
||||
updateChartSubtitleAndSetChartAsWidget();
|
||||
showResultData();
|
||||
}
|
||||
|
||||
private void updateKeyComparatorListBox() {
|
||||
boolean hidden = true;
|
||||
boolean visible = false;
|
||||
Comparator<GroupKey> valueToBeSelected = standardKeyComparator;
|
||||
Collection<Comparator<GroupKey>> acceptableValues = new ArrayList<>();
|
||||
acceptableValues.add(valueToBeSelected);
|
||||
if (currentResult != null && isCurrentResultSimple()) {
|
||||
if (getCurrentResult() != null && isCurrentResultSimple()) {
|
||||
valueToBeSelected = getKeyComparator() != null ? getKeyComparator() : valueToBeSelected;
|
||||
acceptableValues.add(ascendingByValueKeyComparator);
|
||||
acceptableValues.add(descendingByValueKeyComparator);
|
||||
hidden = false;
|
||||
visible = true;
|
||||
}
|
||||
keyComparatorListBox.setValue(valueToBeSelected);
|
||||
keyComparatorListBox.setAcceptableValues(acceptableValues);
|
||||
mainPanel.setWidgetHidden(sortByPanel, hidden);
|
||||
mainPanel.forceLayout();
|
||||
sortByPanel.setVisible(visible);
|
||||
}
|
||||
|
||||
private boolean isCurrentResultSimple() {
|
||||
for (GroupKey groupKey : currentResult.getResults().keySet()) {
|
||||
for (GroupKey groupKey : getCurrentResult().getResults().keySet()) {
|
||||
if (groupKey.hasSubKey()) {
|
||||
return false;
|
||||
}
|
||||
@@ -208,24 +162,21 @@ public class ResultsChart implements ResultsPresenter<Number> {
|
||||
}
|
||||
|
||||
private void updateYAxisLabels() {
|
||||
chart.getYAxis().setAxisTitleText(currentResult.getResultSignifier());
|
||||
chart.setToolTip(new ToolTip().setValueDecimals(currentResult.getValueDecimals()).setValueSuffix(
|
||||
currentResult.getUnitSignifier()));
|
||||
chart.getYAxis().setAxisTitleText(getCurrentResult().getResultSignifier());
|
||||
chart.setToolTip(new ToolTip().setValueDecimals(getCurrentResult().getValueDecimals()).setValueSuffix(
|
||||
getCurrentResult().getUnitSignifier()));
|
||||
}
|
||||
|
||||
private void updateChartSubtitleAndSetChartAsWidget() {
|
||||
chart.setChartSubtitle(new ChartSubtitle().setText(stringMessages.queryResultsChartSubtitle(
|
||||
currentResult.getRetrievedDataAmount(), currentResult.getCalculationTimeInSeconds())));
|
||||
// This is needed, so that the subtitle is updated. Otherwise the text would stay empty
|
||||
presentationPanel.setWidget(null);
|
||||
presentationPanel.setWidget(chart);
|
||||
chart.setChartSubtitle(new ChartSubtitle().setText(getStringMessages().queryResultsChartSubtitle(
|
||||
getCurrentResult().getRetrievedDataAmount(), getCurrentResult().getCalculationTimeInSeconds())));
|
||||
}
|
||||
|
||||
private void showResultData() {
|
||||
buildMainKeyMapAndSetXAxisCategories();
|
||||
createAndAddSeriesToChart();
|
||||
|
||||
for (Entry<GroupKey, ? extends Number> resultEntry : currentResult.getResults().entrySet()) {
|
||||
for (Entry<GroupKey, ? extends Number> resultEntry : getCurrentResult().getResults().entrySet()) {
|
||||
GroupKey mainKey = resultEntry.getKey().getMainKey();
|
||||
Point point = new Point(mainKeyToXValueMap.get(mainKey), resultEntry.getValue());
|
||||
point.setName(mainKey.asString());
|
||||
@@ -248,9 +199,9 @@ public class ResultsChart implements ResultsPresenter<Number> {
|
||||
chart.getXAxis().setCategories(false, categories);
|
||||
}
|
||||
|
||||
public List<GroupKey> getSortedMainKeys() {
|
||||
private List<GroupKey> getSortedMainKeys() {
|
||||
Collection<GroupKey> mainKeySet = new HashSet<>();
|
||||
for (GroupKey groupKey : currentResult.getResults().keySet()) {
|
||||
for (GroupKey groupKey : getCurrentResult().getResults().keySet()) {
|
||||
mainKeySet.add(groupKey.getMainKey());
|
||||
}
|
||||
List<GroupKey> sortedKeys = new ArrayList<>(mainKeySet);
|
||||
@@ -263,7 +214,7 @@ public class ResultsChart implements ResultsPresenter<Number> {
|
||||
}
|
||||
|
||||
private void createAndAddSeriesToChart() {
|
||||
for (GroupKey groupKey : currentResult.getResults().keySet()) {
|
||||
for (GroupKey groupKey : getCurrentResult().getResults().keySet()) {
|
||||
GroupKey seriesKey = groupKeyToSeriesKey(groupKey);
|
||||
if (!seriesMappedByGroupKey.containsKey(seriesKey)) {
|
||||
seriesMappedByGroupKey.put(seriesKey, chart.createSeries().setName(seriesKey.asString()));
|
||||
@@ -290,7 +241,9 @@ public class ResultsChart implements ResultsPresenter<Number> {
|
||||
.setBorderColor(new Color("#F0AB00"))
|
||||
.setPlotBorderWidth(0)
|
||||
.setCredits(new Credits().setEnabled(false))
|
||||
.setChartTitle(new ChartTitle().setText(stringMessages.dataMiningResult()));
|
||||
.setChartTitle(new ChartTitle().setText(getStringMessages().dataMiningResult()));
|
||||
|
||||
chart.setExporting(new Exporting().setEnabled(false));
|
||||
|
||||
chart.getXAxis().setAllowDecimals(false);
|
||||
|
||||
@@ -307,10 +260,5 @@ public class ResultsChart implements ResultsPresenter<Number> {
|
||||
|
||||
return chart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Widget getWidget() {
|
||||
return mainPanel;
|
||||
}
|
||||
|
||||
}
|
||||
+6
-2
@@ -86,6 +86,11 @@ public class TabbedResultsPresenter implements ResultsPresenter<Number> {
|
||||
getSelectedPresenter().showBusyIndicator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryResult<Number> getCurrentResult() {
|
||||
return getSelectedPresenter().getCurrentResult();
|
||||
}
|
||||
|
||||
private CloseableTabHeader getSelectedHeader() {
|
||||
return (CloseableTabHeader) tabPanel.getTabWidget(tabPanel.getSelectedIndex());
|
||||
}
|
||||
@@ -96,8 +101,7 @@ public class TabbedResultsPresenter implements ResultsPresenter<Number> {
|
||||
|
||||
private void addTabAndFocus() {
|
||||
CloseableTabHeader tabHeader = new CloseableTabHeader();
|
||||
ResultsChart tabPresenter = new ResultsChart(stringMessages);
|
||||
tabPresenter.showError(stringMessages.runAQuery());
|
||||
ResultsPresenter<Number> tabPresenter = new MultiResultsPresenter(stringMessages);
|
||||
presentersMappedByHeader.put(tabHeader, tabPresenter);
|
||||
|
||||
tabPanel.insert(tabPresenter.getWidget(), tabHeader, tabPanel.getWidgetCount() - 1);
|
||||
|
||||
+2
-2
@@ -19,7 +19,7 @@ import com.google.gwt.user.client.ui.SplitLayoutPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.datamining.DataMiningComponentProvider;
|
||||
import com.sap.sailing.gwt.ui.datamining.DataMiningControls;
|
||||
import com.sap.sailing.gwt.ui.datamining.WithControls;
|
||||
import com.sap.sailing.gwt.ui.datamining.DataMiningServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.datamining.DataRetrieverChainDefinitionChangedListener;
|
||||
import com.sap.sailing.gwt.ui.datamining.DataRetrieverChainDefinitionProvider;
|
||||
@@ -40,7 +40,7 @@ import com.sap.sse.datamining.shared.impl.dto.ModifiableStatisticQueryDefinition
|
||||
import com.sap.sse.gwt.client.ErrorReporter;
|
||||
import com.sap.sse.gwt.client.shared.components.SettingsDialogComponent;
|
||||
|
||||
public class BufferingQueryDefinitionProviderWithControls extends AbstractQueryDefinitionProvider implements DataMiningControls {
|
||||
public class BufferingQueryDefinitionProviderWithControls extends AbstractQueryDefinitionProvider implements WithControls {
|
||||
|
||||
/**
|
||||
* The delay before a changed query definition is submitted to the listeners.
|
||||
|
||||
@@ -96,13 +96,6 @@
|
||||
version="1.6.4.1"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="rome"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="1.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="routeconverter"
|
||||
download-size="0"
|
||||
|
||||
Binary file not shown.
@@ -226,7 +226,6 @@
|
||||
<plugin id="org.objectweb.asm"/>
|
||||
<plugin id="org.objectweb.asm.source"/>
|
||||
<plugin id="org.objenesis"/>
|
||||
<plugin id="rome"/>
|
||||
<plugin id="routeconverter"/>
|
||||
<plugin id="slf4j.api"/>
|
||||
<plugin id="slf4j.jdk14"/>
|
||||
|
||||
@@ -14,6 +14,6 @@ Export-Package: com.sap.sse.common,
|
||||
com.sap.sse.common.search,
|
||||
com.sap.sse.common.settings,
|
||||
com.sap.sse.common.util
|
||||
Require-Bundle: com.sap.sse.datamining.shared;bundle-version="1.0.0",
|
||||
org.json.simple;bundle-version="1.1.0"
|
||||
Require-Bundle: org.json.simple;bundle-version="1.1.0",
|
||||
com.sap.sse.datamining.shared;bundle-version="1.0.0"
|
||||
Bundle-ActivationPolicy: lazy
|
||||
@@ -10,5 +10,6 @@ Export-Package: com.sap.sse.datamining.shared,
|
||||
com.sap.sse.datamining.shared.data,
|
||||
com.sap.sse.datamining.shared.dto,
|
||||
com.sap.sse.datamining.shared.impl,
|
||||
com.sap.sse.datamining.shared.impl.dto
|
||||
com.sap.sse.datamining.shared.impl.dto,
|
||||
com.sap.sse.datamining.shared.util
|
||||
Bundle-ActivationPolicy: lazy
|
||||
@@ -6,4 +6,5 @@
|
||||
<source path='shared/dto'/>
|
||||
<source path='shared/impl'/>
|
||||
<source path='shared/impl/dto'/>
|
||||
<source path='shared/util'/>
|
||||
</module>
|
||||
+5
@@ -1,6 +1,7 @@
|
||||
package com.sap.sse.datamining.shared.impl;
|
||||
|
||||
import com.sap.sse.datamining.shared.GroupKey;
|
||||
import com.sap.sse.datamining.shared.util.AlphanumericalComparator;
|
||||
|
||||
|
||||
public class GenericGroupKey<T> extends AbstractGroupKey {
|
||||
@@ -50,6 +51,10 @@ public class GenericGroupKey<T> extends AbstractGroupKey {
|
||||
if (value instanceof Enum && keyValue instanceof Enum) {
|
||||
result = ((Enum<?>) value).ordinal() - ((Enum<?>) keyValue).ordinal();
|
||||
}
|
||||
if (value instanceof String && keyValue instanceof String) {
|
||||
AlphanumericalComparator comparator = new AlphanumericalComparator();
|
||||
result = comparator.compare((String) value, (String) keyValue);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
package com.sap.sse.datamining.shared.util;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Comparator;
|
||||
|
||||
public class AlphanumericalComparator implements Comparator<String>, Serializable {
|
||||
private static final long serialVersionUID = 1932325900088375762L;
|
||||
|
||||
private final boolean isDigit(char ch) {
|
||||
return ch >= 48 && ch <= 57;
|
||||
}
|
||||
|
||||
/** Length of string is passed in for improved efficiency (only need to calculate it once) **/
|
||||
private final String getChunk(String s, int slength, int marker) {
|
||||
StringBuilder chunk = new StringBuilder();
|
||||
char c = s.charAt(marker);
|
||||
chunk.append(c);
|
||||
marker++;
|
||||
if (isDigit(c)) {
|
||||
while (marker < slength) {
|
||||
c = s.charAt(marker);
|
||||
if (!isDigit(c))
|
||||
break;
|
||||
chunk.append(c);
|
||||
marker++;
|
||||
}
|
||||
} else {
|
||||
while (marker < slength) {
|
||||
c = s.charAt(marker);
|
||||
if (isDigit(c))
|
||||
break;
|
||||
chunk.append(c);
|
||||
marker++;
|
||||
}
|
||||
}
|
||||
return chunk.toString();
|
||||
}
|
||||
|
||||
public int compare(String s1, String s2) {
|
||||
int thisMarker = 0;
|
||||
int thatMarker = 0;
|
||||
int s1Length = s1.length();
|
||||
int s2Length = s2.length();
|
||||
|
||||
while (thisMarker < s1Length && thatMarker < s2Length) {
|
||||
String thisChunk = getChunk(s1, s1Length, thisMarker);
|
||||
thisMarker += thisChunk.length();
|
||||
|
||||
String thatChunk = getChunk(s2, s2Length, thatMarker);
|
||||
thatMarker += thatChunk.length();
|
||||
|
||||
// If both chunks contain numeric characters, sort them numerically
|
||||
int result = 0;
|
||||
if (isDigit(thisChunk.charAt(0)) && isDigit(thatChunk.charAt(0))) {
|
||||
// Simple chunk comparison by length.
|
||||
int thisChunkLength = thisChunk.length();
|
||||
result = thisChunkLength - thatChunk.length();
|
||||
// If equal, the first different number counts
|
||||
if (result == 0) {
|
||||
for (int i = 0; i < thisChunkLength; i++) {
|
||||
result = thisChunk.charAt(i) - thatChunk.charAt(i);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = thisChunk.compareTo(thatChunk);
|
||||
}
|
||||
|
||||
if (result != 0)
|
||||
return result;
|
||||
}
|
||||
|
||||
return s1Length - s2Length;
|
||||
}
|
||||
|
||||
}
|
||||
+3
-2
@@ -147,6 +147,7 @@
|
||||
<properties>
|
||||
<tycho-version>0.21.0</tycho-version>
|
||||
<gwt.version>2.7.0</gwt.version>
|
||||
<gwt.minVersion>2.7.0</gwt.minVersion>
|
||||
<gwt.workers>2</gwt.workers>
|
||||
<p2-target>race-analysis-p2-remote</p2-target><!--can be overidden through p2-target.local profile -->
|
||||
<!-- QUESTION: Which properties or settings are system dependent and differ across different machines/environments? QUESTION:
|
||||
@@ -170,6 +171,7 @@
|
||||
<!-- "Forward declaration" for better readability. The actual value should be defined in the local settings.xml, because
|
||||
of the differences between the CI-Build and the local setup. -->
|
||||
<parameters.proxy>
|
||||
-Dhttp.proxyHost=proxy.wdf.sap.corp -Dhttp.proxyPort=8080 -Dhttps.proxyHost=proxy.wdf.sap.corp -Dhttps.proxyPort=8080
|
||||
</parameters.proxy>
|
||||
<reportsdirectory>${project.build.directory}/surefire-reports</reportsdirectory>
|
||||
<skipTests>false</skipTests>
|
||||
@@ -327,8 +329,7 @@
|
||||
<artifactId>tycho-compiler-plugin</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<useJDK>BREE</useJDK>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
|
||||
Reference in new issue
Block a user