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;
27 * Class to show the full range details in a separate popup
29 public class FullRangeDetails extends GenericFunction
32 private JDialog _dialog = null;
33 /** Label for number of segments */
34 private JLabel _numSegsLabel = null;
36 private JLabel _paceLabel = null;
37 /** Label for gradient */
38 private JLabel _gradientLabel = null;
39 /** Moving distance, speed */
40 private JLabel _movingDistanceLabel = null, _aveMovingSpeedLabel = null;
41 /** Number formatter for one decimal place */
42 private static final NumberFormat FORMAT_ONE_DP = NumberFormat.getNumberInstance();
43 /** Flexible number formatter for different decimal places */
44 private NumberFormat _distanceFormatter = NumberFormat.getInstance();
48 * @param inApp App object
50 public FullRangeDetails(App inApp)
53 FORMAT_ONE_DP.setMaximumFractionDigits(1);
54 FORMAT_ONE_DP.setMinimumFractionDigits(1);
57 /** Get the name key */
58 public String getNameKey() {
59 return "function.fullrangedetails";
69 _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
70 _dialog.setLocationRelativeTo(_parentFrame);
71 _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
72 _dialog.getContentPane().add(makeDialogComponents());
76 _dialog.setVisible(true);
80 * Create dialog components
81 * @return Panel containing all gui elements in dialog
83 private Component makeDialogComponents()
85 JPanel dialogPanel = new JPanel();
86 dialogPanel.setLayout(new BorderLayout(5, 5));
88 JLabel topLabel = new JLabel(I18nManager.getText("dialog.fullrangedetails.intro"));
89 topLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
90 dialogPanel.add(topLabel, BorderLayout.NORTH);
92 // Details panel in middle
93 JPanel midPanel = new JPanel();
94 midPanel.setLayout(new GridLayout(0, 2, 6, 2));
95 midPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15));
97 JLabel segLabel = new JLabel(I18nManager.getText("details.range.numsegments") + ": ");
98 segLabel.setHorizontalAlignment(JLabel.RIGHT);
99 midPanel.add(segLabel);
100 _numSegsLabel = new JLabel("100");
101 midPanel.add(_numSegsLabel);
103 JLabel paceLabel = new JLabel(I18nManager.getText("details.range.pace") + ": ");
104 paceLabel.setHorizontalAlignment(JLabel.RIGHT);
105 midPanel.add(paceLabel);
106 _paceLabel = new JLabel("8 min/km");
107 midPanel.add(_paceLabel);
109 JLabel gradientLabel = new JLabel(I18nManager.getText("details.range.gradient") + ": ");
110 gradientLabel.setHorizontalAlignment(JLabel.RIGHT);
111 midPanel.add(gradientLabel);
112 _gradientLabel = new JLabel("10 %");
113 midPanel.add(_gradientLabel);
115 JLabel movingDistLabel = new JLabel(I18nManager.getText("fieldname.movingdistance") + ": ");
116 movingDistLabel.setHorizontalAlignment(JLabel.RIGHT);
117 midPanel.add(movingDistLabel);
118 _movingDistanceLabel = new JLabel("5 km");
119 midPanel.add(_movingDistanceLabel);
121 JLabel movingSpeedLabel = new JLabel(I18nManager.getText("details.range.avemovingspeed") + ": ");
122 movingSpeedLabel.setHorizontalAlignment(JLabel.RIGHT);
123 midPanel.add(movingSpeedLabel);
124 _aveMovingSpeedLabel = new JLabel("5 km/h");
125 midPanel.add(_aveMovingSpeedLabel);
127 dialogPanel.add(midPanel, BorderLayout.CENTER);
128 // button panel at bottom
129 JPanel buttonPanel = new JPanel();
130 buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
131 JButton closeButton = new JButton(I18nManager.getText("button.close"));
132 closeButton.addActionListener(new ActionListener() {
133 public void actionPerformed(ActionEvent e)
138 buttonPanel.add(closeButton);
139 dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
145 * Update the labels with the current details
147 private void updateDetails()
149 Selection selection = _app.getTrackInfo().getSelection();
150 // Number of segments
151 _numSegsLabel.setText("" + selection.getNumSegments());
153 if (selection.getNumSeconds() > 0)
155 boolean useMetric = Config.getConfigBoolean(Config.KEY_METRIC_UNITS);
156 Distance.Units distUnits = useMetric?Distance.Units.KILOMETRES:Distance.Units.MILES;
157 String distUnitsStr = I18nManager.getText(useMetric?"units.kilometres.short":"units.miles.short");
158 _paceLabel.setText(DisplayUtils.buildDurationString(
159 (long) (selection.getNumSeconds()/selection.getDistance(distUnits)))
160 + " / " + distUnitsStr);
163 _paceLabel.setText("");
166 Altitude firstAlt = _app.getTrackInfo().getTrack().getPoint(selection.getStart()).getAltitude();
167 Altitude lastAlt = _app.getTrackInfo().getTrack().getPoint(selection.getEnd()).getAltitude();
168 double metreDist = selection.getDistance(Distance.Units.METRES);
169 if (firstAlt.isValid() && lastAlt.isValid() && metreDist > 0.0)
171 // got an altitude and range
172 int altDiffInMetres = lastAlt.getValue(Altitude.Format.METRES) - firstAlt.getValue(Altitude.Format.METRES);
173 double gradient = altDiffInMetres * 100.0 / metreDist;
174 _gradientLabel.setText(FORMAT_ONE_DP.format(gradient) + " %");
178 _gradientLabel.setText("");
181 // Show moving distance and average even when number of segments is 1
182 final boolean isMetric = Config.getConfigBoolean(Config.KEY_METRIC_UNITS);
183 final Distance.Units distUnits = isMetric?Distance.Units.KILOMETRES:Distance.Units.MILES;
184 final String distUnitsStr = I18nManager.getText(isMetric?"units.kilometres.short":"units.miles.short");
185 final String speedUnitsStr = I18nManager.getText(isMetric?"units.kmh":"units.mph");
187 _movingDistanceLabel.setText(roundedNumber(selection.getMovingDistance(distUnits)) + " " + distUnitsStr);
188 // Moving average speed
189 long numSecs = selection.getMovingSeconds();
191 _aveMovingSpeedLabel.setText(roundedNumber(selection.getMovingDistance(distUnits)/numSecs*3600.0)
192 + " " + speedUnitsStr);
195 _aveMovingSpeedLabel.setText("");
200 * Format a number to a sensible precision
201 * @param inDist distance
202 * @return formatted String
204 private String roundedNumber(double inDist)
206 // Set precision of formatter
210 else if (inDist < 10.0)
212 else if (inDist < 100.0)
215 _distanceFormatter.setMaximumFractionDigits(numDigits);
216 _distanceFormatter.setMinimumFractionDigits(numDigits);
217 return _distanceFormatter.format(inDist);