1 package tim.prune.function;
3 import java.awt.BorderLayout;
4 import java.awt.Component;
5 import java.awt.FlowLayout;
6 import java.awt.GridLayout;
7 import java.awt.event.ActionEvent;
8 import java.awt.event.ActionListener;
9 import java.text.NumberFormat;
11 import javax.swing.BorderFactory;
12 import javax.swing.JButton;
13 import javax.swing.JDialog;
14 import javax.swing.JLabel;
15 import javax.swing.JPanel;
18 import tim.prune.GenericFunction;
19 import tim.prune.I18nManager;
20 import tim.prune.config.Config;
21 import tim.prune.data.Altitude;
22 import tim.prune.data.Distance;
23 import tim.prune.data.Selection;
24 import tim.prune.gui.DisplayUtils;
25 import tim.prune.gui.profile.SpeedData;
28 * Class to show the full range details in a separate popup
30 public class FullRangeDetails extends GenericFunction
33 private JDialog _dialog = null;
34 /** Label for number of segments */
35 private JLabel _numSegsLabel = null;
37 private JLabel _paceLabel = null;
38 /** Label for gradient */
39 private JLabel _gradientLabel = null;
40 /** Moving distance, speed */
41 private JLabel _movingDistanceLabel = null, _aveMovingSpeedLabel = null;
42 private JLabel _maxSpeedLabel = null;
43 /** Number formatter for one decimal place */
44 private static final NumberFormat FORMAT_ONE_DP = NumberFormat.getNumberInstance();
45 /** Flexible number formatter for different decimal places */
46 private NumberFormat _distanceFormatter = NumberFormat.getInstance();
50 * @param inApp App object
52 public FullRangeDetails(App inApp)
55 FORMAT_ONE_DP.setMaximumFractionDigits(1);
56 FORMAT_ONE_DP.setMinimumFractionDigits(1);
59 /** Get the name key */
60 public String getNameKey() {
61 return "function.fullrangedetails";
71 _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
72 _dialog.setLocationRelativeTo(_parentFrame);
73 _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
74 _dialog.getContentPane().add(makeDialogComponents());
78 _dialog.setVisible(true);
82 * Create dialog components
83 * @return Panel containing all gui elements in dialog
85 private Component makeDialogComponents()
87 JPanel dialogPanel = new JPanel();
88 dialogPanel.setLayout(new BorderLayout(5, 5));
90 JLabel topLabel = new JLabel(I18nManager.getText("dialog.fullrangedetails.intro"));
91 topLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
92 dialogPanel.add(topLabel, BorderLayout.NORTH);
94 // Details panel in middle
95 JPanel midPanel = new JPanel();
96 midPanel.setLayout(new GridLayout(0, 2, 6, 2));
97 midPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15));
99 JLabel segLabel = new JLabel(I18nManager.getText("details.range.numsegments") + ": ");
100 segLabel.setHorizontalAlignment(JLabel.RIGHT);
101 midPanel.add(segLabel);
102 _numSegsLabel = new JLabel("100");
103 midPanel.add(_numSegsLabel);
105 JLabel paceLabel = new JLabel(I18nManager.getText("details.range.pace") + ": ");
106 paceLabel.setHorizontalAlignment(JLabel.RIGHT);
107 midPanel.add(paceLabel);
108 _paceLabel = new JLabel("8 min/km");
109 midPanel.add(_paceLabel);
111 JLabel gradientLabel = new JLabel(I18nManager.getText("details.range.gradient") + ": ");
112 gradientLabel.setHorizontalAlignment(JLabel.RIGHT);
113 midPanel.add(gradientLabel);
114 _gradientLabel = new JLabel("10 %");
115 midPanel.add(_gradientLabel);
117 JLabel movingDistLabel = new JLabel(I18nManager.getText("fieldname.movingdistance") + ": ");
118 movingDistLabel.setHorizontalAlignment(JLabel.RIGHT);
119 midPanel.add(movingDistLabel);
120 _movingDistanceLabel = new JLabel("5 km");
121 midPanel.add(_movingDistanceLabel);
123 JLabel movingSpeedLabel = new JLabel(I18nManager.getText("details.range.avemovingspeed") + ": ");
124 movingSpeedLabel.setHorizontalAlignment(JLabel.RIGHT);
125 midPanel.add(movingSpeedLabel);
126 _aveMovingSpeedLabel = new JLabel("5 km/h");
127 midPanel.add(_aveMovingSpeedLabel);
129 JLabel maxSpeedLabel = new JLabel(I18nManager.getText("details.range.maxspeed") + ": ");
130 maxSpeedLabel.setHorizontalAlignment(JLabel.RIGHT);
131 midPanel.add(maxSpeedLabel);
132 _maxSpeedLabel = new JLabel("10 km/h");
133 midPanel.add(_maxSpeedLabel);
135 dialogPanel.add(midPanel, BorderLayout.CENTER);
136 // button panel at bottom
137 JPanel buttonPanel = new JPanel();
138 buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
139 JButton closeButton = new JButton(I18nManager.getText("button.close"));
140 closeButton.addActionListener(new ActionListener() {
141 public void actionPerformed(ActionEvent e)
146 buttonPanel.add(closeButton);
147 dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
153 * Update the labels with the current details
155 private void updateDetails()
157 Selection selection = _app.getTrackInfo().getSelection();
158 // Number of segments
159 _numSegsLabel.setText("" + selection.getNumSegments());
161 if (selection.getNumSeconds() > 0)
163 boolean useMetric = Config.getConfigBoolean(Config.KEY_METRIC_UNITS);
164 Distance.Units distUnits = useMetric?Distance.Units.KILOMETRES:Distance.Units.MILES;
165 String distUnitsStr = I18nManager.getText(useMetric?"units.kilometres.short":"units.miles.short");
166 _paceLabel.setText(DisplayUtils.buildDurationString(
167 (long) (selection.getNumSeconds()/selection.getDistance(distUnits)))
168 + " / " + distUnitsStr);
171 _paceLabel.setText("");
174 Altitude firstAlt = _app.getTrackInfo().getTrack().getPoint(selection.getStart()).getAltitude();
175 Altitude lastAlt = _app.getTrackInfo().getTrack().getPoint(selection.getEnd()).getAltitude();
176 double metreDist = selection.getDistance(Distance.Units.METRES);
177 if (firstAlt.isValid() && lastAlt.isValid() && metreDist > 0.0)
179 // got an altitude and range
180 int altDiffInMetres = lastAlt.getValue(Altitude.Format.METRES) - firstAlt.getValue(Altitude.Format.METRES);
181 double gradient = altDiffInMetres * 100.0 / metreDist;
182 _gradientLabel.setText(FORMAT_ONE_DP.format(gradient) + " %");
186 _gradientLabel.setText("");
189 // Show moving distance and average even when number of segments is 1
190 final boolean isMetric = Config.getConfigBoolean(Config.KEY_METRIC_UNITS);
191 final Distance.Units distUnits = isMetric?Distance.Units.KILOMETRES:Distance.Units.MILES;
192 final String distUnitsStr = I18nManager.getText(isMetric?"units.kilometres.short":"units.miles.short");
193 final String speedUnitsStr = I18nManager.getText(isMetric?"units.kmh":"units.mph");
195 _movingDistanceLabel.setText(roundedNumber(selection.getMovingDistance(distUnits)) + " " + distUnitsStr);
196 // Moving average speed
197 long numSecs = selection.getMovingSeconds();
199 _aveMovingSpeedLabel.setText(roundedNumber(selection.getMovingDistance(distUnits)/numSecs*3600.0)
200 + " " + speedUnitsStr);
203 _aveMovingSpeedLabel.setText("");
207 SpeedData speeds = new SpeedData(_app.getTrackInfo().getTrack());
209 double maxSpeed = 0.0;
210 for (int i=selection.getStart(); i<=selection.getEnd(); i++) {
211 if (speeds.hasData(i) && (speeds.getData(i) > maxSpeed)) {
212 maxSpeed = speeds.getData(i);
215 if (maxSpeed > 0.0) {
216 _maxSpeedLabel.setText(roundedNumber(maxSpeed) + " " + speedUnitsStr);
219 _maxSpeedLabel.setText("");
224 * Format a number to a sensible precision
225 * @param inDist distance
226 * @return formatted String
228 private String roundedNumber(double inDist)
230 // Set precision of formatter
234 else if (inDist < 10.0)
236 else if (inDist < 100.0)
239 _distanceFormatter.setMaximumFractionDigits(numDigits);
240 _distanceFormatter.setMinimumFractionDigits(numDigits);
241 return _distanceFormatter.format(inDist);