]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/function/edit/PointEditor.java
40cf12ba251495dfebca5a673c4f67cf6b3c816e
[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
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;
28
29 import tim.prune.App;
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;
37
38 /**
39  * Class to manage the display and editing of point data
40  */
41 public class PointEditor
42 {
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;
55
56
57         /**
58          * Constructor
59          * @param inApp application object to inform of success
60          * @param inParentFrame parent frame
61          */
62         public PointEditor(App inApp, JFrame inParentFrame)
63         {
64                 _app = inApp;
65                 _parentFrame = inParentFrame;
66         }
67
68
69         /**
70          * Show the edit point dialog
71          * @param inTrack track object
72          * @param inPoint point to edit
73          */
74         public void showDialog(Track inTrack, DataPoint inPoint)
75         {
76                 _track = inTrack;
77                 _point = inPoint;
78                 _dialog = new JDialog(_parentFrame, I18nManager.getText("dialog.pointedit.title"), true);
79                 _dialog.setLocationRelativeTo(_parentFrame);
80                 // Check field list
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++)
86                 {
87                         Field field = fieldList.getField(i);
88                         _model.addFieldInfo(field.getName(), _point.getFieldValue(field), i);
89                 }
90                 // Create Gui
91                 _dialog.getContentPane().add(makeDialogComponents());
92                 _dialog.pack();
93                 // Init right-hand side
94                 SwingUtilities.invokeLater(new Runnable() {
95                         public void run() {
96                                 _valueField.setVisible(false);
97                                 _valueAreaPane.setVisible(false);
98                         }
99                 });
100                 _dialog.setVisible(true);
101         }
102
103
104         /**
105          * Make the dialog components
106          * @return the GUI components for the dialog
107          */
108         private Component makeDialogComponents()
109         {
110                 JPanel panel = new JPanel();
111                 panel.setLayout(new BorderLayout(20, 10));
112                 // Create GUI layout for point editor
113                 _table = new JTable(_model)
114                 {
115                         // Paint the changed fields orange
116                         public Component prepareRenderer(TableCellRenderer renderer, int row, int column)
117                         {
118                                 Component comp = super.prepareRenderer(renderer, row, column);
119                                 boolean changed = ((EditFieldsTableModel) getModel()).getChanged(row);
120                                 comp.setBackground(changed ? Color.orange : getBackground());
121                                 return comp;
122                         }
123                 };
124                 _table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
125                 _table.getSelectionModel().clearSelection();
126                 _table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
127                         public void valueChanged(ListSelectionEvent e)
128                         {
129                                 fieldSelected();
130                         }
131                 });
132                 _table.setPreferredScrollableViewportSize(new Dimension(_table.getWidth() * 2, _table.getRowHeight() * 6));
133                 JScrollPane tablePane = new JScrollPane(_table);
134                 tablePane.setPreferredSize(new Dimension(150, 100));
135
136                 // Label at top
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);
140
141                 // listener for ok event
142                 ActionListener okListener = new ActionListener() {
143                         public void actionPerformed(ActionEvent e)
144                         {
145                                 // update App with edit
146                                 confirmEdit();
147                                 _dialog.dispose();
148                         }
149                 };
150
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);
168
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);
175
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)
182                         {
183                                 _dialog.dispose();
184                         }
185                 });
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);
191                 return panel;
192         }
193
194
195         /**
196          * When table selection changes, need to update model and go to the selected field
197          */
198         private void fieldSelected()
199         {
200                 int rowNum = _table.getSelectedRow();
201                 if (rowNum == _prevRowIndex) {return;} // selection hasn't changed
202                 // Check the current values
203                 if (_prevRowIndex >= 0)
204                 {
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);
210                 }
211
212                 if (rowNum < 0)
213                 {
214                         _fieldnameLabel.setText("");
215                 }
216                 else
217                 {
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;
223                         if (littleField) {
224                                 _valueField.setText(currValue);
225                         }
226                         else {
227                                 _valueArea.setText(currValue);
228                         }
229                         _valueField.setVisible(littleField);
230                         _valueAreaPane.setVisible(!littleField);
231                         if (littleField) {
232                                 _valueField.requestFocus();
233                         }
234                         else {
235                                 _valueArea.requestFocus();
236                         }
237                 }
238                 _prevRowIndex = rowNum;
239         }
240
241         /**
242          * @param inField field
243          * @param inPoint current point
244          * @return label string for above the entry field / area
245          */
246         private static String makeFieldLabel(Field inField, DataPoint inPoint)
247         {
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)
251                 {
252                         label += makeUnitsLabel(inPoint.hasAltitude() ? inPoint.getAltitude().getUnit() : Config.getUnitSet().getAltitudeUnit());
253                 }
254                 else if (inField == Field.SPEED)
255                 {
256                         label += makeUnitsLabel(inPoint.hasHSpeed() ? inPoint.getHSpeed().getUnit() : Config.getUnitSet().getSpeedUnit());
257                 }
258                 else if (inField == Field.VERTICAL_SPEED)
259                 {
260                         label += makeUnitsLabel(inPoint.hasVSpeed() ? inPoint.getVSpeed().getUnit() : Config.getUnitSet().getVerticalSpeedUnit());
261                 }
262                 return label;
263         }
264
265         /**
266          * @param inUnit units for altitude / speed
267          * @return addition to the field label to describe the units
268          */
269         private static String makeUnitsLabel(Unit inUnit)
270         {
271                 if (inUnit == null) return "";
272                 return " (" + I18nManager.getText(inUnit.getShortnameKey()) + ")";
273         }
274
275         /**
276          * Confirm the edit and inform the app
277          */
278         private void confirmEdit()
279         {
280                 // Apply the edits to the current field
281                 int rowNum = _table.getSelectedRow();
282                 if (rowNum >= 0)
283                 {
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);
288                 }
289
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++)
297                 {
298                         if (_model.getChanged(i))
299                         {
300                                 Field field = fieldList.getField(i);
301                                 editList.addEdit(new FieldEdit(field, _model.getValue(i)));
302                                 undoList.addEdit(new FieldEdit(field, _point.getFieldValue(field)));
303                         }
304                 }
305                 _app.completePointEdit(editList, undoList);
306         }
307 }