]> gitweb.fperrin.net Git - GpsPrune.git/blob - src/tim/prune/function/DistanceTimeLimitFunction.java
eaa7b7d8a16ccd8fa42079a3421f6a4c8919ec96
[GpsPrune.git] / src / tim / prune / function / DistanceTimeLimitFunction.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.event.ActionEvent;
7 import java.awt.event.ActionListener;
8 import java.awt.event.ItemEvent;
9 import java.awt.event.ItemListener;
10 import java.awt.event.KeyAdapter;
11 import java.awt.event.KeyEvent;
12
13 import javax.swing.Box;
14 import javax.swing.BoxLayout;
15 import javax.swing.ButtonGroup;
16 import javax.swing.JButton;
17 import javax.swing.JComboBox;
18 import javax.swing.JDialog;
19 import javax.swing.JLabel;
20 import javax.swing.JPanel;
21 import javax.swing.JRadioButton;
22
23 import tim.prune.App;
24 import tim.prune.GenericFunction;
25 import tim.prune.I18nManager;
26 import tim.prune.data.Distance;
27 import tim.prune.data.Field;
28 import tim.prune.data.TimeDifference;
29 import tim.prune.data.Unit;
30 import tim.prune.data.UnitSetLibrary;
31 import tim.prune.gui.WholeNumberField;
32
33 /**
34  * Superclass for functions which act on a defined
35  * distance limit or time limit
36  */
37 public abstract class DistanceTimeLimitFunction extends GenericFunction
38 {
39         /** Dialog */
40         protected JDialog _dialog = null;
41         /** Radio buttons for splitting by distance and time */
42         private JRadioButton _distLimitRadio = null, _timeLimitRadio = null;
43         /** Dropdown for selecting distance units */
44         private JComboBox<String> _distUnitsDropdown = null;
45         /** Text field for entering distance */
46         private WholeNumberField _distanceField = null;
47         /** Text fields for entering distance */
48         private WholeNumberField _limitHourField = null, _limitMinField = null;
49         /** Ok and cancel buttons */
50         private JButton _okButton = null;
51         private JButton _cancelButton = null;
52
53
54         /**
55          * React to item changes and key presses
56          */
57         private abstract class ChangeListener extends KeyAdapter implements ItemListener
58         {
59                 /** Method to be implemented */
60                 public abstract void optionsChanged();
61
62                 /** Item changed in ItemListener */
63                 public void itemStateChanged(ItemEvent arg0) {
64                         optionsChanged();
65                 }
66
67                 /** Key released in KeyListener */
68                 public void keyReleased(KeyEvent arg0) {
69                         optionsChanged();
70                 }
71         }
72
73         /**
74          * Constructor
75          */
76         public DistanceTimeLimitFunction(App inApp) {
77                 super(inApp);
78         }
79
80         /**
81          * Begin the function
82          */
83         public void begin()
84         {
85                 if (_dialog == null)
86                 {
87                         _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
88                         _dialog.setLocationRelativeTo(_parentFrame);
89                         _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
90                         _dialog.getContentPane().add(makeDialogComponents());
91                         _dialog.pack();
92                 }
93                 enableOkButton();
94                 // TODO: Maybe set distance units according to current Config setting?
95                 final boolean hasTimestamps = _app.getTrackInfo().getTrack().hasData(Field.TIMESTAMP);
96                 _timeLimitRadio.setEnabled(hasTimestamps);
97                 if (!hasTimestamps)
98                 {
99                         _distLimitRadio.setSelected(true);
100                 }
101                 // set focus to Cancel button so that pressing "Esc" works
102                 _cancelButton.requestFocus();
103                 _dialog.setVisible(true);
104         }
105
106         /**
107          * Create dialog components
108          * @return Panel containing all gui elements in dialog
109          */
110         private Component makeDialogComponents()
111         {
112                 JPanel dialogPanel = new JPanel();
113                 dialogPanel.setLayout(new BorderLayout(5, 5));
114
115                 // Make radio buttons for three different options
116                 _distLimitRadio = new JRadioButton(I18nManager.getText("dialog.correlate.options.distancelimit") + ": ");
117                 _timeLimitRadio = new JRadioButton(I18nManager.getText("dialog.correlate.options.timelimit") + ": ");
118                 ButtonGroup radioGroup = new ButtonGroup();
119                 radioGroup.add(_distLimitRadio);
120                 radioGroup.add(_timeLimitRadio);
121
122                 // central panel for limits
123                 JPanel limitsPanel = new JPanel();
124                 limitsPanel.setLayout(new BoxLayout(limitsPanel, BoxLayout.Y_AXIS));
125                 limitsPanel.add(Box.createVerticalStrut(8));
126                 ChangeListener optionsChangedListener = new ChangeListener() {
127                         public void optionsChanged() {
128                                 enableOkButton();
129                         }
130                 };
131                 // distance limits
132                 JPanel distLimitPanel = new JPanel();
133                 distLimitPanel.setLayout(new FlowLayout());
134                 _distLimitRadio.setSelected(true);
135                 _distLimitRadio.addItemListener(optionsChangedListener);
136                 distLimitPanel.add(_distLimitRadio);
137                 _distanceField = new WholeNumberField(3);
138                 _distanceField.addKeyListener(optionsChangedListener);
139                 distLimitPanel.add(_distanceField);
140                 String[] distUnitsOptions = {I18nManager.getText("units.kilometres"), I18nManager.getText("units.metres"),
141                         I18nManager.getText("units.miles")};
142                 _distUnitsDropdown = new JComboBox<String>(distUnitsOptions);
143                 _distUnitsDropdown.addItemListener(optionsChangedListener);
144                 distLimitPanel.add(_distUnitsDropdown);
145                 distLimitPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
146                 limitsPanel.add(distLimitPanel);
147
148                 // time limit panel
149                 JPanel timeLimitPanel = new JPanel();
150                 timeLimitPanel.setLayout(new FlowLayout());
151                 _timeLimitRadio.addItemListener(optionsChangedListener);
152                 timeLimitPanel.add(_timeLimitRadio);
153                 _limitHourField = new WholeNumberField(2);
154                 _limitHourField.addKeyListener(optionsChangedListener);
155                 timeLimitPanel.add(_limitHourField);
156                 timeLimitPanel.add(new JLabel(I18nManager.getText("dialog.correlate.options.offset.hours")));
157                 _limitMinField = new WholeNumberField(3);
158                 _limitMinField.addKeyListener(optionsChangedListener);
159                 timeLimitPanel.add(_limitMinField);
160                 timeLimitPanel.add(new JLabel(I18nManager.getText("units.minutes")));
161                 timeLimitPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
162                 limitsPanel.add(timeLimitPanel);
163
164                 dialogPanel.add(limitsPanel, BorderLayout.NORTH);
165
166                 // button panel at bottom
167                 JPanel buttonPanel = new JPanel();
168                 buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
169                 // OK button
170                 _okButton = new JButton(I18nManager.getText("button.ok"));
171                 _okButton.addActionListener(new ActionListener() {
172                         public void actionPerformed(ActionEvent e) {
173                                 performFunction();
174                         }
175                 });
176                 buttonPanel.add(_okButton);
177                 // Cancel button
178                 _cancelButton = new JButton(I18nManager.getText("button.cancel"));
179                 _cancelButton.addActionListener(new ActionListener() {
180                         public void actionPerformed(ActionEvent e) {
181                                 _dialog.dispose();
182                         }
183                 });
184                 _cancelButton.addKeyListener(new KeyAdapter() {
185                         public void keyPressed(KeyEvent inE) {
186                                 if (inE.getKeyCode() == KeyEvent.VK_ESCAPE) {_dialog.dispose();}
187                         }
188                 });
189                 buttonPanel.add(_cancelButton);
190                 dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
191                 return dialogPanel;
192         }
193
194         /**
195          * Enable or disable the OK button according to the inputs
196          */
197         private void enableOkButton()
198         {
199                 boolean enabled = false;
200                 if (_distLimitRadio.isSelected()) {
201                         enabled = _distanceField.getValue() > 0;
202                 }
203                 else if (_timeLimitRadio.isSelected()) {
204                         enabled = _limitHourField.getValue() > 0 || _limitMinField.getValue() > 0;
205                 }
206                 _okButton.setEnabled(enabled);
207
208                 // Also enable/disable the other fields
209                 _distanceField.setEnabled(_distLimitRadio.isSelected());
210                 _distUnitsDropdown.setEnabled(_distLimitRadio.isSelected());
211                 _limitHourField.setEnabled(_timeLimitRadio.isSelected());
212                 _limitMinField.setEnabled(_timeLimitRadio.isSelected());
213         }
214
215         /**
216          * @return selected time limit in seconds, or 0
217          */
218         protected int getTimeLimitInSeconds()
219         {
220                 if (_timeLimitRadio.isSelected()
221                         && (_limitHourField.getValue() > 0 || _limitMinField.getValue() > 0))
222                 {
223                         int timeLimitSeconds = _limitHourField.getValue() * 60 * 60
224                                 + _limitMinField.getValue() * 60;
225                         if (timeLimitSeconds > 0)
226                                 return timeLimitSeconds;
227                 }
228                 return 0;
229         }
230
231         /**
232          * @return selected distance limit in radians, or 0.0
233          */
234         protected double getDistanceLimitRadians()
235         {
236                 if (_distLimitRadio.isSelected()
237                         && _distanceField.getValue() > 0)
238                 {
239                         final Unit[] distUnits = {UnitSetLibrary.UNITS_KILOMETRES,
240                                 UnitSetLibrary.UNITS_METRES, UnitSetLibrary.UNITS_MILES};
241                         Unit distUnit = distUnits[_distUnitsDropdown.getSelectedIndex()];
242                         double distLimitRadians = Distance.convertDistanceToRadians(_distanceField.getValue(), distUnit);
243                         return distLimitRadians;
244                 }
245                 return 0.0;
246         }
247
248         /**
249          * The dialog has been completed and OK pressed, so do the corresponding function
250          */
251         protected abstract void performFunction();
252
253         /**
254          * Create a description for the given multiple of the configured limit
255          * @param inMultiple multiple of selected limit
256          * @return language-specific String description for waypoint names
257          */
258         protected String createLimitDescription(int inMultiple)
259         {
260                 if (_distLimitRadio.isSelected()
261                         && _distanceField.getValue() > 0)
262                 {
263                         final int distLimit = inMultiple * _distanceField.getValue();
264                         final String[] distUnits = {"kilometres", "metres", "miles"};
265                         final String unitKey = "units." + distUnits[_distUnitsDropdown.getSelectedIndex()] + ".short";
266                         return "" + distLimit + " " + I18nManager.getText(unitKey);
267                 }
268                 else if (_timeLimitRadio.isSelected())
269                 {
270                         final long timeLimitSecs = (long) getTimeLimitInSeconds() * inMultiple;
271                         return new TimeDifference(timeLimitSecs).getDescription();
272                 }
273                 return null;
274         }
275 }