package tim.prune.function.edit; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.TableCellRenderer; import tim.prune.App; import tim.prune.I18nManager; import tim.prune.config.Config; import tim.prune.data.DataPoint; import tim.prune.data.Field; import tim.prune.data.FieldList; import tim.prune.data.Track; import tim.prune.data.Unit; /** * Class to manage the display and editing of point data */ public class PointEditor { private App _app = null; private JFrame _parentFrame = null; private JDialog _dialog = null; private JTable _table = null; private JLabel _fieldnameLabel = null; private JTextField _valueField = null; private JTextArea _valueArea = null; private JScrollPane _valueAreaPane = null; private Track _track = null; private DataPoint _point = null; private EditFieldsTableModel _model = null; private int _prevRowIndex = -1; /** * Constructor * @param inApp application object to inform of success * @param inParentFrame parent frame */ public PointEditor(App inApp, JFrame inParentFrame) { _app = inApp; _parentFrame = inParentFrame; } /** * Show the edit point dialog * @param inTrack track object * @param inPoint point to edit */ public void showDialog(Track inTrack, DataPoint inPoint) { _track = inTrack; _point = inPoint; _dialog = new JDialog(_parentFrame, I18nManager.getText("dialog.pointedit.title"), true); _dialog.setLocationRelativeTo(_parentFrame); // Check field list FieldList fieldList = _track.getFieldList(); int numFields = fieldList.getNumFields(); // Create table model for point editor _model = new EditFieldsTableModel(numFields); for (int i=0; i<numFields; i++) { Field field = fieldList.getField(i); _model.addFieldInfo(field.getName(), _point.getFieldValue(field), i); } // Create Gui _dialog.getContentPane().add(makeDialogComponents()); _dialog.pack(); // Init right-hand side SwingUtilities.invokeLater(new Runnable() { public void run() { _valueField.setVisible(false); _valueAreaPane.setVisible(false); } }); _dialog.setVisible(true); } /** * Make the dialog components * @return the GUI components for the dialog */ private Component makeDialogComponents() { JPanel panel = new JPanel(); panel.setLayout(new BorderLayout(20, 10)); // Create GUI layout for point editor _table = new JTable(_model) { // Paint the changed fields orange public Component prepareRenderer(TableCellRenderer renderer, int row, int column) { Component comp = super.prepareRenderer(renderer, row, column); boolean changed = ((EditFieldsTableModel) getModel()).getChanged(row); comp.setBackground(changed ? Color.orange : getBackground()); return comp; } }; _table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); _table.getSelectionModel().clearSelection(); _table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { fieldSelected(); } }); _table.setPreferredScrollableViewportSize(new Dimension(_table.getWidth() * 2, _table.getRowHeight() * 6)); JScrollPane tablePane = new JScrollPane(_table); tablePane.setPreferredSize(new Dimension(150, 100)); // Label at top JLabel topLabel = new JLabel(I18nManager.getText("dialog.pointedit.intro")); topLabel.setBorder(BorderFactory.createEmptyBorder(8, 6, 3, 6)); panel.add(topLabel, BorderLayout.NORTH); // listener for ok event ActionListener okListener = new ActionListener() { public void actionPerformed(ActionEvent e) { // update App with edit confirmEdit(); _dialog.dispose(); } }; JPanel rightPanel = new JPanel(); rightPanel.setLayout(new BorderLayout()); JPanel rightiPanel = new JPanel(); rightiPanel.setLayout(new BoxLayout(rightiPanel, BoxLayout.Y_AXIS)); // Add GUI elements to rhs _fieldnameLabel = new JLabel(I18nManager.getText("dialog.pointedit.nofield")); rightiPanel.add(_fieldnameLabel); _valueField = new JTextField(11); // Add listener for enter button _valueField.addActionListener(okListener); rightiPanel.add(_valueField); rightPanel.add(rightiPanel, BorderLayout.NORTH); _valueArea = new JTextArea(5, 15); _valueArea.setLineWrap(true); _valueArea.setWrapStyleWord(true); _valueAreaPane = new JScrollPane(_valueArea); rightPanel.add(_valueAreaPane, BorderLayout.CENTER); // Put the table and the right-hand panel together in a grid JPanel mainPanel = new JPanel(); mainPanel.setLayout(new GridLayout(0, 2, 10, 10)); mainPanel.add(tablePane); mainPanel.add(rightPanel); panel.add(mainPanel, BorderLayout.CENTER); // Bottom panel for OK, cancel buttons JPanel lowerPanel = new JPanel(); lowerPanel.setLayout(new FlowLayout(FlowLayout.RIGHT)); JButton cancelButton = new JButton(I18nManager.getText("button.cancel")); cancelButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { _dialog.dispose(); } }); lowerPanel.add(cancelButton); JButton okButton = new JButton(I18nManager.getText("button.ok")); okButton.addActionListener(okListener); lowerPanel.add(okButton); panel.add(lowerPanel, BorderLayout.SOUTH); return panel; } /** * When table selection changes, need to update model and go to the selected field */ private void fieldSelected() { int rowNum = _table.getSelectedRow(); if (rowNum == _prevRowIndex) {return;} // selection hasn't changed // Check the current values if (_prevRowIndex >= 0) { Field prevField = _track.getFieldList().getField(_prevRowIndex); boolean littleField = prevField.isBuiltIn() && prevField != Field.DESCRIPTION; String newValue = littleField ? _valueField.getText() : _valueArea.getText(); // Update the model from the current GUI values _model.updateValue(_prevRowIndex, newValue); } if (rowNum < 0) { _fieldnameLabel.setText(""); } else { String currValue = _model.getValue(rowNum); Field field = _track.getFieldList().getField(rowNum); _fieldnameLabel.setText(makeFieldLabel(field, _point)); _fieldnameLabel.setVisible(true); boolean littleField = field.isBuiltIn() && field != Field.DESCRIPTION; if (littleField) { _valueField.setText(currValue); } else { _valueArea.setText(currValue); } _valueField.setVisible(littleField); _valueAreaPane.setVisible(!littleField); if (littleField) { _valueField.requestFocus(); } else { _valueArea.requestFocus(); } } _prevRowIndex = rowNum; } /** * @param inField field * @param inPoint current point * @return label string for above the entry field / area */ private static String makeFieldLabel(Field inField, DataPoint inPoint) { String label = I18nManager.getText("dialog.pointedit.table.field") + ": " + inField.getName(); // Add units if the field is altitude / speed / vspeed if (inField == Field.ALTITUDE) { label += makeUnitsLabel(inPoint.hasAltitude() ? inPoint.getAltitude().getUnit() : Config.getUnitSet().getAltitudeUnit()); } else if (inField == Field.SPEED) { label += makeUnitsLabel(inPoint.hasHSpeed() ? inPoint.getHSpeed().getUnit() : Config.getUnitSet().getSpeedUnit()); } else if (inField == Field.VERTICAL_SPEED) { label += makeUnitsLabel(inPoint.hasVSpeed() ? inPoint.getVSpeed().getUnit() : Config.getUnitSet().getVerticalSpeedUnit()); } return label; } /** * @param inUnit units for altitude / speed * @return addition to the field label to describe the units */ private static String makeUnitsLabel(Unit inUnit) { if (inUnit == null) return ""; return " (" + I18nManager.getText(inUnit.getShortnameKey()) + ")"; } /** * Confirm the edit and inform the app */ private void confirmEdit() { // Apply the edits to the current field int rowNum = _table.getSelectedRow(); if (rowNum >= 0) { Field currField = _track.getFieldList().getField(rowNum); boolean littleField = currField.isBuiltIn() && currField != Field.DESCRIPTION; String newValue = littleField ? _valueField.getText() : _valueArea.getText(); _model.updateValue(_prevRowIndex, newValue); } // Package the modified fields into an object FieldList fieldList = _track.getFieldList(); int numFields = fieldList.getNumFields(); // Make lists for edit and undo, and add each changed field in turn FieldEditList editList = new FieldEditList(); FieldEditList undoList = new FieldEditList(); for (int i=0; i<numFields; i++) { if (_model.getChanged(i)) { Field field = fieldList.getField(i); editList.addEdit(new FieldEdit(field, _model.getValue(i))); undoList.addEdit(new FieldEdit(field, _point.getFieldValue(field))); } } _app.completePointEdit(editList, undoList); } }