Commit 9ff1a382 authored by MarkG's avatar MarkG Committed by TIGERs GitLab
Browse files

Resolve "Refactor visualizer to improve usability and code quality"

Closes #1731

See merge request main/Sumatra!1502

sumatra-commit: 3b6a9d00321678b9cb1746970a6c61ed8a136c71
parent e5c6a8dd
Pipeline #17589 passed with stage
in 4 minutes and 47 seconds
......@@ -11,7 +11,6 @@ dependencies {
implementation project(':common-math')
implementation project(':common-gui')
implementation project(':sumatra-model')
implementation project(':sumatra-gui-visualizer')
implementation project(':moduli-autoreferee')
implementation project(':moduli-record')
implementation project(':moduli-referee')
......
/*
* Copyright (c) 2009 - 2020, DHBW Mannheim - TIGERs Mannheim
* Copyright (c) 2009 - 2022, DHBW Mannheim - TIGERs Mannheim
*/
package edu.tigers.autoref.presenter;
......@@ -9,73 +9,52 @@ import edu.tigers.autoreferee.IAutoRefObserver;
import edu.tigers.autoreferee.engine.EAutoRefMode;
import edu.tigers.autoreferee.engine.detector.EGameEventDetectorType;
import edu.tigers.autoreferee.module.AutoRefModule;
import edu.tigers.moduli.listenerVariables.ModulesState;
import edu.tigers.sumatra.components.EnumCheckBoxPanel.IEnumPanelObserver;
import edu.tigers.sumatra.model.SumatraModel;
import edu.tigers.sumatra.referee.gameevent.IGameEvent;
import edu.tigers.sumatra.views.ISumatraView;
import edu.tigers.sumatra.views.ISumatraViewPresenter;
import lombok.Getter;
import java.awt.Component;
import java.awt.EventQueue;
import java.util.Optional;
public class AutoRefPresenter
implements ISumatraViewPresenter, IStartStopPanelObserver, IAutoRefObserver
public class AutoRefPresenter implements ISumatraViewPresenter, IStartStopPanelObserver, IAutoRefObserver
{
private AutoRefMainPanel mainPanel = new AutoRefMainPanel();
@Getter
private AutoRefMainPanel viewPanel = new AutoRefMainPanel();
private final GameEventDetectorObserver gameEventDetectorObserver = new GameEventDetectorObserver();
@Override
public Component getComponent()
public void onStartModuli()
{
return mainPanel;
ISumatraViewPresenter.super.onStartModuli();
SumatraModel.getInstance().getModuleOpt(AutoRefModule.class).ifPresent(autoRef -> autoRef.addObserver(this));
SumatraModel.getInstance().getModuleOpt(AutoRefModule.class)
.ifPresent(autoRef -> viewPanel.getStartStopPanel().setAutoRefMode(autoRef.getMode())
);
EventQueue.invokeLater(() -> viewPanel.setEnabled(true));
viewPanel.getStartStopPanel().addObserver(this);
viewPanel.getGameEventDetectorPanel().addObserver(gameEventDetectorObserver);
viewPanel.getGameEventDetectorPanel().setSelectedBoxes(EGameEventDetectorType.valuesEnabledByDefault());
}
@Override
public ISumatraView getSumatraView()
public void onStopModuli()
{
return mainPanel;
}
@Override
public void onModuliStateChanged(final ModulesState state)
{
Optional<AutoRefModule> optModule = SumatraModel.getInstance().getModuleOpt(AutoRefModule.class);
if (optModule.isEmpty())
{
return;
}
switch (state)
{
case ACTIVE:
optModule.ifPresent(autoRef -> autoRef.addObserver(this));
EventQueue.invokeLater(() -> mainPanel.setEnabled(true));
mainPanel.getStartStopPanel().addObserver(this);
mainPanel.getGameEventDetectorPanel().addObserver(gameEventDetectorObserver);
mainPanel.getGameEventDetectorPanel().setSelectedBoxes(EGameEventDetectorType.valuesEnabledByDefault());
optModule.ifPresent(autoRef -> mainPanel.getStartStopPanel().setAutoRefMode(autoRef.getMode()));
break;
case NOT_LOADED:
case RESOLVED:
optModule.ifPresent(autoRef -> autoRef.removeObserver(this));
mainPanel.getStartStopPanel().removeObserver(this);
mainPanel.getGameEventDetectorPanel().removeObserver(gameEventDetectorObserver);
EventQueue.invokeLater(() -> mainPanel.setEnabled(false));
break;
}
ISumatraViewPresenter.super.onStopModuli();
SumatraModel.getInstance().getModuleOpt(AutoRefModule.class).ifPresent(autoRef -> autoRef.removeObserver(this));
viewPanel.getStartStopPanel().removeObserver(this);
viewPanel.getGameEventDetectorPanel().removeObserver(gameEventDetectorObserver);
EventQueue.invokeLater(() -> viewPanel.setEnabled(false));
}
@Override
public void onAutoRefModeChanged(EAutoRefMode mode)
{
EventQueue.invokeLater(() -> mainPanel.getStartStopPanel().setAutoRefMode(mode));
EventQueue.invokeLater(() -> viewPanel.getStartStopPanel().setAutoRefMode(mode));
}
......
/*
* Copyright (c) 2009 - 2017, DHBW Mannheim - TIGERs Mannheim
* Copyright (c) 2009 - 2022, DHBW Mannheim - TIGERs Mannheim
*/
package edu.tigers.autoref.presenter;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Timer;
import com.github.g3force.configurable.ConfigRegistration;
import com.github.g3force.configurable.IConfigClient;
import com.github.g3force.configurable.IConfigObserver;
import edu.tigers.autoref.model.ballspeed.BallSpeedModel;
import edu.tigers.autoref.view.ballspeed.BallSpeedPanel;
import edu.tigers.autoref.view.ballspeed.IBallSpeedPanelListener;
import edu.tigers.autoref.view.generic.FixedTimeRangeChartPanel;
import edu.tigers.moduli.IModuliStateObserver;
import edu.tigers.moduli.exceptions.ModuleNotFoundException;
import edu.tigers.moduli.listenerVariables.ModulesState;
import edu.tigers.sumatra.geometry.RuleConstraints;
import edu.tigers.sumatra.model.SumatraModel;
import edu.tigers.sumatra.referee.data.EGameState;
import edu.tigers.sumatra.views.ISumatraView;
import edu.tigers.sumatra.views.ISumatraViewPresenter;
import edu.tigers.sumatra.wp.AWorldPredictor;
import edu.tigers.sumatra.wp.IWorldFrameObserver;
import edu.tigers.sumatra.wp.data.WorldFrameWrapper;
import lombok.Getter;
import javax.swing.Timer;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.TimeUnit;
/**
......@@ -47,15 +39,21 @@ import edu.tigers.sumatra.wp.data.WorldFrameWrapper;
* of the world frames directly but maintains its own timestamp value that is incremented with the time delta of two
* consecutive frames. To avoid gaps the timestamp value is not updated when the plot is paused. Because of this new
* data points are displayed directly after the last points before the pause.
*
* @author "Lukas Magel"
*/
public class BallSpeedPresenter implements ISumatraViewPresenter, IWorldFrameObserver, IModuliStateObserver,
IBallSpeedPanelListener, ActionListener
{
/** The period in ms at the end of which the chart is updated */
/**
* The period in ms at the end of which the chart is updated
*/
private static final int CHART_UPDATE_PERIOD = 50;
/** The absolute time range displayed in the chart in seconds */
@Getter
private BallSpeedPanel viewPanel;
/**
* The absolute time range displayed in the chart in seconds
*/
private int timeRange = 20;
private boolean pauseWhenNotRunning = false;
private boolean pauseRequested = false;
......@@ -64,102 +62,105 @@ public class BallSpeedPresenter implements ISumatraViewPresenter, IWorldFrameObs
private long curTime = 0L;
private BallSpeedModel model = new BallSpeedModel();
private Timer chartTimer;
private BallSpeedPanel panel;
/**
* Default constructor
*/
public BallSpeedPresenter()
{
panel = new BallSpeedPanel(getTimeRange(), TimeUnit.MILLISECONDS.toNanos(CHART_UPDATE_PERIOD));
panel.addObserver(this);
panel.setMaxBallVelocityLine(RuleConstraints.getMaxBallSpeed());
viewPanel = new BallSpeedPanel(getTimeRange(), TimeUnit.MILLISECONDS.toNanos(CHART_UPDATE_PERIOD));
viewPanel.setMaxBallVelocityLine(RuleConstraints.getMaxBallSpeed());
chartTimer = new Timer(CHART_UPDATE_PERIOD, this);
chartTimer.setDelay(CHART_UPDATE_PERIOD);
ConfigRegistration.registerConfigurableCallback("autoreferee", new IConfigObserver()
{
@Override
public void afterApply(final IConfigClient configClient)
{
panel.setMaxBallVelocityLine(RuleConstraints.getMaxBallSpeed());
viewPanel.setMaxBallVelocityLine(RuleConstraints.getMaxBallSpeed());
}
});
}
/**
* @return time range in naoseconds
*/
private long getTimeRange()
{
return TimeUnit.SECONDS.toNanos(timeRange);
}
@Override
public Component getComponent()
public void onStartModuli()
{
return panel;
ISumatraViewPresenter.super.onStartModuli();
SumatraModel.getInstance().getModuleOpt(AWorldPredictor.class).ifPresent(predictor -> {
predictor.addObserver(this);
chartTimer.start();
});
}
@Override
public ISumatraView getSumatraView()
public void onStopModuli()
{
return panel;
ISumatraViewPresenter.super.onStopModuli();
chartTimer.stop();
SumatraModel.getInstance().getModuleOpt(AWorldPredictor.class).ifPresent(
predictor -> predictor.removeObserver(this)
);
}
/**
* @return time range in naoseconds
*/
private long getTimeRange()
@Override
public void onStart()
{
return TimeUnit.SECONDS.toNanos(timeRange);
ISumatraViewPresenter.super.onStart();
viewPanel.addObserver(this);
}
@Override
public void onModuliStateChanged(final ModulesState state)
public void onStop()
{
Optional<AWorldPredictor> optPredictor = getPredictor();
if (state == ModulesState.ACTIVE)
{
optPredictor.ifPresent(predictor -> {
predictor.addObserver(this);
chartTimer.start();
});
} else if (state == ModulesState.RESOLVED)
{
chartTimer.stop();
optPredictor.ifPresent(predictor -> predictor.removeObserver(this));
}
ISumatraViewPresenter.super.onStop();
viewPanel.removeObserver(this);
}
@Override
public void onNewWorldFrame(final WorldFrameWrapper wFrameWrapper)
{
EventQueue.invokeLater(() -> model.update(wFrameWrapper));
}
@Override
public void actionPerformed(final ActionEvent e)
{
updateChart();
model.reset();
}
private void updateChart()
{
updateChartState();
if (chartState == PauseState.RUNNING)
{
curTime += TimeUnit.MILLISECONDS.toNanos(CHART_UPDATE_PERIOD);
panel.addPoint(curTime, model.getLastBallSpeed());
panel.addInitialVelPoint(curTime, model.getLastEstimatedBallSpeed());
viewPanel.addPoint(curTime, model.getLastBallSpeed());
viewPanel.addInitialVelPoint(curTime, model.getLastEstimatedBallSpeed());
}
}
/**
* Updates the state of the chart according to the gamestate and requests from the user.
* The chart can be in a RUNNING, MANUAL (manually stopped by the user) or AUTO (automatically stopped
......@@ -182,7 +183,7 @@ public class BallSpeedPresenter implements ISumatraViewPresenter, IWorldFrameObs
chartState = PauseState.AUTO;
}
}
/*
* A manualy pause request will override the automatic pause/resume mechanism and will cause the chart to be
* paused until the resume button is pressed
......@@ -202,41 +203,27 @@ public class BallSpeedPresenter implements ISumatraViewPresenter, IWorldFrameObs
resumeRequested = false;
}
}
private Optional<AWorldPredictor> getPredictor()
{
try
{
AWorldPredictor predictor = SumatraModel.getInstance().getModule(AWorldPredictor.class);
return Optional.of(predictor);
} catch (ModuleNotFoundException e)
{
Logger.getAnonymousLogger().log(Level.FINE, "WP Module not found.", e);
}
return Optional.empty();
}
@Override
public void pauseButtonPressed()
{
pauseRequested = true;
}
@Override
public void resumeButtonPressed()
{
resumeRequested = true;
}
@Override
public void stopChartValueChanged(final boolean value)
{
pauseWhenNotRunning = value;
/*
* The updateChartState() method only triggers on state transitions that occur after the pauseWhenNotRunning
* variable has been altered. To also stop/restart the chart if the pauseWhenNotRunning feature is first
......@@ -256,26 +243,32 @@ public class BallSpeedPresenter implements ISumatraViewPresenter, IWorldFrameObs
}
}
}
@Override
public void timeRangeSliderValueChanged(final int value)
{
timeRange = value;
panel.setTimeRange(getTimeRange());
viewPanel.setTimeRange(getTimeRange());
curTime = 0;
}
private enum PauseState
{
/** The chart has been paused manually by the user */
/**
* The chart has been paused manually by the user
*/
MANUAL,
/** The chart has been paused through the auto pause setting if the gamestate is not running */
/**
* The chart has been paused through the auto pause setting if the gamestate is not running
*/
AUTO,
/** The chart is running */
/**
* The chart is running
*/
RUNNING
}
}
/*
* Copyright (c) 2009 - 2021, DHBW Mannheim - TIGERs Mannheim
* Copyright (c) 2009 - 2022, DHBW Mannheim - TIGERs Mannheim
*/
package edu.tigers.autoref.presenter;
......@@ -19,15 +19,14 @@ import edu.tigers.sumatra.components.EnumCheckBoxPanel;
import edu.tigers.sumatra.model.SumatraModel;
import edu.tigers.sumatra.referee.data.GameEventProposalGroup;
import edu.tigers.sumatra.referee.gameevent.IGameEvent;
import edu.tigers.sumatra.views.ISumatraView;
import edu.tigers.sumatra.views.ISumatraViewPresenter;
import edu.tigers.sumatra.wp.AWorldPredictor;
import edu.tigers.sumatra.wp.IWorldFrameObserver;
import edu.tigers.sumatra.wp.data.WorldFrameWrapper;
import lombok.Getter;
import org.apache.commons.lang.StringUtils;
import javax.swing.SwingUtilities;
import java.awt.Component;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
......@@ -37,19 +36,21 @@ import java.util.Set;
import java.util.stream.Collectors;
public class GameLogPresenter implements ISumatraViewPresenter, IAutoRefObserver,
EnumCheckBoxPanel.IEnumPanelObserver<ELogEntryType>, IWorldFrameObserver
public class GameLogPresenter
implements ISumatraViewPresenter, IAutoRefObserver, EnumCheckBoxPanel.IEnumPanelObserver<ELogEntryType>,
IWorldFrameObserver
{
private static final String ACTIVE_LOG_TYPES_KEY = GameLogPresenter.class + ".activeLogTypes";
private GameLogTableModel gameLogTableModel = new GameLogTableModel();
private GameLogPanel gameLogPanel = new GameLogPanel(gameLogTableModel);
private final GameLogTableModel gameLogTableModel = new GameLogTableModel();
@Getter
private GameLogPanel viewPanel = new GameLogPanel(gameLogTableModel);
private WorldFrameWrapper lastWorldFrameWrapper;
public GameLogPresenter()
{
EnumCheckBoxPanel<ELogEntryType> logPanel = gameLogPanel.getLogTypePanel();
EnumCheckBoxPanel<ELogEntryType> logPanel = viewPanel.getLogTypePanel();
Set<ELogEntryType> types = new HashSet<>();
String activeLogTypes = SumatraModel.getInstance().getUserProperty(ACTIVE_LOG_TYPES_KEY);
......@@ -65,26 +66,12 @@ public class GameLogPresenter implements ISumatraViewPresenter, IAutoRefObserver
.forEach(types::add);
}
logPanel.setSelectedBoxes(types);
gameLogPanel.setActiveLogTypes(types);
viewPanel.setActiveLogTypes(types);
logPanel.addObserver(this);
}
@Override
public Component getComponent()
{
return gameLogPanel;
}
@Override
public ISumatraView getSumatraView()
{
return gameLogPanel;
}
@Override
public void onNewWorldFrame(final WorldFrameWrapper wfw)
{
......@@ -148,7 +135,7 @@ public class GameLogPresenter implements ISumatraViewPresenter, IAutoRefObserver
List<IGameEvent> lastProposals = lastWorldFrameWrapper.getRefereeMsg().getGameEventProposalGroups().stream()
.map(GameEventProposalGroup::getGameEvents)
.flatMap(Collection::stream)
.collect(Collectors.toList());
.toList();
proposals.removeAll(lastProposals);
for (IGameEvent gameEvent : proposals)
{
......@@ -193,8 +180,8 @@ public class GameLogPresenter implements ISumatraViewPresenter, IAutoRefObserver
@Override
public void onValueTicked(final ELogEntryType type, final boolean value)
{
Set<ELogEntryType> activeTypes = gameLogPanel.getLogTypePanel().getValues();
gameLogPanel.setActiveLogTypes(activeTypes);
Set<ELogEntryType> activeTypes = viewPanel.getLogTypePanel().getValues();
viewPanel.setActiveLogTypes(activeTypes);
String propValue = StringUtils.join(activeTypes, ",");
SumatraModel.getInstance().setUserProperty(ACTIVE_LOG_TYPES_KEY, propValue);
}
......
/*
* *********************************************************
* Copyright (c) 2009 - 2016, DHBW Mannheim - Tigers Mannheim
* Project: TIGERS - Sumatra
* Date: Jun 15, 2016
* Author(s): "Lukas Magel"
* *********************************************************
* Copyright (c) 2009 - 2022, DHBW Mannheim - TIGERs Mannheim
*/
package edu.tigers.autoref.view.ballspeed;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.util.concurrent.TimeUnit;
import edu.tigers.autoref.view.generic.FixedTimeRangeChartPanel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
......@@ -19,45 +11,50 @@ import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingConstants;
import edu.tigers.autoref.view.generic.FixedTimeRangeChartPanel;
import edu.tigers.sumatra.components.BasePanel;
import edu.tigers.sumatra.views.ISumatraView;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.io.Serial;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
/**
* @author "Lukas Magel"
*/