]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/function/edit/PointEditor.java
Version 19.1, August 2018
[GpsPrune.git] / tim / prune / function / edit / PointEditor.java
1 package tim.prune.function.edit;
2
3 import java.awt.BorderLayout;
4 import java.awt.Color;
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;
11 import java.awt.event.KeyAdapter;
12 import java.awt.event.KeyEvent;
13
14 import javax.swing.BorderFactory;
15 import javax.swing.BoxLayout;
16 import javax.swing.JButton;
17 import javax.swing.JDialog;
18 import javax.swing.JFrame;
19 import javax.swing.JLabel;
20 import javax.swing.JPanel;
21 import javax.swing.JScrollPane;
22 import javax.swing.JTable;
23 import javax.swing.JTextArea;
24 import javax.swing.JTextField;
25 import javax.swing.ListSelectionModel;
26 import javax.swing.SwingUtilities;
27 import javax.swing.event.ListSelectionEvent;
28 import javax.swing.event.ListSelectionListener;
29 import javax.swing.table.TableCellRenderer;
30
31 import tim.prune.App;
32 import tim.prune.I18nManager;
33 import tim.prune.config.Config;
34 import tim.prune.data.DataPoint;
35 import tim.prune.data.Field;
36 import tim.prune.data.FieldList;
37 import tim.prune.data.Track;
38 import tim.prune.data.Unit;
39
40 /**
41  * Class to manage the display and editing of point data
42  */
43 public class PointEditor
44 {
45         private App _app = null;
46         private JFrame _parentFrame = null;
47         private JDialog _dialog = null;
48         private JTable _table = null;
49         private JLabel _fieldnameLabel = null;
50         private JTextField _valueField = null;
51         private JTextArea _valueArea = null;
52         private JScrollPane _valueAreaPane = null;
53         private Track _track = null;
54         private DataPoint _point = null;
55         private EditFieldsTableModel _model = null;
56         private JButton _cancelButton = null;
57         private int _prevRowIndex = -1;
58
59
60         /**
61          * Constructor
62          * @param inApp application object to inform of success
63          * @param inParentFrame parent frame
64          */
65         public PointEditor(App inApp, JFrame inParentFrame)
66         {
67                 _app = inApp;
68                 _parentFrame = inParentFrame;
69         }
70
71
72         /**
73          * Show the edit point dialog
74          * @param inTrack track object
75          * @param inPoint point to edit
76          */
77         public void showDialog(Track inTrack, DataPoint inPoint)
78         {
79                 _track = inTrack;
80                 _point = inPoint;
81                 _dialog = new JDialog(_parentFrame, I18nManager.getText("dialog.pointedit.title"), true);
82                 _dialog.setLocationRelativeTo(_parentFrame);
83                 // Check field list
84                 FieldList fieldList = _track.getFieldList();
85                 int numFields = fieldList.getNumFields();
86                 // Create table model for point editor
87                 _model = new EditFieldsTableModel(numFields);
88                 for (int i=0; i<numFields; i++)
89                 {
90                         Field field = fieldList.getField(i);
91                         _model.addFieldInfo(field.getName(), _point.getFieldValue(field), i);
92                 }
93                 // Create Gui
94                 _dialog.getContentPane().add(makeDialogComponents());
95                 _dialog.pack();
96                 // Init right-hand side
97                 SwingUtilities.invokeLater(new Runnable() {
98                         public void run() {
99                                 _valueField.setVisible(false);
100                                 _valueAreaPane.setVisible(false);
101                                 _cancelButton.requestFocus();
102                         }
103                 });
104                 _dialog.setVisible(true);
105         }
106
107
108         /**
109          * Make the dialog components
110          * @return the GUI components for the dialog
111          */
112         private Component makeDialogComponents()
113         {
114                 JPanel panel = new JPanel();
115                 panel.setLayout(new BorderLayout(20, 10));
116                 // Create GUI layout for point editor
117                 _table = new JTable(_model)
118                 {
119                         // Paint the changed fields orange
120                         public Component prepareRenderer(TableCellRenderer renderer, int row, int column)
121                         {
122                                 Component comp = super.prepareRenderer(renderer, row, column);
123                                 boolean changed = ((EditFieldsTableModel) getModel()).getChanged(row);
124                                 comp.setBackground(changed ? Color.orange : getBackground());
125                                 return comp;
126                         }
127                 };
128                 _table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
129                 _table.getSelectionModel().clearSelection();
130                 _table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
131                         public void valueChanged(ListSelectionEvent e)
132                         {
133                                 fieldSelected();
134                         }
135                 });
136                 _table.setPreferredScrollableViewportSize(new Dimension(_table.getWidth() * 2, _table.getRowHeight() * 6));
137                 JScrollPane tablePane = new JScrollPane(_table);
138                 tablePane.setPreferredSize(new Dimension(150, 100));
139
140                 // Label at top
141                 JLabel topLabel = new JLabel(I18nManager.getText("dialog.pointedit.intro"));
142                 topLabel.setBorder(BorderFactory.createEmptyBorder(8, 6, 3, 6));
143                 panel.add(topLabel, BorderLayout.NORTH);
144
145                 // listener for ok event
146                 ActionListener okListener = new ActionListener() {
147                         public void actionPerformed(ActionEvent e)
148                         {
149                                 // update App with edit
150                                 confirmEdit();
151                                 _dialog.dispose();
152                         }
153                 };
154
155                 JPanel rightPanel = new JPanel();
156                 rightPanel.setLayout(new BorderLayout());
157                 JPanel rightiPanel = new JPanel();
158                 rightiPanel.setLayout(new BoxLayout(rightiPanel, BoxLayout.Y_AXIS));
159                 // Add GUI elements to rhs
160                 _fieldnameLabel = new JLabel(I18nManager.getText("dialog.pointedit.nofield"));
161                 rightiPanel.add(_fieldnameLabel);
162                 _valueField = new JTextField(11);
163                 // Add listener for enter button
164                 _valueField.addActionListener(okListener);
165                 rightiPanel.add(_valueField);
166                 rightPanel.add(rightiPanel, BorderLayout.NORTH);
167                 _valueArea = new JTextArea(5, 15);
168                 _valueArea.setLineWrap(true);
169                 _valueArea.setWrapStyleWord(true);
170                 _valueAreaPane = new JScrollPane(_valueArea);
171                 rightPanel.add(_valueAreaPane, BorderLayout.CENTER);
172
173                 // Put the table and the right-hand panel together in a grid
174                 JPanel mainPanel = new JPanel();
175                 mainPanel.setLayout(new GridLayout(0, 2, 10, 10));
176                 mainPanel.add(tablePane);
177                 mainPanel.add(rightPanel);
178                 panel.add(mainPanel, BorderLayout.CENTER);
179
180                 // Bottom panel for OK, cancel buttons
181                 JPanel lowerPanel = new JPanel();
182                 lowerPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
183                 _cancelButton = new JButton(I18nManager.getText("button.cancel"));
184                 _cancelButton.addActionListener(new ActionListener() {
185                         public void actionPerformed(ActionEvent e)
186                         {
187                                 _dialog.dispose();
188                         }
189                 });
190                 _cancelButton.addKeyListener(new KeyAdapter() {
191                         public void keyPressed(KeyEvent inE) {
192                                 if (inE.getKeyCode() == KeyEvent.VK_ESCAPE) {_dialog.dispose();}
193                         }
194                 });
195                 lowerPanel.add(_cancelButton);
196                 JButton okButton = new JButton(I18nManager.getText("button.ok"));
197                 okButton.addActionListener(okListener);
198                 lowerPanel.add(okButton);
199                 panel.add(lowerPanel, BorderLayout.SOUTH);
200                 return panel;
201         }
202
203
204         /**
205          * When table selection changes, need to update model and go to the selected field
206          */
207         private void fieldSelected()
208         {
209                 int rowNum = _table.getSelectedRow();
210                 if (rowNum == _prevRowIndex) {return;} // selection hasn't changed
211                 // Check the current values
212                 if (_prevRowIndex >= 0)
213                 {
214                         Field prevField = _track.getFieldList().getField(_prevRowIndex);
215                         boolean littleField = prevField.isBuiltIn() && prevField != Field.DESCRIPTION;
216                         String newValue = littleField ? _valueField.getText() : _valueArea.getText();
217                         // Update the model from the current GUI values
218                         _model.updateValue(_prevRowIndex, newValue);
219                 }
220
221                 if (rowNum < 0)
222                 {
223                         _fieldnameLabel.setText("");
224                 }
225                 else
226                 {
227                         String currValue = _model.getValue(rowNum);
228                         Field  field     = _track.getFieldList().getField(rowNum);
229                         _fieldnameLabel.setText(makeFieldLabel(field, _point));
230                         _fieldnameLabel.setVisible(true);
231                         boolean littleField = field.isBuiltIn() && field != Field.DESCRIPTION;
232                         if (littleField) {
233                                 _valueField.setText(currValue);
234                         }
235                         else {
236                                 _valueArea.setText(currValue);
237                         }
238                         _valueField.setVisible(littleField);
239                         _valueAreaPane.setVisible(!littleField);
240                         if (littleField) {
241                                 _valueField.requestFocus();
242                         }
243                         else {
244                                 _valueArea.requestFocus();
245                         }
246                 }
247                 _prevRowIndex = rowNum;
248         }
249
250         /**
251          * @param inField field
252          * @param inPoint current point
253          * @return label string for above the entry field / area
254          */
255         private static String makeFieldLabel(Field inField, DataPoint inPoint)
256         {
257                 String label = I18nManager.getText("dialog.pointedit.table.field") + ": " + inField.getName();
258                 // Add units if the field is altitude / speed / vspeed
259                 if (inField == Field.ALTITUDE)
260                 {
261                         label += makeUnitsLabel(inPoint.hasAltitude() ? inPoint.getAltitude().getUnit() : Config.getUnitSet().getAltitudeUnit());
262                 }
263                 else if (inField == Field.SPEED)
264                 {
265                         label += makeUnitsLabel(inPoint.hasHSpeed() ? inPoint.getHSpeed().getUnit() : Config.getUnitSet().getSpeedUnit());
266                 }
267                 else if (inField == Field.VERTICAL_SPEED)
268                 {
269                         label += makeUnitsLabel(inPoint.hasVSpeed() ? inPoint.getVSpeed().getUnit() : Config.getUnitSet().getVerticalSpeedUnit());
270                 }
271                 return label;
272         }
273
274         /**
275          * @param inUnit units for altitude / speed
276          * @return addition to the field label to describe the units
277          */
278         private static String makeUnitsLabel(Unit inUnit)
279         {
280                 if (inUnit == null) return "";
281                 return " (" + I18nManager.getText(inUnit.getShortnameKey()) + ")";
282         }
283
284         /**
285          * Confirm the edit and inform the app
286          */
287         private void confirmEdit()
288         {
289                 // Apply the edits to the current field
290                 int rowNum = _table.getSelectedRow();
291                 if (rowNum >= 0)
292                 {
293                         Field currField = _track.getFieldList().getField(rowNum);
294                         boolean littleField = currField.isBuiltIn() && currField != Field.DESCRIPTION;
295                         String newValue = littleField ? _valueField.getText() : _valueArea.getText();
296                         _model.updateValue(_prevRowIndex, newValue);
297                 }
298
299                 // Package the modified fields into an object
300                 FieldList fieldList = _track.getFieldList();
301                 int numFields = fieldList.getNumFields();
302                 // Make lists for edit and undo, and add each changed field in turn
303                 FieldEditList editList = new FieldEditList();
304                 FieldEditList undoList = new FieldEditList();
305                 for (int i=0; i<numFields; i++)
306                 {
307                         if (_model.getChanged(i))
308                         {
309                                 Field field = fieldList.getField(i);
310                                 editList.addEdit(new FieldEdit(field, _model.getValue(i)));
311                                 undoList.addEdit(new FieldEdit(field, _point.getFieldValue(field)));
312                         }
313                 }
314                 _app.completePointEdit(editList, undoList);
315         }
316 }