X-Git-Url: http://gitweb.fperrin.net/?p=GpsPrune.git;a=blobdiff_plain;f=tim%2Fprune%2Ffunction%2FDistanceTimeLimitFunction.java;fp=tim%2Fprune%2Ffunction%2FDistanceTimeLimitFunction.java;h=eaa7b7d8a16ccd8fa42079a3421f6a4c8919ec96;hp=0000000000000000000000000000000000000000;hb=92dad5df664287acb51728e9ea599f150765d34a;hpb=81843c3d8d0771bf00d0f26034a13aa515465c78 diff --git a/tim/prune/function/DistanceTimeLimitFunction.java b/tim/prune/function/DistanceTimeLimitFunction.java new file mode 100644 index 0000000..eaa7b7d --- /dev/null +++ b/tim/prune/function/DistanceTimeLimitFunction.java @@ -0,0 +1,275 @@ +package tim.prune.function; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; + +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.ButtonGroup; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JRadioButton; + +import tim.prune.App; +import tim.prune.GenericFunction; +import tim.prune.I18nManager; +import tim.prune.data.Distance; +import tim.prune.data.Field; +import tim.prune.data.TimeDifference; +import tim.prune.data.Unit; +import tim.prune.data.UnitSetLibrary; +import tim.prune.gui.WholeNumberField; + +/** + * Superclass for functions which act on a defined + * distance limit or time limit + */ +public abstract class DistanceTimeLimitFunction extends GenericFunction +{ + /** Dialog */ + protected JDialog _dialog = null; + /** Radio buttons for splitting by distance and time */ + private JRadioButton _distLimitRadio = null, _timeLimitRadio = null; + /** Dropdown for selecting distance units */ + private JComboBox _distUnitsDropdown = null; + /** Text field for entering distance */ + private WholeNumberField _distanceField = null; + /** Text fields for entering distance */ + private WholeNumberField _limitHourField = null, _limitMinField = null; + /** Ok and cancel buttons */ + private JButton _okButton = null; + private JButton _cancelButton = null; + + + /** + * React to item changes and key presses + */ + private abstract class ChangeListener extends KeyAdapter implements ItemListener + { + /** Method to be implemented */ + public abstract void optionsChanged(); + + /** Item changed in ItemListener */ + public void itemStateChanged(ItemEvent arg0) { + optionsChanged(); + } + + /** Key released in KeyListener */ + public void keyReleased(KeyEvent arg0) { + optionsChanged(); + } + } + + /** + * Constructor + */ + public DistanceTimeLimitFunction(App inApp) { + super(inApp); + } + + /** + * 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(); + } + enableOkButton(); + // TODO: Maybe set distance units according to current Config setting? + final boolean hasTimestamps = _app.getTrackInfo().getTrack().hasData(Field.TIMESTAMP); + _timeLimitRadio.setEnabled(hasTimestamps); + if (!hasTimestamps) + { + _distLimitRadio.setSelected(true); + } + // set focus to Cancel button so that pressing "Esc" works + _cancelButton.requestFocus(); + _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)); + + // Make radio buttons for three different options + _distLimitRadio = new JRadioButton(I18nManager.getText("dialog.correlate.options.distancelimit") + ": "); + _timeLimitRadio = new JRadioButton(I18nManager.getText("dialog.correlate.options.timelimit") + ": "); + ButtonGroup radioGroup = new ButtonGroup(); + radioGroup.add(_distLimitRadio); + radioGroup.add(_timeLimitRadio); + + // central panel for limits + JPanel limitsPanel = new JPanel(); + limitsPanel.setLayout(new BoxLayout(limitsPanel, BoxLayout.Y_AXIS)); + limitsPanel.add(Box.createVerticalStrut(8)); + ChangeListener optionsChangedListener = new ChangeListener() { + public void optionsChanged() { + enableOkButton(); + } + }; + // distance limits + JPanel distLimitPanel = new JPanel(); + distLimitPanel.setLayout(new FlowLayout()); + _distLimitRadio.setSelected(true); + _distLimitRadio.addItemListener(optionsChangedListener); + distLimitPanel.add(_distLimitRadio); + _distanceField = new WholeNumberField(3); + _distanceField.addKeyListener(optionsChangedListener); + distLimitPanel.add(_distanceField); + String[] distUnitsOptions = {I18nManager.getText("units.kilometres"), I18nManager.getText("units.metres"), + I18nManager.getText("units.miles")}; + _distUnitsDropdown = new JComboBox(distUnitsOptions); + _distUnitsDropdown.addItemListener(optionsChangedListener); + distLimitPanel.add(_distUnitsDropdown); + distLimitPanel.setAlignmentX(Component.LEFT_ALIGNMENT); + limitsPanel.add(distLimitPanel); + + // time limit panel + JPanel timeLimitPanel = new JPanel(); + timeLimitPanel.setLayout(new FlowLayout()); + _timeLimitRadio.addItemListener(optionsChangedListener); + timeLimitPanel.add(_timeLimitRadio); + _limitHourField = new WholeNumberField(2); + _limitHourField.addKeyListener(optionsChangedListener); + timeLimitPanel.add(_limitHourField); + timeLimitPanel.add(new JLabel(I18nManager.getText("dialog.correlate.options.offset.hours"))); + _limitMinField = new WholeNumberField(3); + _limitMinField.addKeyListener(optionsChangedListener); + timeLimitPanel.add(_limitMinField); + timeLimitPanel.add(new JLabel(I18nManager.getText("units.minutes"))); + timeLimitPanel.setAlignmentX(Component.LEFT_ALIGNMENT); + limitsPanel.add(timeLimitPanel); + + dialogPanel.add(limitsPanel, BorderLayout.NORTH); + + // button panel at bottom + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT)); + // OK button + _okButton = new JButton(I18nManager.getText("button.ok")); + _okButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + performFunction(); + } + }); + buttonPanel.add(_okButton); + // Cancel button + _cancelButton = new JButton(I18nManager.getText("button.cancel")); + _cancelButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + _dialog.dispose(); + } + }); + _cancelButton.addKeyListener(new KeyAdapter() { + public void keyPressed(KeyEvent inE) { + if (inE.getKeyCode() == KeyEvent.VK_ESCAPE) {_dialog.dispose();} + } + }); + buttonPanel.add(_cancelButton); + dialogPanel.add(buttonPanel, BorderLayout.SOUTH); + return dialogPanel; + } + + /** + * Enable or disable the OK button according to the inputs + */ + private void enableOkButton() + { + boolean enabled = false; + if (_distLimitRadio.isSelected()) { + enabled = _distanceField.getValue() > 0; + } + else if (_timeLimitRadio.isSelected()) { + enabled = _limitHourField.getValue() > 0 || _limitMinField.getValue() > 0; + } + _okButton.setEnabled(enabled); + + // Also enable/disable the other fields + _distanceField.setEnabled(_distLimitRadio.isSelected()); + _distUnitsDropdown.setEnabled(_distLimitRadio.isSelected()); + _limitHourField.setEnabled(_timeLimitRadio.isSelected()); + _limitMinField.setEnabled(_timeLimitRadio.isSelected()); + } + + /** + * @return selected time limit in seconds, or 0 + */ + protected int getTimeLimitInSeconds() + { + if (_timeLimitRadio.isSelected() + && (_limitHourField.getValue() > 0 || _limitMinField.getValue() > 0)) + { + int timeLimitSeconds = _limitHourField.getValue() * 60 * 60 + + _limitMinField.getValue() * 60; + if (timeLimitSeconds > 0) + return timeLimitSeconds; + } + return 0; + } + + /** + * @return selected distance limit in radians, or 0.0 + */ + protected double getDistanceLimitRadians() + { + if (_distLimitRadio.isSelected() + && _distanceField.getValue() > 0) + { + final Unit[] distUnits = {UnitSetLibrary.UNITS_KILOMETRES, + UnitSetLibrary.UNITS_METRES, UnitSetLibrary.UNITS_MILES}; + Unit distUnit = distUnits[_distUnitsDropdown.getSelectedIndex()]; + double distLimitRadians = Distance.convertDistanceToRadians(_distanceField.getValue(), distUnit); + return distLimitRadians; + } + return 0.0; + } + + /** + * The dialog has been completed and OK pressed, so do the corresponding function + */ + protected abstract void performFunction(); + + /** + * Create a description for the given multiple of the configured limit + * @param inMultiple multiple of selected limit + * @return language-specific String description for waypoint names + */ + protected String createLimitDescription(int inMultiple) + { + if (_distLimitRadio.isSelected() + && _distanceField.getValue() > 0) + { + final int distLimit = inMultiple * _distanceField.getValue(); + final String[] distUnits = {"kilometres", "metres", "miles"}; + final String unitKey = "units." + distUnits[_distUnitsDropdown.getSelectedIndex()] + ".short"; + return "" + distLimit + " " + I18nManager.getText(unitKey); + } + else if (_timeLimitRadio.isSelected()) + { + final long timeLimitSecs = (long) getTimeLimitInSeconds() * inMultiple; + return new TimeDifference(timeLimitSecs).getDescription(); + } + return null; + } +}