]> gitweb.fperrin.net Git - GpsPrune.git/blobdiff - tim/prune/save/FileSaver.java
Moved source into separate src directory due to popular request
[GpsPrune.git] / tim / prune / save / FileSaver.java
diff --git a/tim/prune/save/FileSaver.java b/tim/prune/save/FileSaver.java
deleted file mode 100644 (file)
index 45af83e..0000000
+++ /dev/null
@@ -1,658 +0,0 @@
-package tim.prune.save;
-
-import java.awt.BorderLayout;
-import java.awt.CardLayout;
-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 java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-
-import javax.swing.BorderFactory;
-import javax.swing.Box;
-import javax.swing.BoxLayout;
-import javax.swing.ButtonGroup;
-import javax.swing.JButton;
-import javax.swing.JCheckBox;
-import javax.swing.JDialog;
-import javax.swing.JFileChooser;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JRadioButton;
-import javax.swing.JScrollPane;
-import javax.swing.JTable;
-import javax.swing.JTextField;
-import javax.swing.ListSelectionModel;
-import javax.swing.table.TableModel;
-
-import tim.prune.App;
-import tim.prune.I18nManager;
-import tim.prune.UpdateMessageBroker;
-import tim.prune.config.Config;
-import tim.prune.data.Coordinate;
-import tim.prune.data.DataPoint;
-import tim.prune.data.Field;
-import tim.prune.data.FieldList;
-import tim.prune.data.RecentFile;
-import tim.prune.data.Timestamp;
-import tim.prune.data.Track;
-import tim.prune.data.Unit;
-import tim.prune.data.UnitSetLibrary;
-import tim.prune.load.GenericFileFilter;
-import tim.prune.load.OneCharDocument;
-
-/**
- * Class to manage the saving of track data
- * as text into a user-specified file
- */
-public class FileSaver
-{
-       private App _app = null;
-       private JFrame _parentFrame = null;
-       private JDialog _dialog = null;
-       private JFileChooser _fileChooser = null;
-       private JPanel _cards = null;
-       private JButton _nextButton = null, _backButton = null;
-       private JTable _table = null;
-       private FieldSelectionTableModel _model = null;
-       private JButton _moveUpButton = null, _moveDownButton = null;
-       private UpDownToggler _toggler = null;
-       private JRadioButton[] _delimiterRadios = null;
-       private JTextField _otherDelimiterText = null;
-       private JCheckBox _headerRowCheckbox = null;
-       private PointTypeSelector _pointTypeSelector = null;
-       private JRadioButton[] _coordUnitsRadios = null;
-       private JRadioButton[] _altitudeUnitsRadios = null;
-       private JRadioButton[] _timestampUnitsRadios = null;
-
-       private static final int[] FORMAT_COORDS = {Coordinate.FORMAT_NONE, Coordinate.FORMAT_DEG_MIN_SEC,
-               Coordinate.FORMAT_DEG_MIN, Coordinate.FORMAT_DEG};
-       private static final Unit[] UNIT_ALTS = {null, UnitSetLibrary.UNITS_METRES, UnitSetLibrary.UNITS_FEET};
-       private static final Timestamp.Format[] FORMAT_TIMES = {Timestamp.Format.ORIGINAL, Timestamp.Format.LOCALE, Timestamp.Format.ISO8601};
-
-
-       /**
-        * Constructor
-        * @param inApp application object to inform of success
-        * @param inParentFrame parent frame
-        */
-       public FileSaver(App inApp, JFrame inParentFrame)
-       {
-               _app = inApp;
-               _parentFrame = inParentFrame;
-       }
-
-
-       /**
-        * Show the save file dialog
-        * @param inDefaultDelimiter default delimiter to use
-        */
-       public void showDialog(char inDefaultDelimiter)
-       {
-               if (_dialog == null)
-               {
-                       _dialog = new JDialog(_parentFrame, I18nManager.getText("dialog.saveoptions.title"), true);
-                       _dialog.setLocationRelativeTo(_parentFrame);
-                       _dialog.getContentPane().add(makeDialogComponents());
-                       _dialog.pack();
-               }
-               // Has the track got media?
-               final boolean hasMedia = _app.getTrackInfo().getPhotoList().hasCorrelatedPhotos()
-                       || _app.getTrackInfo().getAudioList().hasCorrelatedAudios();
-               // Check field list
-               Track track = _app.getTrackInfo().getTrack();
-               FieldList fieldList = track.getFieldList();
-               int numFields = fieldList.getNumFields();
-               _model = new FieldSelectionTableModel(numFields + (hasMedia ? 1 : 0));
-               for (int i=0; i<numFields; i++)
-               {
-                       Field field = fieldList.getField(i);
-                       FieldInfo info = new FieldInfo(field, track.hasData(field));
-                       _model.addFieldInfo(info, i);
-               }
-               // Add a field for photos / audio if any present
-               if (hasMedia)
-               {
-                       _model.addFieldInfo(new FieldInfo(Field.MEDIA_FILENAME, true), numFields);
-               }
-               // Initialise dialog and show it
-               initDialog(_model, inDefaultDelimiter);
-               _dialog.setVisible(true);
-       }
-
-
-       /**
-        * Make the dialog components
-        * @return the GUI components for the save dialog
-        */
-       private Component makeDialogComponents()
-       {
-               JPanel panel = new JPanel();
-               panel.setLayout(new BorderLayout());
-               _cards = new JPanel();
-               _cards.setLayout(new CardLayout());
-               panel.add(_cards, BorderLayout.CENTER);
-
-               // Make first card for field selection and delimiter
-               JPanel firstCard = new JPanel();
-               firstCard.setLayout(new BoxLayout(firstCard, BoxLayout.Y_AXIS));
-               JPanel tablePanel = new JPanel();
-               tablePanel.setLayout(new BorderLayout());
-               _table = new JTable();
-               _table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-               // Enclose table in a scrollpane to prevent other components getting lost
-               JScrollPane scrollPane = new JScrollPane(_table);
-               _table.setPreferredScrollableViewportSize(new Dimension(300, 150));
-               tablePanel.add(scrollPane, BorderLayout.CENTER);
-
-               // Make a panel to hold the table and up/down buttons
-               JPanel fieldsPanel = new JPanel();
-               fieldsPanel.setLayout(new BorderLayout());
-               fieldsPanel.add(tablePanel, BorderLayout.CENTER);
-               JPanel updownPanel = new JPanel();
-               updownPanel.setLayout(new BoxLayout(updownPanel, BoxLayout.Y_AXIS));
-               _moveUpButton = new JButton(I18nManager.getText("button.moveup"));
-               _moveUpButton.addActionListener(new ActionListener() {
-                       public void actionPerformed(ActionEvent e)
-                       {
-                               int row = _table.getSelectedRow();
-                               if (row > 0)
-                               {
-                                       _model.swapItems(row, row - 1);
-                                       _table.setRowSelectionInterval(row - 1, row - 1);
-                               }
-                       }
-               });
-               _moveUpButton.setEnabled(false);
-               updownPanel.add(_moveUpButton);
-               _moveDownButton = new JButton(I18nManager.getText("button.movedown"));
-               _moveDownButton.addActionListener(new ActionListener() {
-                       public void actionPerformed(ActionEvent e)
-                       {
-                               int row = _table.getSelectedRow();
-                               if (row > -1 && row < (_model.getRowCount() - 1))
-                               {
-                                       _model.swapItems(row, row + 1);
-                                       _table.setRowSelectionInterval(row + 1, row + 1);
-                               }
-                       }
-               });
-               _moveDownButton.setEnabled(false);
-               updownPanel.add(_moveDownButton);
-               fieldsPanel.add(updownPanel, BorderLayout.EAST);
-               // enable/disable buttons based on table row selection
-               _toggler = new UpDownToggler(_moveUpButton, _moveDownButton);
-               _table.getSelectionModel().addListSelectionListener(_toggler);
-
-               // Add fields panel and the delimiter panel to first card in pack
-               JLabel saveOptionsLabel = new JLabel(I18nManager.getText("dialog.save.fieldstosave"));
-               saveOptionsLabel.setAlignmentX(JLabel.LEFT_ALIGNMENT);
-               firstCard.add(saveOptionsLabel);
-               fieldsPanel.setAlignmentX(JPanel.LEFT_ALIGNMENT);
-               firstCard.add(fieldsPanel);
-               firstCard.add(Box.createRigidArea(new Dimension(0,10)));
-
-               // delimiter panel
-               JLabel delimLabel = new JLabel(I18nManager.getText("dialog.delimiter.label"));
-               delimLabel.setAlignmentX(JLabel.LEFT_ALIGNMENT);
-               firstCard.add(delimLabel);
-               JPanel delimsPanel = new JPanel();
-               delimsPanel.setLayout(new GridLayout(0, 2));
-               delimsPanel.setAlignmentX(JPanel.LEFT_ALIGNMENT);
-               // radio buttons
-               _delimiterRadios = new JRadioButton[5];
-               _delimiterRadios[0] = new JRadioButton(I18nManager.getText("dialog.delimiter.comma"));
-               delimsPanel.add(_delimiterRadios[0]);
-               _delimiterRadios[1] = new JRadioButton(I18nManager.getText("dialog.delimiter.tab"));
-               delimsPanel.add(_delimiterRadios[1]);
-               _delimiterRadios[2] = new JRadioButton(I18nManager.getText("dialog.delimiter.semicolon"));
-               delimsPanel.add(_delimiterRadios[2]);
-               _delimiterRadios[3] = new JRadioButton(I18nManager.getText("dialog.delimiter.space"));
-               delimsPanel.add(_delimiterRadios[3]);
-               JPanel otherPanel = new JPanel();
-               otherPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
-               _delimiterRadios[4] = new JRadioButton(I18nManager.getText("dialog.delimiter.other"));
-               otherPanel.add(_delimiterRadios[4]);
-               _otherDelimiterText = new JTextField(new OneCharDocument(), null, 2);
-               otherPanel.add(_otherDelimiterText);
-               // Group radio buttons
-               ButtonGroup delimGroup = new ButtonGroup();
-               for (int i=0; i<_delimiterRadios.length; i++)
-               {
-                       delimGroup.add(_delimiterRadios[i]);
-               }
-               delimsPanel.add(otherPanel);
-               firstCard.add(delimsPanel);
-
-               // header checkbox
-               firstCard.add(Box.createRigidArea(new Dimension(0,10)));
-               _headerRowCheckbox = new JCheckBox(I18nManager.getText("dialog.save.headerrow"), true);
-               firstCard.add(_headerRowCheckbox);
-               _cards.add(firstCard, "card1");
-
-               // Second card
-               JPanel secondCard = new JPanel();
-               secondCard.setLayout(new BorderLayout());
-               JPanel secondCardHolder = new JPanel();
-               secondCardHolder.setLayout(new BoxLayout(secondCardHolder, BoxLayout.Y_AXIS));
-               // point type selector
-               secondCardHolder.add(Box.createRigidArea(new Dimension(0,10)));
-               _pointTypeSelector = new PointTypeSelector();
-               _pointTypeSelector.setAlignmentX(JLabel.LEFT_ALIGNMENT);
-               secondCardHolder.add(_pointTypeSelector);
-               JLabel coordLabel = new JLabel(I18nManager.getText("dialog.save.coordinateunits"));
-               coordLabel.setAlignmentX(JLabel.LEFT_ALIGNMENT);
-               secondCardHolder.add(coordLabel);
-               JPanel coordsUnitsPanel = new JPanel();
-               coordsUnitsPanel.setBorder(BorderFactory.createEtchedBorder());
-               coordsUnitsPanel.setLayout(new GridLayout(0, 2));
-               _coordUnitsRadios = new JRadioButton[4];
-               _coordUnitsRadios[0] = new JRadioButton(I18nManager.getText("units.original"));
-               _coordUnitsRadios[1] = new JRadioButton(I18nManager.getText("units.degminsec"));
-               _coordUnitsRadios[2] = new JRadioButton(I18nManager.getText("units.degmin"));
-               _coordUnitsRadios[3] = new JRadioButton(I18nManager.getText("units.deg"));
-               ButtonGroup coordGroup = new ButtonGroup();
-               for (int i=0; i<4; i++)
-               {
-                       coordGroup.add(_coordUnitsRadios[i]);
-                       coordsUnitsPanel.add(_coordUnitsRadios[i]);
-                       _coordUnitsRadios[i].setSelected(i==0);
-               }
-               coordsUnitsPanel.setAlignmentX(JPanel.LEFT_ALIGNMENT);
-               secondCardHolder.add(coordsUnitsPanel);
-               secondCardHolder.add(Box.createRigidArea(new Dimension(0,7)));
-               // altitude units
-               JLabel altUnitsLabel = new JLabel(I18nManager.getText("dialog.save.altitudeunits"));
-               altUnitsLabel.setAlignmentX(JLabel.LEFT_ALIGNMENT);
-               secondCardHolder.add(altUnitsLabel);
-               JPanel altUnitsPanel = new JPanel();
-               altUnitsPanel.setBorder(BorderFactory.createEtchedBorder());
-               altUnitsPanel.setLayout(new GridLayout(0, 2));
-               _altitudeUnitsRadios = new JRadioButton[3];
-               _altitudeUnitsRadios[0] = new JRadioButton(I18nManager.getText("units.original"));
-               _altitudeUnitsRadios[1] = new JRadioButton(I18nManager.getText("units.metres"));
-               _altitudeUnitsRadios[2] = new JRadioButton(I18nManager.getText("units.feet"));
-               ButtonGroup altGroup = new ButtonGroup();
-               for (int i=0; i<3; i++)
-               {
-                       altGroup.add(_altitudeUnitsRadios[i]);
-                       altUnitsPanel.add(_altitudeUnitsRadios[i]);
-                       _altitudeUnitsRadios[i].setSelected(i==0);
-               }
-               altUnitsPanel.setAlignmentX(JPanel.LEFT_ALIGNMENT);
-               secondCardHolder.add(altUnitsPanel);
-               secondCardHolder.add(Box.createRigidArea(new Dimension(0,7)));
-               // Selection of format of timestamps
-               JLabel timestampLabel = new JLabel(I18nManager.getText("dialog.save.timestampformat"));
-               timestampLabel.setAlignmentX(JLabel.LEFT_ALIGNMENT);
-               secondCardHolder.add(timestampLabel);
-               JPanel timestampPanel = new JPanel();
-               timestampPanel.setBorder(BorderFactory.createEtchedBorder());
-               timestampPanel.setLayout(new GridLayout(0, 2));
-               _timestampUnitsRadios = new JRadioButton[3];
-               _timestampUnitsRadios[0] = new JRadioButton(I18nManager.getText("units.original"));
-               _timestampUnitsRadios[1] = new JRadioButton(I18nManager.getText("units.default"));
-               _timestampUnitsRadios[2] = new JRadioButton(I18nManager.getText("units.iso8601"));
-               ButtonGroup timeGroup = new ButtonGroup();
-               for (int i=0; i<3; i++)
-               {
-                       timeGroup.add(_timestampUnitsRadios[i]);
-                       timestampPanel.add(_timestampUnitsRadios[i]);
-                       _timestampUnitsRadios[i].setSelected(i==0);
-               }
-               timestampPanel.setAlignmentX(JPanel.LEFT_ALIGNMENT);
-               secondCardHolder.add(timestampPanel);
-               secondCard.add(secondCardHolder, BorderLayout.NORTH);
-               _cards.add(secondCard, "card2");
-
-               // Put together with ok/cancel buttons on the bottom
-               JPanel buttonPanel = new JPanel();
-               buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
-               _backButton = new JButton(I18nManager.getText("button.back"));
-               _backButton.addActionListener(new ActionListener() {
-                       public void actionPerformed(ActionEvent e)
-                       {
-                               CardLayout cl = (CardLayout) _cards.getLayout();
-                               cl.previous(_cards);
-                               _backButton.setEnabled(false);
-                               _nextButton.setEnabled(true);
-                       }
-               });
-               _backButton.setEnabled(false);
-               buttonPanel.add(_backButton);
-               _nextButton = new JButton(I18nManager.getText("button.next"));
-               _nextButton.setEnabled(true);
-               _nextButton.addActionListener(new ActionListener() {
-                       public void actionPerformed(ActionEvent e)
-                       {
-                               CardLayout cl = (CardLayout) _cards.getLayout();
-                               cl.next(_cards);
-                               _backButton.setEnabled(true);
-                               _nextButton.setEnabled(false);
-                       }
-               });
-               buttonPanel.add(_nextButton);
-               JButton okButton = new JButton(I18nManager.getText("button.finish"));
-               okButton.addActionListener(new ActionListener() {
-                       public void actionPerformed(ActionEvent e)
-                       {
-                               if (saveToFile())
-                               {
-                                       _dialog.dispose();
-                               }
-                       }
-               });
-               buttonPanel.add(okButton);
-               JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
-               cancelButton.addActionListener(new ActionListener() {
-                       public void actionPerformed(ActionEvent e)
-                       {
-                               _dialog.dispose();
-                       }
-               });
-               buttonPanel.add(cancelButton);
-               panel.add(buttonPanel, BorderLayout.SOUTH);
-               return panel;
-       }
-
-       /**
-        * Initialize the dialog with the given details
-        * @param inModel table model
-        * @param inDefaultDelimiter default delimiter character
-        */
-       private void initDialog(TableModel inModel, char inDefaultDelimiter)
-       {
-               // set table model
-               _table.setModel(inModel);
-               // reset toggler
-               _toggler.setListSize(inModel.getRowCount());
-               // choose last-used delimiter as default
-               switch (inDefaultDelimiter)
-               {
-                       case ','  : _delimiterRadios[0].setSelected(true); break;
-                       case '\t' : _delimiterRadios[1].setSelected(true); break;
-                       case ';'  : _delimiterRadios[2].setSelected(true); break;
-                       case ' '  : _delimiterRadios[3].setSelected(true); break;
-                       default   : _delimiterRadios[4].setSelected(true);
-                                               _otherDelimiterText.setText("" + inDefaultDelimiter);
-               }
-               _pointTypeSelector.init(_app.getTrackInfo());
-               // set card and enable buttons
-               CardLayout cl = (CardLayout) _cards.getLayout();
-               cl.first(_cards);
-               _nextButton.setEnabled(true);
-               _backButton.setEnabled(false);
-       }
-
-
-       /**
-        * Start the save process by choosing the file to save to
-        * @return true if successful or cancelled, false if failed
-        */
-       private boolean saveToFile()
-       {
-               if (!_pointTypeSelector.getAnythingSelected()) {
-                       JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("dialog.save.notypesselected"),
-                               I18nManager.getText("dialog.saveoptions.title"), JOptionPane.WARNING_MESSAGE);
-                       return false;
-               }
-               if (_fileChooser == null)
-               {
-                       _fileChooser = new JFileChooser();
-                       _fileChooser.setDialogType(JFileChooser.SAVE_DIALOG);
-                       _fileChooser.addChoosableFileFilter(new GenericFileFilter("filetype.txt", new String[] {"txt", "text"}));
-                       _fileChooser.setAcceptAllFileFilterUsed(true);
-                       // start from directory in config which should be set
-                       String configDir = Config.getConfigString(Config.KEY_TRACK_DIR);
-                       if (configDir == null) {configDir = Config.getConfigString(Config.KEY_PHOTO_DIR);}
-                       if (configDir != null) {_fileChooser.setCurrentDirectory(new File(configDir));}
-               }
-               if (_fileChooser.showSaveDialog(_parentFrame) == JFileChooser.APPROVE_OPTION)
-               {
-                       return saveToFile(_fileChooser.getSelectedFile());
-               }
-               return true; // cancelled
-       }
-
-
-       /**
-        * Save the track to the specified file using the chosen options
-        * @param inSaveFile file to save to
-        * @return true if save successful, false if failed
-        */
-       private boolean saveToFile(File inSaveFile)
-       {
-               // TODO: Shorten method
-               FileWriter writer = null;
-               final String lineSeparator = System.getProperty("line.separator");
-               boolean saveOK = true;
-               // Get coordinate format and altitude format
-               int coordFormat = Coordinate.FORMAT_NONE;
-               for (int i=0; i<_coordUnitsRadios.length; i++)
-                       if (_coordUnitsRadios[i].isSelected())
-                               coordFormat = FORMAT_COORDS[i];
-               Unit altitudeUnit = null;
-               for (int i=0; i<_altitudeUnitsRadios.length; i++)
-               {
-                       if (_altitudeUnitsRadios[i].isSelected()) {
-                               altitudeUnit = UNIT_ALTS[i];
-                       }
-               }
-               // Get timestamp format
-               Timestamp.Format timestampFormat = Timestamp.Format.ORIGINAL;
-               for (int i=0; i<_timestampUnitsRadios.length; i++)
-               {
-                       if (_timestampUnitsRadios[i].isSelected()) {
-                               timestampFormat = FORMAT_TIMES[i];
-                       }
-               }
-
-               // Correct chosen filename if necessary
-               final File saveFile = (isFilenameOk(inSaveFile)?inSaveFile:new File(inSaveFile.getAbsolutePath() + ".txt"));
-
-               // Check if file exists, and confirm overwrite if necessary
-               Object[] buttonTexts = {I18nManager.getText("button.overwrite"), I18nManager.getText("button.cancel")};
-               if (!saveFile.exists() || JOptionPane.showOptionDialog(_parentFrame,
-                               I18nManager.getText("dialog.save.overwrite.text"),
-                               I18nManager.getText("dialog.save.overwrite.title"), JOptionPane.YES_NO_OPTION,
-                               JOptionPane.WARNING_MESSAGE, null, buttonTexts, buttonTexts[1])
-                       == JOptionPane.YES_OPTION)
-               {
-                       try
-                       {
-                               // Create output file
-                               writer = new FileWriter(saveFile);
-                               // Determine delimiter character to use
-                               final char delimiter = getDelimiter();
-                               FieldInfo info = null;
-
-                               StringBuffer buffer = null;
-                               int numFields = _model.getRowCount();
-                               boolean firstField = true;
-                               // Write header row if required
-                               if (_headerRowCheckbox.isSelected())
-                               {
-                                       buffer = new StringBuffer();
-                                       for (int f=0; f<numFields; f++)
-                                       {
-                                               info = _model.getFieldInfo(f);
-                                               if (info.isSelected())
-                                               {
-                                                       // output field separator
-                                                       if (!firstField) {
-                                                               buffer.append(delimiter);
-                                                       }
-                                                       buffer.append(info.getField().getName());
-                                                       firstField = false;
-                                               }
-                                       }
-                                       writer.write(buffer.toString());
-                                       writer.write(lineSeparator);
-                               }
-
-                               // Examine selection
-                               int selStart = -1, selEnd = -1;
-                               if (_pointTypeSelector.getJustSelection()) {
-                                       selStart = _app.getTrackInfo().getSelection().getStart();
-                                       selEnd = _app.getTrackInfo().getSelection().getEnd();
-                               }
-                               // Loop over points outputting each in turn to buffer
-                               Track track = _app.getTrackInfo().getTrack();
-                               final int numPoints = track.getNumPoints();
-                               int numSaved = 0;
-                               for (int p=0; p<numPoints; p++)
-                               {
-                                       DataPoint point = track.getPoint(p);
-                                       boolean savePoint = ((point.isWaypoint() && _pointTypeSelector.getWaypointsSelected())
-                                               || (!point.isWaypoint() && !point.hasMedia() && _pointTypeSelector.getTrackpointsSelected())
-                                               || (!point.isWaypoint() && point.getPhoto()!=null && _pointTypeSelector.getPhotopointsSelected())
-                                               || (!point.isWaypoint() && point.getAudio()!=null && _pointTypeSelector.getAudiopointsSelected()))
-                                               && (!_pointTypeSelector.getJustSelection() || (p>=selStart && p<=selEnd));
-                                       if (!savePoint) {continue;}
-                                       numSaved++;
-                                       firstField = true;
-                                       buffer = new StringBuffer();
-                                       for (int f=0; f<numFields; f++)
-                                       {
-                                               info = _model.getFieldInfo(f);
-                                               if (info.isSelected())
-                                               {
-                                                       // output field separator
-                                                       if (!firstField) {
-                                                               buffer.append(delimiter);
-                                                       }
-                                                       saveField(buffer, point, info.getField(), coordFormat, altitudeUnit, timestampFormat);
-                                                       firstField = false;
-                                               }
-                                       }
-                                       // Output to file
-                                       writer.write(buffer.toString());
-                                       writer.write(lineSeparator);
-                               }
-                               // Store directory in config for later
-                               Config.setConfigString(Config.KEY_TRACK_DIR, saveFile.getParentFile().getAbsolutePath());
-                               // Add to recent file list
-                               Config.getRecentFileList().addFile(new RecentFile(inSaveFile, true));
-                               // Save successful
-                               UpdateMessageBroker.informSubscribers();
-                               UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.save.ok1")
-                                        + " " + numSaved + " " + I18nManager.getText("confirm.save.ok2")
-                                        + " " + saveFile.getAbsolutePath());
-                               _app.informDataSaved();
-                       }
-                       catch (IOException ioe)
-                       {
-                               saveOK = false;
-                               _app.showErrorMessageNoLookup("error.save.dialogtitle",
-                                       I18nManager.getText("error.save.failed") + " : " + ioe.getMessage());
-                       }
-                       finally
-                       {
-                               // try to close file if it's open
-                               try {
-                                       writer.close();
-                               }
-                               catch (Exception e) {}
-                       }
-               }
-               else
-               {
-                       // Overwrite file confirm cancelled
-                       saveOK = false;
-               }
-               return saveOK;
-       }
-
-
-       /**
-        * Format the given field and append to the given buffer for saving
-        * @param inBuffer buffer to append to
-        * @param inPoint point object
-        * @param inField field object
-        * @param inCoordFormat coordinate format
-        * @param inAltitudeUnit altitude unit
-        * @param inTimestampFormat timestamp format
-        */
-       private void saveField(StringBuffer inBuffer, DataPoint inPoint, Field inField,
-               int inCoordFormat, Unit inAltitudeUnit, Timestamp.Format inTimestampFormat)
-       {
-               // Output field according to type
-               if (inField == Field.LATITUDE)
-               {
-                       inBuffer.append(inPoint.getLatitude().output(inCoordFormat));
-               }
-               else if (inField == Field.LONGITUDE)
-               {
-                       inBuffer.append(inPoint.getLongitude().output(inCoordFormat));
-               }
-               else if (inField == Field.ALTITUDE)
-               {
-                       try
-                       {
-                               inBuffer.append(inPoint.getAltitude().getStringValue(inAltitudeUnit));
-                       }
-                       catch (NullPointerException npe) {}
-               }
-               else if (inField == Field.TIMESTAMP)
-               {
-                       if (inPoint.hasTimestamp())
-                       {
-                               // format value accordingly
-                               inBuffer.append(inPoint.getTimestamp().getText(inTimestampFormat, null));
-                       }
-               }
-               else if (inField == Field.MEDIA_FILENAME)
-               {
-                       if (inPoint.hasMedia())
-                       {
-                               inBuffer.append(inPoint.getMediaName());
-                       }
-               }
-               else
-               {
-                       String value = inPoint.getFieldValue(inField);
-                       if (value != null)
-                       {
-                               inBuffer.append(value);
-                       }
-               }
-       }
-
-
-       /**
-        * @return the selected delimiter character
-        */
-       private char getDelimiter()
-       {
-               // Check the preset 4 delimiters
-               final char[] delimiters = {',', '\t', ';', ' '};
-               for (int i=0; i<4; i++)
-               {
-                       if (_delimiterRadios[i].isSelected())
-                       {
-                               return delimiters[i];
-                       }
-               }
-               // Wasn't any of those so must be 'other'
-               return _otherDelimiterText.getText().charAt(0);
-       }
-
-
-       /**
-        * Check the selected filename to see if it is acceptable
-        * @param inFile chosen file to save
-        * @return true if filename is ok
-        */
-       private static boolean isFilenameOk(File inFile)
-       {
-               String filename = inFile.getName().toLowerCase();
-               return (filename.length() <4 || (!filename.endsWith(".gpx")
-                       && !filename.endsWith(".kml") && !filename.endsWith(".kmz") && !filename.endsWith(".zip")));
-       }
-}