package tim.prune.function;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import tim.prune.App;
import tim.prune.GenericFunction;
import tim.prune.I18nManager;
import tim.prune.config.Config;
import tim.prune.data.RangeStats;
import tim.prune.data.Selection;
import tim.prune.data.Unit;
import tim.prune.gui.DisplayUtils;
import tim.prune.gui.profile.SpeedData;
/**
* Class to show the full range details in a separate popup
*/
public class FullRangeDetails extends GenericFunction
{
/** Dialog */
private JDialog _dialog = null;
/** Label for number of points */
private JLabel _numPointsLabel = null;
/** Label for number of segments */
private JLabel _numSegsLabel = null;
/** Label for the maximum speed */
private JLabel _maxSpeedLabel = null;
/** Label for heading of "total" column */
private JLabel _colTotalLabel = null;
/** Label for heading of "segments" column */
private JLabel _colSegmentsLabel = null;
/** Labels for distances */
private JLabel _totalDistanceLabel = null, _movingDistanceLabel = null;
/** Labels for durations */
private JLabel _totalDurationLabel = null, _movingDurationLabel = null;
/** Labels for climbs */
private JLabel _totalClimbLabel = null, _movingClimbLabel = null;
/** Labels for descents */
private JLabel _totalDescentLabel = null, _movingDescentLabel = null;
/** Labels for pace */
private JLabel _totalPaceLabel = null, _movingPaceLabel = null;
/** Labels for gradient */
private JLabel _totalGradientLabel = null, _movingGradientLabel = null;
/** Labels for speed */
private JLabel _totalSpeedLabel, _movingSpeedLabel = null;
/** Labels for vertical speed */
private JLabel _totalVertSpeedLabel, _movingVertSpeedLabel = null;
/**
* Constructor
* @param inApp App object
*/
public FullRangeDetails(App inApp)
{
super(inApp);
}
/** Get the name key */
public String getNameKey() {
return "function.fullrangedetails";
}
/**
* Begin the function
*/
public void begin()
{
if (_dialog == null)
{
_dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
_dialog.setLocationRelativeTo(_parentFrame);
_dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
_dialog.getContentPane().add(makeDialogComponents());
_dialog.pack();
}
updateDetails();
_dialog.setVisible(true);
}
/**
* Create dialog components
* @return Panel containing all gui elements in dialog
*/
private Component makeDialogComponents()
{
JPanel dialogPanel = new JPanel();
dialogPanel.setLayout(new BorderLayout(5, 5));
// Label at top
JLabel topLabel = new JLabel(I18nManager.getText("dialog.fullrangedetails.intro") + ":");
topLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
dialogPanel.add(topLabel, BorderLayout.NORTH);
// Details panel in middle
JPanel midPanel = new JPanel();
midPanel.setLayout(new GridLayout(0, 3, 6, 2));
midPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15));
// Number of points
JLabel pointsLabel = new JLabel(I18nManager.getText("details.track.points") + ": ");
pointsLabel.setHorizontalAlignment(JLabel.RIGHT);
midPanel.add(pointsLabel);
_numPointsLabel = new JLabel("100");
midPanel.add(_numPointsLabel);
midPanel.add(new JLabel(" "));
// Number of segments
JLabel segLabel = new JLabel(I18nManager.getText("details.range.numsegments") + ": ");
segLabel.setHorizontalAlignment(JLabel.RIGHT);
midPanel.add(segLabel);
_numSegsLabel = new JLabel("100");
midPanel.add(_numSegsLabel);
midPanel.add(new JLabel(" "));
// Maximum speed
JLabel maxSpeedLabel = new JLabel(I18nManager.getText("details.range.maxspeed") + ": ");
maxSpeedLabel.setHorizontalAlignment(JLabel.RIGHT);
midPanel.add(maxSpeedLabel);
_maxSpeedLabel = new JLabel("10 km/h");
midPanel.add(_maxSpeedLabel);
midPanel.add(new JLabel(" "));
// blank row
for (int i=0; i<3; i++) midPanel.add(new JLabel(" "));
// Row for column headings
midPanel.add(new JLabel(" "));
_colTotalLabel = new JLabel(I18nManager.getText("dialog.fullrangedetails.coltotal"));
midPanel.add(_colTotalLabel);
_colSegmentsLabel = new JLabel(I18nManager.getText("dialog.fullrangedetails.colsegments"));
midPanel.add(_colSegmentsLabel);
// Distance
JLabel distLabel = new JLabel(I18nManager.getText("fieldname.distance") + ": ");
distLabel.setHorizontalAlignment(JLabel.RIGHT);
midPanel.add(distLabel);
_totalDistanceLabel = new JLabel("5 km");
midPanel.add(_totalDistanceLabel);
_movingDistanceLabel = new JLabel("5 km");
midPanel.add(_movingDistanceLabel);
// Duration
JLabel durationLabel = new JLabel(I18nManager.getText("fieldname.duration") + ": ");
durationLabel.setHorizontalAlignment(JLabel.RIGHT);
midPanel.add(durationLabel);
_totalDurationLabel = new JLabel("15 min");
midPanel.add(_totalDurationLabel);
_movingDurationLabel = new JLabel("15 min");
midPanel.add(_movingDurationLabel);
// Speed
JLabel speedLabel = new JLabel(I18nManager.getText("details.range.avespeed") + ": ");
speedLabel.setHorizontalAlignment(JLabel.RIGHT);
midPanel.add(speedLabel);
_totalSpeedLabel = new JLabel("5.5 km/h");
midPanel.add(_totalSpeedLabel);
_movingSpeedLabel = new JLabel("5.5 km/h");
midPanel.add(_movingSpeedLabel);
// Pace
JLabel paceLabel = new JLabel(I18nManager.getText("details.range.pace") + ": ");
paceLabel.setHorizontalAlignment(JLabel.RIGHT);
midPanel.add(paceLabel);
_totalPaceLabel = new JLabel("8 min/km");
midPanel.add(_totalPaceLabel);
_movingPaceLabel = new JLabel("8 min/km");
midPanel.add(_movingPaceLabel);
// Climb
JLabel climbLabel = new JLabel(I18nManager.getText("details.range.climb") + ": ");
climbLabel.setHorizontalAlignment(JLabel.RIGHT);
midPanel.add(climbLabel);
_totalClimbLabel = new JLabel("1000 m");
midPanel.add(_totalClimbLabel);
_movingClimbLabel = new JLabel("1000 m");
midPanel.add(_movingClimbLabel);
// Descent
JLabel descentLabel = new JLabel(I18nManager.getText("details.range.descent") + ": ");
descentLabel.setHorizontalAlignment(JLabel.RIGHT);
midPanel.add(descentLabel);
_totalDescentLabel = new JLabel("1000 m");
midPanel.add(_totalDescentLabel);
_movingDescentLabel = new JLabel("1000 m");
midPanel.add(_movingDescentLabel);
// Gradient
JLabel gradientLabel = new JLabel(I18nManager.getText("details.range.gradient") + ": ");
gradientLabel.setHorizontalAlignment(JLabel.RIGHT);
midPanel.add(gradientLabel);
_totalGradientLabel = new JLabel("10 %");
midPanel.add(_totalGradientLabel);
_movingGradientLabel = new JLabel("10 %");
midPanel.add(_movingGradientLabel);
// Vertical speed
JLabel vSpeedLabel = new JLabel(I18nManager.getText("fieldname.verticalspeed") + ": ");
vSpeedLabel.setHorizontalAlignment(JLabel.RIGHT);
midPanel.add(vSpeedLabel);
_totalVertSpeedLabel = new JLabel("1 m/s");
midPanel.add(_totalVertSpeedLabel);
_movingVertSpeedLabel = new JLabel("1 m/s");
midPanel.add(_movingVertSpeedLabel);
dialogPanel.add(midPanel, BorderLayout.CENTER);
// button panel at bottom
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
JButton closeButton = new JButton(I18nManager.getText("button.close"));
closeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
_dialog.dispose();
}
});
closeButton.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent inE) {
if (inE.getKeyCode() == KeyEvent.VK_ESCAPE) {_dialog.dispose();}
super.keyPressed(inE);
}
});
buttonPanel.add(closeButton);
dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
return dialogPanel;
}
/**
* Update the labels with the current details
*/
private void updateDetails()
{
Selection selection = _app.getTrackInfo().getSelection();
// Do the calculations with a separate class
RangeStats stats = new RangeStats(_app.getTrackInfo().getTrack(), selection.getStart(), selection.getEnd());
// Number of points
_numPointsLabel.setText("" + stats.getNumPoints());
// Number of segments
_numSegsLabel.setText("" + stats.getNumSegments());
final boolean isMultiSegments = (stats.getNumSegments() > 1);
// Set visibility of third column accordingly
_movingDistanceLabel.setVisible(isMultiSegments);
_movingDurationLabel.setVisible(isMultiSegments || stats.getTimestampsOutOfSequence());
// FIXME: What to show if timestamps are out of sequence? Warning message?
_movingClimbLabel.setVisible(isMultiSegments);
_movingDescentLabel.setVisible(isMultiSegments);
_movingSpeedLabel.setVisible(isMultiSegments);
_movingPaceLabel.setVisible(isMultiSegments);
_movingGradientLabel.setVisible(isMultiSegments);
_movingVertSpeedLabel.setVisible(isMultiSegments);
// Total and moving distance in current units
final Unit distUnit = Config.getUnitSet().getDistanceUnit();
final String distUnitsStr = I18nManager.getText(distUnit.getShortnameKey());
_totalDistanceLabel.setText(DisplayUtils.roundedNumber(stats.getTotalDistance()) + " " + distUnitsStr);
_movingDistanceLabel.setText(DisplayUtils.roundedNumber(stats.getMovingDistance()) + " " + distUnitsStr);
// Duration
_totalDurationLabel.setText(DisplayUtils.buildDurationString(stats.getTotalDurationInSeconds()));
_movingDurationLabel.setText(DisplayUtils.buildDurationString(stats.getMovingDurationInSeconds()));
// Climb and descent
final Unit altUnit = Config.getUnitSet().getAltitudeUnit();
final String altUnitsStr = " " + I18nManager.getText(altUnit.getShortnameKey());
if (stats.getTotalAltitudeRange().hasRange()) {
_totalClimbLabel.setText(stats.getTotalAltitudeRange().getClimb(altUnit) + altUnitsStr);
_totalDescentLabel.setText(stats.getTotalAltitudeRange().getDescent(altUnit) + altUnitsStr);
}
else {
_totalClimbLabel.setText("");
_totalDescentLabel.setText("");
}
if (stats.getMovingAltitudeRange().hasRange()) {
_movingClimbLabel.setText(stats.getMovingAltitudeRange().getClimb(altUnit) + altUnitsStr);
_movingDescentLabel.setText(stats.getMovingAltitudeRange().getDescent(altUnit) + altUnitsStr);
}
else {
_movingClimbLabel.setText("");
_movingDescentLabel.setText("");
}
// Overall pace and speed
final String speedUnitsStr = I18nManager.getText(Config.getUnitSet().getSpeedUnit().getShortnameKey());
long numSecs = stats.getTotalDurationInSeconds();
double dist = stats.getTotalDistance();
if (numSecs > 0 && dist > 0)
{
_totalSpeedLabel.setText(DisplayUtils.roundedNumber(dist/numSecs*3600.0) + " " + speedUnitsStr);
_totalPaceLabel.setText(DisplayUtils.buildDurationString((long) (numSecs/dist))
+ " / " + distUnitsStr);
}
else {
_totalSpeedLabel.setText("");
_totalPaceLabel.setText("");
}
// and same for within the segments
numSecs = stats.getMovingDurationInSeconds();
dist = stats.getMovingDistance();
if (numSecs > 0 && dist > 0)
{
_movingSpeedLabel.setText(DisplayUtils.roundedNumber(dist/numSecs*3600.0) + " " + speedUnitsStr);
_movingPaceLabel.setText(DisplayUtils.buildDurationString((long) (numSecs/dist))
+ " / " + distUnitsStr);
}
else {
_movingSpeedLabel.setText("");
_movingPaceLabel.setText("");
}
// Gradient
if (stats.getTotalAltitudeRange().hasRange()) {
_totalGradientLabel.setText(DisplayUtils.formatOneDp(stats.getTotalGradient()) + " %");
}
else {
_totalGradientLabel.setText("");
}
if (stats.getMovingAltitudeRange().hasRange()) {
_movingGradientLabel.setText(DisplayUtils.formatOneDp(stats.getMovingGradient()) + " %");
}
else {
_movingGradientLabel.setText("");
}
// Maximum speed
SpeedData speeds = new SpeedData(_app.getTrackInfo().getTrack());
speeds.init(Config.getUnitSet());
double maxSpeed = 0.0;
for (int i=selection.getStart(); i<=selection.getEnd(); i++)
{
if (speeds.hasData(i) && (speeds.getData(i) > maxSpeed)) {
maxSpeed = speeds.getData(i);
}
}
if (maxSpeed > 0.0) {
_maxSpeedLabel.setText(DisplayUtils.roundedNumber(maxSpeed) + " " + speedUnitsStr);
}
else {
_maxSpeedLabel.setText("");
}
// vertical speed
final String vertSpeedUnitsStr = I18nManager.getText(Config.getUnitSet().getVerticalSpeedUnit().getShortnameKey());
if (stats.getMovingAltitudeRange().hasRange() && stats.getTotalDurationInSeconds() > 0)
{
// got an altitude and time - do totals
_totalVertSpeedLabel.setText(DisplayUtils.roundedNumber(stats.getTotalVerticalSpeed()) + " " + vertSpeedUnitsStr);
_movingVertSpeedLabel.setText(DisplayUtils.roundedNumber(stats.getMovingVerticalSpeed()) + " " + vertSpeedUnitsStr);
}
else
{
// no vertical speed available
_totalVertSpeedLabel.setText("");
_movingVertSpeedLabel.setText("");
}
}
}