]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/save/FileSaver.java
Version 1, September 2006
[GpsPrune.git] / tim / prune / save / FileSaver.java
1 package tim.prune.save;
2
3 import java.awt.BorderLayout;
4 import java.awt.CardLayout;
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.io.File;
12 import java.io.FileWriter;
13 import java.io.IOException;
14
15 import javax.swing.BorderFactory;
16 import javax.swing.Box;
17 import javax.swing.BoxLayout;
18 import javax.swing.ButtonGroup;
19 import javax.swing.JButton;
20 import javax.swing.JDialog;
21 import javax.swing.JFileChooser;
22 import javax.swing.JFrame;
23 import javax.swing.JLabel;
24 import javax.swing.JOptionPane;
25 import javax.swing.JPanel;
26 import javax.swing.JRadioButton;
27 import javax.swing.JTable;
28 import javax.swing.JTextField;
29 import javax.swing.ListSelectionModel;
30
31 import tim.prune.App;
32 import tim.prune.I18nManager;
33 import tim.prune.data.Altitude;
34 import tim.prune.data.Coordinate;
35 import tim.prune.data.DataPoint;
36 import tim.prune.data.Field;
37 import tim.prune.data.FieldList;
38 import tim.prune.data.Track;
39 import tim.prune.load.OneCharDocument;
40
41 /**
42  * Class to manage the saving of track data
43  * into a user-specified file
44  */
45 public class FileSaver
46 {
47         private App _app = null;
48         private JFrame _parentFrame = null;
49         private Track _track = null;
50         private JDialog _dialog = null;
51         private JFileChooser _fileChooser = null;
52         private JPanel _cards = null;
53         private JButton _nextButton = null, _backButton = null;
54         private JTable _table = null;
55         private FieldSelectionTableModel _model = null;
56         private JButton _moveUpButton = null, _moveDownButton = null;
57         private JRadioButton[] _delimiterRadios = null;
58         private JTextField _otherDelimiterText = null;
59         private JRadioButton[] _coordUnitsRadios = null;
60         private JRadioButton[] _altitudeUnitsRadios = null;
61         private static final int[] FORMAT_COORDS = {Coordinate.FORMAT_NONE, Coordinate.FORMAT_DEG_MIN_SEC,
62                 Coordinate.FORMAT_DEG_MIN, Coordinate.FORMAT_DEG};
63         private static final int[] FORMAT_ALTS = {Altitude.FORMAT_NONE, Altitude.FORMAT_METRES, Altitude.FORMAT_FEET};
64
65
66         /**
67          * Constructor
68          * @param inApp application object to inform of success
69          * @param inParentFrame parent frame
70          * @param inTrack track object to save
71          */
72         public FileSaver(App inApp, JFrame inParentFrame, Track inTrack)
73         {
74                 _app = inApp;
75                 _parentFrame = inParentFrame;
76                 _track = inTrack;
77         }
78
79
80         /**
81          * Show the save file dialog
82          * @param inDefaultDelimiter default delimiter to use
83          */
84         public void showDialog(char inDefaultDelimiter)
85         {
86                 _dialog = new JDialog(_parentFrame, I18nManager.getText("dialog.saveoptions.title"), true);
87                 _dialog.setLocationRelativeTo(_parentFrame);
88                 // Check field list
89                 FieldList fieldList = _track.getFieldList();
90                 int numFields = fieldList.getNumFields();
91                 _model = new FieldSelectionTableModel(numFields);
92                 for (int i=0; i<numFields; i++)
93                 {
94                         Field field = fieldList.getField(i);
95                         FieldInfo info = new FieldInfo(field, _track.hasData(field));
96                         _model.addFieldInfo(info, i);
97                 }
98                 _dialog.getContentPane().add(makeDialogComponents(_model, inDefaultDelimiter));
99                 _dialog.pack();
100                 _dialog.show();
101         }
102
103
104         /**
105          * Make the dialog components
106          * @param inTableModel table model for fields
107          * @param inDelimiter default delimiter character
108          * @return the GUI components for the save dialog
109          */
110         private Component makeDialogComponents(FieldSelectionTableModel inTableModel, char inDelimiter)
111         {
112                 JPanel panel = new JPanel();
113                 panel.setLayout(new BorderLayout());
114                 _cards = new JPanel();
115                 _cards.setLayout(new CardLayout());
116                 panel.add(_cards, BorderLayout.CENTER);
117
118                 // Make first card for field selection and delimiter
119                 JPanel firstCard = new JPanel();
120                 firstCard.setLayout(new BoxLayout(firstCard, BoxLayout.Y_AXIS));
121                 JPanel tablePanel = new JPanel();
122                 tablePanel.setLayout(new BorderLayout());
123                 _table = new JTable(inTableModel);
124                 _table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
125                 tablePanel.add(_table.getTableHeader(), BorderLayout.NORTH);
126                 tablePanel.add(_table, BorderLayout.CENTER);
127
128                 // Make a panel to hold the table and up/down buttons
129                 JPanel fieldsPanel = new JPanel();
130                 fieldsPanel.setLayout(new BorderLayout());
131                 fieldsPanel.add(tablePanel, BorderLayout.CENTER);
132                 JPanel updownPanel = new JPanel();
133                 updownPanel.setLayout(new BoxLayout(updownPanel, BoxLayout.Y_AXIS));
134                 _moveUpButton = new JButton(I18nManager.getText("button.moveup"));
135                 _moveUpButton.addActionListener(new ActionListener() {
136                         public void actionPerformed(ActionEvent e)
137                         {
138                                 int row = _table.getSelectedRow();
139                                 if (row > 0)
140                                 {
141                                         _model.swapItems(row, row - 1);
142                                         _table.setRowSelectionInterval(row - 1, row - 1);
143                                 }
144                         }
145                 });
146                 _moveUpButton.setEnabled(false);
147                 updownPanel.add(_moveUpButton);
148                 _moveDownButton = new JButton(I18nManager.getText("button.movedown"));
149                 _moveDownButton.addActionListener(new ActionListener() {
150                         public void actionPerformed(ActionEvent e)
151                         {
152                                 int row = _table.getSelectedRow();
153                                 if (row > -1 && row < (_model.getRowCount() - 1))
154                                 {
155                                         _model.swapItems(row, row + 1);
156                                         _table.setRowSelectionInterval(row + 1, row + 1);
157                                 }
158                         }
159                 });
160                 _moveDownButton.setEnabled(false);
161                 updownPanel.add(_moveDownButton);
162                 fieldsPanel.add(updownPanel, BorderLayout.EAST);
163                 // enable/disable buttons based on table row selection
164                 _table.getSelectionModel().addListSelectionListener(
165                         new UpDownToggler(_moveUpButton, _moveDownButton, inTableModel.getRowCount())
166                 );
167
168                 // Add fields panel and the delimiter panel to first card in pack
169                 JLabel saveOptionsLabel = new JLabel(I18nManager.getText("dialog.save.fieldstosave"));
170                 saveOptionsLabel.setAlignmentX(JLabel.LEFT_ALIGNMENT);
171                 firstCard.add(saveOptionsLabel);
172                 fieldsPanel.setAlignmentX(JPanel.LEFT_ALIGNMENT);
173                 firstCard.add(fieldsPanel);
174                 firstCard.add(Box.createRigidArea(new Dimension(0,10)));
175
176                 // delimiter panel
177                 JLabel delimLabel = new JLabel(I18nManager.getText("dialog.delimiter.label"));
178                 delimLabel.setAlignmentX(JLabel.LEFT_ALIGNMENT);
179                 firstCard.add(delimLabel);
180                 JPanel delimsPanel = new JPanel();
181                 delimsPanel.setLayout(new GridLayout(0, 2));
182                 delimsPanel.setAlignmentX(JPanel.LEFT_ALIGNMENT);
183                 // radio buttons
184                 _delimiterRadios = new JRadioButton[5];
185                 _delimiterRadios[0] = new JRadioButton(I18nManager.getText("dialog.delimiter.comma"));
186                 delimsPanel.add(_delimiterRadios[0]);
187                 _delimiterRadios[1] = new JRadioButton(I18nManager.getText("dialog.delimiter.tab"));
188                 delimsPanel.add(_delimiterRadios[1]);
189                 _delimiterRadios[2] = new JRadioButton(I18nManager.getText("dialog.delimiter.semicolon"));
190                 delimsPanel.add(_delimiterRadios[2]);
191                 _delimiterRadios[3] = new JRadioButton(I18nManager.getText("dialog.delimiter.space"));
192                 delimsPanel.add(_delimiterRadios[3]);
193                 JPanel otherPanel = new JPanel();
194                 otherPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
195                 _delimiterRadios[4] = new JRadioButton(I18nManager.getText("dialog.delimiter.other"));
196                 otherPanel.add(_delimiterRadios[4]);
197                 _otherDelimiterText = new JTextField(new OneCharDocument(), null, 2);
198                 otherPanel.add(_otherDelimiterText);
199                 // Group radio buttons
200                 ButtonGroup delimGroup = new ButtonGroup();
201                 for (int i=0; i<_delimiterRadios.length; i++)
202                 {
203                         delimGroup.add(_delimiterRadios[i]);
204                 }
205                 // choose last-used delimiter as default
206                 switch (inDelimiter)
207                 {
208                         case ','  : _delimiterRadios[0].setSelected(true); break;
209                         case '\t' : _delimiterRadios[1].setSelected(true); break;
210                         case ';'  : _delimiterRadios[2].setSelected(true); break;
211                         case ' '  : _delimiterRadios[3].setSelected(true); break;
212                         default   : _delimiterRadios[4].setSelected(true);
213                                                 _otherDelimiterText.setText("" + inDelimiter);
214                 }
215                 delimsPanel.add(otherPanel);
216                 firstCard.add(delimsPanel);
217                 _cards.add(firstCard, "card1");
218
219                 JPanel secondCard = new JPanel();
220                 secondCard.setLayout(new BorderLayout());
221                 JPanel secondCardHolder = new JPanel();
222                 secondCardHolder.setLayout(new BoxLayout(secondCardHolder, BoxLayout.Y_AXIS));
223                 JLabel coordLabel = new JLabel(I18nManager.getText("dialog.save.coordinateunits"));
224                 coordLabel.setAlignmentX(JLabel.LEFT_ALIGNMENT);
225                 secondCardHolder.add(coordLabel);
226                 JPanel coordsUnitsPanel = new JPanel();
227                 coordsUnitsPanel.setBorder(BorderFactory.createEtchedBorder());
228                 coordsUnitsPanel.setLayout(new GridLayout(0, 2));
229                 _coordUnitsRadios = new JRadioButton[4];
230                 _coordUnitsRadios[0] = new JRadioButton(I18nManager.getText("dialog.save.units.original"));
231                 _coordUnitsRadios[1] = new JRadioButton(I18nManager.getText("units.degminsec"));
232                 _coordUnitsRadios[2] = new JRadioButton(I18nManager.getText("units.degmin"));
233                 _coordUnitsRadios[3] = new JRadioButton(I18nManager.getText("units.deg"));
234                 ButtonGroup coordGroup = new ButtonGroup();
235                 for (int i=0; i<4; i++)
236                 {
237                         coordGroup.add(_coordUnitsRadios[i]);
238                         coordsUnitsPanel.add(_coordUnitsRadios[i]);
239                         _coordUnitsRadios[i].setSelected(i==0);
240                 }
241                 coordsUnitsPanel.setAlignmentX(JPanel.LEFT_ALIGNMENT);
242                 secondCardHolder.add(coordsUnitsPanel);
243                 secondCardHolder.add(Box.createRigidArea(new Dimension(0,10)));
244                 JLabel altUnitsLabel = new JLabel(I18nManager.getText("dialog.save.altitudeunits"));
245                 altUnitsLabel.setAlignmentX(JLabel.LEFT_ALIGNMENT);
246                 secondCardHolder.add(altUnitsLabel);
247                 JPanel altUnitsPanel = new JPanel();
248                 altUnitsPanel.setBorder(BorderFactory.createEtchedBorder());
249                 altUnitsPanel.setLayout(new GridLayout(0, 2));
250                 _altitudeUnitsRadios = new JRadioButton[3];
251                 _altitudeUnitsRadios[0] = new JRadioButton(I18nManager.getText("dialog.save.units.original"));
252                 _altitudeUnitsRadios[1] = new JRadioButton(I18nManager.getText("units.metres"));
253                 _altitudeUnitsRadios[2] = new JRadioButton(I18nManager.getText("units.feet"));
254                 ButtonGroup altGroup = new ButtonGroup();
255                 for (int i=0; i<3; i++)
256                 {
257                         altGroup.add(_altitudeUnitsRadios[i]);
258                         altUnitsPanel.add(_altitudeUnitsRadios[i]);
259                         _altitudeUnitsRadios[i].setSelected(i==0);
260                 }
261                 altUnitsPanel.setAlignmentX(JPanel.LEFT_ALIGNMENT);
262                 secondCardHolder.add(altUnitsPanel);
263                 secondCard.add(secondCardHolder, BorderLayout.NORTH);
264                 _cards.add(secondCard, "card2");
265
266                 // Put together with ok/cancel buttons on the bottom
267                 JPanel buttonPanel = new JPanel();
268                 buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
269                 _backButton = new JButton(I18nManager.getText("button.back"));
270                 _backButton.addActionListener(new ActionListener() {
271                         public void actionPerformed(ActionEvent e)
272                         {
273                             CardLayout cl = (CardLayout)(_cards.getLayout());
274                             cl.previous(_cards);
275                             _backButton.setEnabled(false);
276                             _nextButton.setEnabled(true);
277                         }
278                 });
279                 _backButton.setEnabled(false);
280                 buttonPanel.add(_backButton);
281                 _nextButton = new JButton(I18nManager.getText("button.next"));
282                 _nextButton.setEnabled(true);
283                 _nextButton.addActionListener(new ActionListener() {
284                         public void actionPerformed(ActionEvent e)
285                         {
286                             CardLayout cl = (CardLayout)(_cards.getLayout());
287                             cl.next(_cards);
288                             _backButton.setEnabled(true);
289                             _nextButton.setEnabled(false);
290                         }
291                 });
292                 buttonPanel.add(_nextButton);
293                 JButton okButton = new JButton(I18nManager.getText("button.finish"));
294                 okButton.addActionListener(new ActionListener() {
295                         public void actionPerformed(ActionEvent e)
296                         {
297                                 if (saveToFile())
298                                 {
299                                         _dialog.dispose();
300                                 }
301                         }
302                 });
303                 buttonPanel.add(okButton);
304                 JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
305                 cancelButton.addActionListener(new ActionListener() {
306                         public void actionPerformed(ActionEvent e)
307                         {
308                                 _dialog.dispose();
309                         }
310                 });
311                 buttonPanel.add(cancelButton);
312                 panel.add(buttonPanel, BorderLayout.SOUTH);
313                 return panel;
314         }
315
316
317         /**
318          * Save the track to file with the chosen options
319          * @return true if successful or cancelled, false if failed
320          */
321         private boolean saveToFile()
322         {
323                 boolean saveOK = true;
324                 FileWriter writer = null;
325                 if (_fileChooser == null)
326                         _fileChooser = new JFileChooser();
327                 _fileChooser.setDialogType(JFileChooser.SAVE_DIALOG);
328                 if (_fileChooser.showSaveDialog(_parentFrame) == JFileChooser.APPROVE_OPTION)
329                 {
330                         File saveFile = _fileChooser.getSelectedFile();
331                         String lineSeparator = System.getProperty("line.separator");
332                         // Get coordinate format and altitude format
333                         int coordFormat = Coordinate.FORMAT_NONE;
334                         for (int i=0; i<_coordUnitsRadios.length; i++)
335                                 if (_coordUnitsRadios[i].isSelected())
336                                         coordFormat = FORMAT_COORDS[i];
337                         int altitudeFormat = Altitude.FORMAT_NONE;
338                         for (int i=0; i<_altitudeUnitsRadios.length; i++)
339                                 if (_altitudeUnitsRadios[i].isSelected())
340                                         altitudeFormat = FORMAT_ALTS[i];
341                         
342                         // Check if file exists, don't overwrite any files for v1!
343                         if (!saveFile.exists())
344                         {
345                                 try
346                                 {
347                                         // Create output file
348                                         writer = new FileWriter(saveFile);
349                                         // Determine delimiter character to use
350                                         char delimiter = getDelimiter();
351                                         FieldInfo info = null;
352                                         Field field = null;
353                                         StringBuffer buffer = null;
354                                         // For now, just spit out to console
355                                         int numPoints = _track.getNumPoints();
356                                         int numFields = _model.getRowCount();
357                                         for (int p=0; p<numPoints; p++)
358                                         {
359                                                 DataPoint point = _track.getPoint(p);
360                                                 boolean firstField = true;
361                                                 buffer = new StringBuffer();
362                                                 for (int f=0; f<numFields; f++)
363                                                 {
364                                                         info = _model.getFieldInfo(f);
365                                                         if (info.isSelected())
366                                                         {
367                                                                 if (!firstField)
368                                                                 {
369                                                                         // output field separator
370                                                                         buffer.append(delimiter);
371                                                                 }
372                                                                 field = info.getField();
373                                                                 // Output field according to type
374                                                                 if (field == Field.LATITUDE)
375                                                                 {
376                                                                         buffer.append(point.getLatitude().output(coordFormat));
377                                                                 }
378                                                                 else if (field == Field.LONGITUDE)
379                                                                 {
380                                                                         buffer.append(point.getLongitude().output(coordFormat));
381                                                                 }
382                                                                 else if (field == Field.ALTITUDE)
383                                                                 {
384                                                                         buffer.append(point.getAltitude().getValue(altitudeFormat));
385                                                                 }
386                                                                 else if (field == Field.TIMESTAMP)
387                                                                 {
388                                                                         buffer.append(point.getTimestamp().getText());
389                                                                 }
390                                                                 else
391                                                                 {
392                                                                         String value = point.getFieldValue(field);
393                                                                         if (value != null)
394                                                                         {
395                                                                                 buffer.append(value);
396                                                                         }
397                                                                 }
398                                                                 firstField = false;
399                                                         }
400                                                 }
401                                                 // Output to file
402                                                 writer.write(buffer.toString());
403                                                 writer.write(lineSeparator);
404                                         }
405                                         // Save successful
406                                         JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("dialog.save.ok1")
407                                                  + " " + numPoints + " " + I18nManager.getText("dialog.save.ok2")
408                                                  + saveFile.getAbsolutePath(),
409                                                 I18nManager.getText("dialog.save.oktitle"), JOptionPane.INFORMATION_MESSAGE);
410                                         _app.informDataSaved();
411                                 }
412                                 catch (IOException ioe)
413                                 {
414                                         saveOK = false;
415                                         JOptionPane.showMessageDialog(_parentFrame,
416                                                 I18nManager.getText("error.save.failed") + ioe.getMessage(),
417                                                 I18nManager.getText("error.save.dialogtitle"),
418                                                 JOptionPane.ERROR_MESSAGE);
419                                 }
420                                 finally
421                                 {
422                                         // try to close file if it's open
423                                         try
424                                         {
425                                                 if (writer != null)
426                                                 {
427                                                         writer.close();
428                                                 }
429                                         }
430                                         catch (Exception e) {}
431                                 }
432                         }
433                         else
434                         {
435                                 saveOK = false;
436                                 JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("error.save.fileexists"),
437                                         I18nManager.getText("error.save.dialogtitle"), JOptionPane.ERROR_MESSAGE);
438                         }
439                 }
440                 return saveOK;
441         }
442
443
444         /**
445          * @return the selected delimiter character
446          */
447         private char getDelimiter()
448         {
449                 // Check the preset 4 delimiters
450                 final char[] delimiters = {',', '\t', ';', ' '};
451                 for (int i=0; i<4; i++)
452                 {
453                         if (_delimiterRadios[i].isSelected())
454                         {
455                                 return delimiters[i];
456                         }
457                 }
458                 // Wasn't any of those so must be 'other'
459                 return _otherDelimiterText.getText().charAt(0);
460         }
461 }