1 package tim.prune.function.edit;
3 import java.awt.BorderLayout;
5 import java.awt.Component;
6 import java.awt.Dimension;
7 import java.awt.FlowLayout;
8 import java.awt.GridLayout;
9 import java.awt.event.ActionEvent;
10 import java.awt.event.ActionListener;
12 import javax.swing.BorderFactory;
13 import javax.swing.BoxLayout;
14 import javax.swing.JButton;
15 import javax.swing.JDialog;
16 import javax.swing.JFrame;
17 import javax.swing.JLabel;
18 import javax.swing.JPanel;
19 import javax.swing.JScrollPane;
20 import javax.swing.JTable;
21 import javax.swing.JTextArea;
22 import javax.swing.JTextField;
23 import javax.swing.ListSelectionModel;
24 import javax.swing.SwingUtilities;
25 import javax.swing.event.ListSelectionEvent;
26 import javax.swing.event.ListSelectionListener;
27 import javax.swing.table.TableCellRenderer;
30 import tim.prune.I18nManager;
31 import tim.prune.config.Config;
32 import tim.prune.data.DataPoint;
33 import tim.prune.data.Field;
34 import tim.prune.data.FieldList;
35 import tim.prune.data.Track;
36 import tim.prune.data.Unit;
39 * Class to manage the display and editing of point data
41 public class PointEditor
43 private App _app = null;
44 private JFrame _parentFrame = null;
45 private JDialog _dialog = null;
46 private JTable _table = null;
47 private JLabel _fieldnameLabel = null;
48 private JTextField _valueField = null;
49 private JTextArea _valueArea = null;
50 private JScrollPane _valueAreaPane = null;
51 private Track _track = null;
52 private DataPoint _point = null;
53 private EditFieldsTableModel _model = null;
54 private int _prevRowIndex = -1;
59 * @param inApp application object to inform of success
60 * @param inParentFrame parent frame
62 public PointEditor(App inApp, JFrame inParentFrame)
65 _parentFrame = inParentFrame;
70 * Show the edit point dialog
71 * @param inTrack track object
72 * @param inPoint point to edit
74 public void showDialog(Track inTrack, DataPoint inPoint)
78 _dialog = new JDialog(_parentFrame, I18nManager.getText("dialog.pointedit.title"), true);
79 _dialog.setLocationRelativeTo(_parentFrame);
81 FieldList fieldList = _track.getFieldList();
82 int numFields = fieldList.getNumFields();
83 // Create table model for point editor
84 _model = new EditFieldsTableModel(numFields);
85 for (int i=0; i<numFields; i++)
87 Field field = fieldList.getField(i);
88 _model.addFieldInfo(field.getName(), _point.getFieldValue(field), i);
91 _dialog.getContentPane().add(makeDialogComponents());
93 // Init right-hand side
94 SwingUtilities.invokeLater(new Runnable() {
96 _valueField.setVisible(false);
97 _valueAreaPane.setVisible(false);
100 _dialog.setVisible(true);
105 * Make the dialog components
106 * @return the GUI components for the dialog
108 private Component makeDialogComponents()
110 JPanel panel = new JPanel();
111 panel.setLayout(new BorderLayout(20, 10));
112 // Create GUI layout for point editor
113 _table = new JTable(_model)
115 // Paint the changed fields orange
116 public Component prepareRenderer(TableCellRenderer renderer, int row, int column)
118 Component comp = super.prepareRenderer(renderer, row, column);
119 boolean changed = ((EditFieldsTableModel) getModel()).getChanged(row);
120 comp.setBackground(changed ? Color.orange : getBackground());
124 _table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
125 _table.getSelectionModel().clearSelection();
126 _table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
127 public void valueChanged(ListSelectionEvent e)
132 _table.setPreferredScrollableViewportSize(new Dimension(_table.getWidth() * 2, _table.getRowHeight() * 6));
133 JScrollPane tablePane = new JScrollPane(_table);
134 tablePane.setPreferredSize(new Dimension(150, 100));
137 JLabel topLabel = new JLabel(I18nManager.getText("dialog.pointedit.intro"));
138 topLabel.setBorder(BorderFactory.createEmptyBorder(8, 6, 3, 6));
139 panel.add(topLabel, BorderLayout.NORTH);
141 // listener for ok event
142 ActionListener okListener = new ActionListener() {
143 public void actionPerformed(ActionEvent e)
145 // update App with edit
151 JPanel rightPanel = new JPanel();
152 rightPanel.setLayout(new BorderLayout());
153 JPanel rightiPanel = new JPanel();
154 rightiPanel.setLayout(new BoxLayout(rightiPanel, BoxLayout.Y_AXIS));
155 // Add GUI elements to rhs
156 _fieldnameLabel = new JLabel(I18nManager.getText("dialog.pointedit.nofield"));
157 rightiPanel.add(_fieldnameLabel);
158 _valueField = new JTextField(11);
159 // Add listener for enter button
160 _valueField.addActionListener(okListener);
161 rightiPanel.add(_valueField);
162 rightPanel.add(rightiPanel, BorderLayout.NORTH);
163 _valueArea = new JTextArea(5, 15);
164 _valueArea.setLineWrap(true);
165 _valueArea.setWrapStyleWord(true);
166 _valueAreaPane = new JScrollPane(_valueArea);
167 rightPanel.add(_valueAreaPane, BorderLayout.CENTER);
169 // Put the table and the right-hand panel together in a grid
170 JPanel mainPanel = new JPanel();
171 mainPanel.setLayout(new GridLayout(0, 2, 10, 10));
172 mainPanel.add(tablePane);
173 mainPanel.add(rightPanel);
174 panel.add(mainPanel, BorderLayout.CENTER);
176 // Bottom panel for OK, cancel buttons
177 JPanel lowerPanel = new JPanel();
178 lowerPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
179 JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
180 cancelButton.addActionListener(new ActionListener() {
181 public void actionPerformed(ActionEvent e)
186 lowerPanel.add(cancelButton);
187 JButton okButton = new JButton(I18nManager.getText("button.ok"));
188 okButton.addActionListener(okListener);
189 lowerPanel.add(okButton);
190 panel.add(lowerPanel, BorderLayout.SOUTH);
196 * When table selection changes, need to update model and go to the selected field
198 private void fieldSelected()
200 int rowNum = _table.getSelectedRow();
201 if (rowNum == _prevRowIndex) {return;} // selection hasn't changed
202 // Check the current values
203 if (_prevRowIndex >= 0)
205 Field prevField = _track.getFieldList().getField(_prevRowIndex);
206 boolean littleField = prevField.isBuiltIn() && prevField != Field.DESCRIPTION;
207 String newValue = littleField ? _valueField.getText() : _valueArea.getText();
208 // Update the model from the current GUI values
209 _model.updateValue(_prevRowIndex, newValue);
214 _fieldnameLabel.setText("");
218 String currValue = _model.getValue(rowNum);
219 Field field = _track.getFieldList().getField(rowNum);
220 _fieldnameLabel.setText(makeFieldLabel(field, _point));
221 _fieldnameLabel.setVisible(true);
222 boolean littleField = field.isBuiltIn() && field != Field.DESCRIPTION;
224 _valueField.setText(currValue);
227 _valueArea.setText(currValue);
229 _valueField.setVisible(littleField);
230 _valueAreaPane.setVisible(!littleField);
232 _valueField.requestFocus();
235 _valueArea.requestFocus();
238 _prevRowIndex = rowNum;
242 * @param inField field
243 * @param inPoint current point
244 * @return label string for above the entry field / area
246 private static String makeFieldLabel(Field inField, DataPoint inPoint)
248 String label = I18nManager.getText("dialog.pointedit.table.field") + ": " + inField.getName();
249 // Add units if the field is altitude / speed / vspeed
250 if (inField == Field.ALTITUDE)
252 label += makeUnitsLabel(inPoint.hasAltitude() ? inPoint.getAltitude().getUnit() : Config.getUnitSet().getAltitudeUnit());
254 else if (inField == Field.SPEED)
256 label += makeUnitsLabel(inPoint.hasHSpeed() ? inPoint.getHSpeed().getUnit() : Config.getUnitSet().getSpeedUnit());
258 else if (inField == Field.VERTICAL_SPEED)
260 label += makeUnitsLabel(inPoint.hasVSpeed() ? inPoint.getVSpeed().getUnit() : Config.getUnitSet().getVerticalSpeedUnit());
266 * @param inUnit units for altitude / speed
267 * @return addition to the field label to describe the units
269 private static String makeUnitsLabel(Unit inUnit)
271 if (inUnit == null) return "";
272 return " (" + I18nManager.getText(inUnit.getShortnameKey()) + ")";
276 * Confirm the edit and inform the app
278 private void confirmEdit()
280 // Apply the edits to the current field
281 int rowNum = _table.getSelectedRow();
284 Field currField = _track.getFieldList().getField(rowNum);
285 boolean littleField = currField.isBuiltIn() && currField != Field.DESCRIPTION;
286 String newValue = littleField ? _valueField.getText() : _valueArea.getText();
287 _model.updateValue(_prevRowIndex, newValue);
290 // Package the modified fields into an object
291 FieldList fieldList = _track.getFieldList();
292 int numFields = fieldList.getNumFields();
293 // Make lists for edit and undo, and add each changed field in turn
294 FieldEditList editList = new FieldEditList();
295 FieldEditList undoList = new FieldEditList();
296 for (int i=0; i<numFields; i++)
298 if (_model.getChanged(i))
300 Field field = fieldList.getField(i);
301 editList.addEdit(new FieldEdit(field, _model.getValue(i)));
302 undoList.addEdit(new FieldEdit(field, _point.getFieldValue(field)));
305 _app.completePointEdit(editList, undoList);