]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/function/FullRangeDetails.java
ed86ef90ec54e75e7da713bd87f6424e8f051d66
[GpsPrune.git] / tim / prune / function / FullRangeDetails.java
1 package tim.prune.function;
2
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;
10
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;
16
17 import tim.prune.App;
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
26 /**
27  * Class to show the full range details in a separate popup
28  */
29 public class FullRangeDetails extends GenericFunction
30 {
31         /** Dialog */
32         private JDialog _dialog = null;
33         /** Label for number of segments */
34         private JLabel _numSegsLabel = null;
35         /** Label for pace */
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();
45
46         /**
47          * Constructor
48          * @param inApp App object
49          */
50         public FullRangeDetails(App inApp)
51         {
52                 super(inApp);
53                 FORMAT_ONE_DP.setMaximumFractionDigits(1);
54                 FORMAT_ONE_DP.setMinimumFractionDigits(1);
55         }
56
57         /** Get the name key */
58         public String getNameKey() {
59                 return "function.fullrangedetails";
60         }
61
62         /**
63          * Begin the function
64          */
65         public void begin()
66         {
67                 if (_dialog == null)
68                 {
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());
73                         _dialog.pack();
74                 }
75                 updateDetails();
76                 _dialog.setVisible(true);
77         }
78
79         /**
80          * Create dialog components
81          * @return Panel containing all gui elements in dialog
82          */
83         private Component makeDialogComponents()
84         {
85                 JPanel dialogPanel = new JPanel();
86                 dialogPanel.setLayout(new BorderLayout(5, 5));
87                 // Label at top
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);
91
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));
96                 // Number of segments
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);
102                 // Pace
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);
108                 // Gradient
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);
114                 // Moving distance
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);
120                 // Moving speed
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);
126
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)
134                         {
135                                 _dialog.dispose();
136                         }
137                 });
138                 buttonPanel.add(closeButton);
139                 dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
140                 return dialogPanel;
141         }
142
143
144         /**
145          * Update the labels with the current details
146          */
147         private void updateDetails()
148         {
149                 Selection selection = _app.getTrackInfo().getSelection();
150                 // Number of segments
151                 _numSegsLabel.setText("" + selection.getNumSegments());
152                 // Pace value
153                 if (selection.getNumSeconds() > 0)
154                 {
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);
161                 }
162                 else {
163                         _paceLabel.setText("");
164                 }
165                 // Gradient
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)
170                 {
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) + " %");
175                 }
176                 else {
177                         // no altitude given
178                         _gradientLabel.setText("");
179                 }
180
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");
186                 // Moving distance
187                 _movingDistanceLabel.setText(roundedNumber(selection.getMovingDistance(distUnits)) + " " + distUnitsStr);
188                 // Moving average speed
189                 long numSecs = selection.getMovingSeconds();
190                 if (numSecs > 0) {
191                         _aveMovingSpeedLabel.setText(roundedNumber(selection.getMovingDistance(distUnits)/numSecs*3600.0)
192                                 + " " + speedUnitsStr);
193                 }
194                 else {
195                         _aveMovingSpeedLabel.setText("");
196                 }
197         }
198
199         /**
200          * Format a number to a sensible precision
201          * @param inDist distance
202          * @return formatted String
203          */
204         private String roundedNumber(double inDist)
205         {
206                 // Set precision of formatter
207                 int numDigits = 0;
208                 if (inDist < 1.0)
209                         numDigits = 3;
210                 else if (inDist < 10.0)
211                         numDigits = 2;
212                 else if (inDist < 100.0)
213                         numDigits = 1;
214                 // set formatter
215                 _distanceFormatter.setMaximumFractionDigits(numDigits);
216                 _distanceFormatter.setMinimumFractionDigits(numDigits);
217                 return _distanceFormatter.format(inDist);
218         }
219 }