X-Git-Url: https://gitweb.fperrin.net/?a=blobdiff_plain;f=tim%2Fprune%2Fload%2FFileLoader.java;h=52bdef232942f0c5290d2c8160dccba45ce0ef92;hb=92dad5df664287acb51728e9ea599f150765d34a;hp=c7126f584ecfcb04589671ba0238a33457d48167;hpb=312fec956e43f5d0a38617da5d0add9c62563e2c;p=GpsPrune.git diff --git a/tim/prune/load/FileLoader.java b/tim/prune/load/FileLoader.java index c7126f5..52bdef2 100644 --- a/tim/prune/load/FileLoader.java +++ b/tim/prune/load/FileLoader.java @@ -1,91 +1,34 @@ package tim.prune.load; -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 javax.swing.*; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; -import javax.swing.table.TableCellEditor; - import java.io.File; +import java.util.ArrayList; +import java.util.TreeSet; + +import javax.swing.JFileChooser; +import javax.swing.JFrame; import tim.prune.App; -import tim.prune.I18nManager; -import tim.prune.data.Altitude; -import tim.prune.data.Field; +import tim.prune.config.Config; +import tim.prune.data.Photo; +import tim.prune.load.xml.GzipFileLoader; +import tim.prune.load.xml.XmlFileLoader; +import tim.prune.load.xml.ZipFileLoader; /** - * Special class to handle file loading including GUI options, - * and conversion to a Track object + * Generic FileLoader class to select a file + * and pass handling on to appropriate loader */ public class FileLoader { - private File _file = null; - private App _app = null; - private JFrame _parentFrame = null; - private JDialog _dialog = null; - private JPanel _cardPanel = null; - private CardLayout _layout = null; - private JButton _backButton = null, _nextButton = null; - private JButton _finishButton = null; - private JButton _moveUpButton = null, _moveDownButton = null; - private JRadioButton[] _delimiterRadios = null; - private JTextField _otherDelimiterText = null; - private JLabel _statusLabel = null; - private DelimiterInfo[] _delimiterInfos = null; + private App _app; private JFileChooser _fileChooser = null; - private FileCacher _fileCacher = null; - private JList _snippetBox = null; - private FileExtractTableModel _fileExtractTableModel = null; - private JTable _fieldTable; - private FieldSelectionTableModel _fieldTableModel = null; - private JComboBox _unitsDropDown = null; - private int _selectedField = -1; - private char _currentDelimiter = ','; - - // previously selected values - private char _lastUsedDelimiter = ','; - private int _lastNumFields = -1; - private Field[] _lastSelectedFields = null; - private int _lastAltitudeFormat = Altitude.FORMAT_NONE; - - // constants - private static final int SNIPPET_SIZE = 6; - private static final int MAX_SNIPPET_WIDTH = 80; - private static final char[] DELIMITERS = {',', '\t', ';', ' '}; - - - /** - * Inner class to listen for delimiter change operations - */ - private class DelimListener implements ActionListener, DocumentListener - { - public void actionPerformed(ActionEvent e) - { - informDelimiterSelected(); - } - public void changedUpdate(DocumentEvent e) - { - informDelimiterSelected(); - } - public void insertUpdate(DocumentEvent e) - { - informDelimiterSelected(); - } - public void removeUpdate(DocumentEvent e) - { - informDelimiterSelected(); - } - } + private JFrame _parentFrame; + private TextFileLoader _textFileLoader = null; + private NmeaFileLoader _nmeaFileLoader = null; + private XmlFileLoader _xmlFileLoader = null; + private ZipFileLoader _zipFileLoader = null; + private GzipFileLoader _gzipFileLoader = null; /** @@ -97,6 +40,11 @@ public class FileLoader { _app = inApp; _parentFrame = inParentFrame; + _textFileLoader = new TextFileLoader(inApp, inParentFrame); + _nmeaFileLoader = new NmeaFileLoader(inApp); + _xmlFileLoader = new XmlFileLoader(inApp); + _zipFileLoader = new ZipFileLoader(inApp, _xmlFileLoader); + _gzipFileLoader = new GzipFileLoader(inApp, _xmlFileLoader); } @@ -106,458 +54,106 @@ public class FileLoader */ public void openFile() { + // Construct file chooser if necessary if (_fileChooser == null) + { _fileChooser = new JFileChooser(); + _fileChooser.addChoosableFileFilter(new GenericFileFilter("filetype.txt", new String[] {"txt", "text"})); + _fileChooser.addChoosableFileFilter(new GenericFileFilter("filetype.gpx", new String[] {"gpx"})); + _fileChooser.addChoosableFileFilter(new GenericFileFilter("filetype.kml", new String[] {"kml"})); + _fileChooser.addChoosableFileFilter(new GenericFileFilter("filetype.kmz", new String[] {"kmz"})); + _fileChooser.setAcceptAllFileFilterUsed(true); + _fileChooser.setFileFilter(_fileChooser.getAcceptAllFileFilter()); // For some reason seems necessary + // start from directory in config if already set (by load jpegs) + 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));} + _fileChooser.setMultiSelectionEnabled(true); // Allow multiple selections + } + // Show the open dialog if (_fileChooser.showOpenDialog(_parentFrame) == JFileChooser.APPROVE_OPTION) { - _file = _fileChooser.getSelectedFile(); - if (preCheckFile(_file)) + File[] files = _fileChooser.getSelectedFiles(); + // Loop through files looking for files which exist and are readable + ArrayList dataFiles = new ArrayList(); + if (files != null) { - _dialog = new JDialog(_parentFrame, I18nManager.getText("dialog.openoptions.title"), true); - _dialog.setLocationRelativeTo(_parentFrame); - _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); - _dialog.getContentPane().add(makeDialogComponents()); - - // select best separator according to row counts (more is better) - int bestDelim = getBestOption(_delimiterInfos[0].getNumWinningRecords(), - _delimiterInfos[1].getNumWinningRecords(), _delimiterInfos[2].getNumWinningRecords(), - _delimiterInfos[3].getNumWinningRecords()); - if (bestDelim >= 0) - _delimiterRadios[bestDelim].setSelected(true); - else - _delimiterRadios[_delimiterRadios.length-1].setSelected(true); - informDelimiterSelected(); - _dialog.pack(); - _dialog.show(); + for (int i=0; i 0) { + _app.loadDataFiles(dataFiles); } else { - JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("error.load.noread"), - I18nManager.getText("error.load.dialogtitle"), JOptionPane.ERROR_MESSAGE); + // couldn't find any files to load - show error message + _app.showErrorMessage("error.load.dialogtitle", "error.load.noread"); } } } - /** - * Check the given file for readability and funny characters, - * and count the fields for the various separators - * @param inFile file to check + * Open the selected input file + * @param inFile file to open */ - private boolean preCheckFile(File inFile) + public void openFile(File inFile) { - // Check file exists and is readable - if (inFile == null || !inFile.exists() || !inFile.canRead()) - { - return false; + // Store directory in config for later + File parent = inFile.getParentFile(); + if (parent != null) { + Config.setConfigString(Config.KEY_TRACK_DIR, parent.getAbsolutePath()); } - // Use a FileCacher to read the file into an array - _fileCacher = new FileCacher(inFile); - - // Check each line of the file - String[] fileContents = _fileCacher.getContents(); - boolean fileOK = true; - _delimiterInfos = new DelimiterInfo[5]; - for (int i=0; i<4; i++) _delimiterInfos[i] = new DelimiterInfo(DELIMITERS[i]); - - String currLine = null; - String[] splitFields = null; - int commaFields = 0, semicolonFields = 0, tabFields = 0, spaceFields = 0; - for (int lineNum=0; lineNum= 0) {fileOK = false;} - // check for commas - splitFields = currLine.split(","); - commaFields = splitFields.length; - if (commaFields > 1) _delimiterInfos[0].incrementNumRecords(); - _delimiterInfos[0].updateMaxFields(commaFields); - // check for tabs - splitFields = currLine.split("\t"); - tabFields = splitFields.length; - if (tabFields > 1) _delimiterInfos[1].incrementNumRecords(); - _delimiterInfos[1].updateMaxFields(tabFields); - // check for semicolons - splitFields = currLine.split(";"); - semicolonFields = splitFields.length; - if (semicolonFields > 1) _delimiterInfos[2].incrementNumRecords(); - _delimiterInfos[2].updateMaxFields(semicolonFields); - // check for spaces - splitFields = currLine.split(" "); - spaceFields = splitFields.length; - if (spaceFields > 1) _delimiterInfos[3].incrementNumRecords(); - _delimiterInfos[3].updateMaxFields(spaceFields); - // increment counters - int bestScorer = getBestOption(commaFields, tabFields, semicolonFields, spaceFields); - if (bestScorer >= 0) - _delimiterInfos[bestScorer].incrementNumWinningRecords(); + // Check file type to see if it's xml or just normal text + String fileExtension = inFile.getName().toLowerCase(); + if (fileExtension.length() > 4) { + fileExtension = fileExtension.substring(fileExtension.length() - 4); } - return fileOK; - } - - - /** - * Get the index of the best one in the list - * @return the index of the maximum of the four given values - */ - private static int getBestOption(int inOpt0, int inOpt1, int inOpt2, int inOpt3) - { - int bestIndex = -1; - int maxScore = 1; - if (inOpt0 > maxScore) {bestIndex = 0; maxScore = inOpt0;} - if (inOpt1 > maxScore) {bestIndex = 1; maxScore = inOpt1;} - if (inOpt2 > maxScore) {bestIndex = 2; maxScore = inOpt2;} - if (inOpt3 > maxScore) {bestIndex = 3; maxScore = inOpt3;} - return bestIndex; - } - - - /** - * Make the components for the open options dialog - * @return Component for all options - */ - private Component makeDialogComponents() - { - JPanel wholePanel = new JPanel(); - wholePanel.setLayout(new BorderLayout()); - - // add buttons to south - JPanel buttonPanel = new JPanel(); - buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER)); - _backButton = new JButton(I18nManager.getText("button.back")); - _backButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) - { - _layout.previous(_cardPanel); - _backButton.setEnabled(false); - _nextButton.setEnabled(true); - _finishButton.setEnabled(false); - } - }); - _backButton.setEnabled(false); - buttonPanel.add(_backButton); - _nextButton = new JButton(I18nManager.getText("button.next")); - _nextButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) - { - prepareSecondPanel(); - _layout.next(_cardPanel); - _nextButton.setEnabled(false); - _backButton.setEnabled(true); - _finishButton.setEnabled(true); - } - }); - buttonPanel.add(_nextButton); - _finishButton = new JButton(I18nManager.getText("button.finish")); - _finishButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) - { - finished(); - } - }); - _finishButton.setEnabled(false); - buttonPanel.add(_finishButton); - JButton cancelButton = new JButton(I18nManager.getText("button.cancel")); - cancelButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) - { - _dialog.dispose(); - } - }); - buttonPanel.add(cancelButton); - wholePanel.add(buttonPanel, BorderLayout.SOUTH); - - // Make the two cards, for delimiter and fields - _cardPanel = new JPanel(); - _layout = new CardLayout(); - _cardPanel.setLayout(_layout); - JPanel firstCard = new JPanel(); - firstCard.setLayout(new BorderLayout()); - - JPanel delimsPanel = new JPanel(); - delimsPanel.setLayout(new GridLayout(0, 2)); - delimsPanel.add(new JLabel(I18nManager.getText("dialog.delimiter.label"))); - delimsPanel.add(new JLabel("")); // blank label to go to next grid row - // 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(); - DelimListener delimListener = new DelimListener(); - for (int i=0; i<_delimiterRadios.length; i++) - { - delimGroup.add(_delimiterRadios[i]); - _delimiterRadios[i].addActionListener(delimListener); - } - _otherDelimiterText.getDocument().addDocumentListener(delimListener); - delimsPanel.add(new JLabel("")); - delimsPanel.add(otherPanel); - _statusLabel = new JLabel(""); - delimsPanel.add(_statusLabel); - firstCard.add(delimsPanel, BorderLayout.SOUTH); - // load snippet to show first few lines - _snippetBox = new JList(_fileCacher.getSnippet(SNIPPET_SIZE, MAX_SNIPPET_WIDTH)); - _snippetBox.setEnabled(false); - firstCard.add(makeLabelledPanel("dialog.openoptions.filesnippet", _snippetBox), BorderLayout.CENTER); - - // Second screen, for field order selection - JPanel secondCard = new JPanel(); - secondCard.setLayout(new BorderLayout()); - // table for file contents - _fileExtractTableModel = new FileExtractTableModel(); - JTable extractTable = new JTable(_fileExtractTableModel); - JScrollPane tableScrollPane = new JScrollPane(extractTable); - extractTable.setPreferredScrollableViewportSize(new Dimension(350, 80)); - extractTable.getTableHeader().setReorderingAllowed(false); - secondCard.add(makeLabelledPanel("dialog.openoptions.tabledesc", tableScrollPane), BorderLayout.NORTH); - JPanel innerPanel2 = new JPanel(); - innerPanel2.setLayout(new BorderLayout()); - _fieldTable = new JTable(new FieldSelectionTableModel()); - _fieldTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - // add listener for selected table row - _fieldTable.getSelectionModel().addListSelectionListener( - new ListSelectionListener() { - public void valueChanged(ListSelectionEvent e) { - ListSelectionModel lsm = (ListSelectionModel) e.getSource(); - if (lsm.isSelectionEmpty()) { - //no rows are selected - selectField(-1); - } else { - selectField(lsm.getMinSelectionIndex()); - } - } - }); - JPanel tablePanel = new JPanel(); - tablePanel.setLayout(new BorderLayout()); - tablePanel.add(_fieldTable.getTableHeader(), BorderLayout.NORTH); - tablePanel.add(_fieldTable, BorderLayout.CENTER); - innerPanel2.add(tablePanel, BorderLayout.CENTER); - - JPanel innerPanel3 = new JPanel(); - innerPanel3.setLayout(new BoxLayout(innerPanel3, BoxLayout.Y_AXIS)); - _moveUpButton = new JButton(I18nManager.getText("button.moveup")); - _moveUpButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) - { - int currRow = _fieldTable.getSelectedRow(); - closeTableComboBox(currRow); - _fieldTableModel.moveUp(currRow); - _fieldTable.setRowSelectionInterval(currRow-1, currRow-1); - } - }); - innerPanel3.add(_moveUpButton); - _moveDownButton = new JButton(I18nManager.getText("button.movedown")); - _moveDownButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) - { - int currRow = _fieldTable.getSelectedRow(); - closeTableComboBox(currRow); - _fieldTableModel.moveDown(currRow); - _fieldTable.setRowSelectionInterval(currRow+1, currRow+1); - } - }); - innerPanel3.add(_moveDownButton); - innerPanel3.add(Box.createVerticalStrut(70)); - - innerPanel2.add(innerPanel3, BorderLayout.EAST); - secondCard.add(innerPanel2, BorderLayout.CENTER); - JPanel altUnitsPanel = new JPanel(); - altUnitsPanel.setLayout(new FlowLayout(FlowLayout.LEFT)); - altUnitsPanel.add(new JLabel(I18nManager.getText("dialog.openoptions.altitudeunits"))); - String[] units = {I18nManager.getText("units.metres"), I18nManager.getText("units.feet")}; - _unitsDropDown = new JComboBox(units); - altUnitsPanel.add(_unitsDropDown); - secondCard.add(altUnitsPanel, BorderLayout.SOUTH); - _cardPanel.add(firstCard, "card1"); - _cardPanel.add(secondCard, "card2"); - - wholePanel.add(_cardPanel, BorderLayout.CENTER); - return wholePanel; - } - - - /** - * Close the combo box on the selected row of the field table - * @param inRow currently selected row number - */ - private void closeTableComboBox(int inRow) - { - TableCellEditor editor = _fieldTable.getCellEditor(inRow, 1); - if (editor != null) + if (fileExtension.equals(".kml") || fileExtension.equals(".gpx") + || fileExtension.equals(".xml")) { - editor.stopCellEditing(); + // Use xml loader for kml, gpx and xml filenames + _xmlFileLoader.openFile(inFile); } - } - - - /** - * change the status based on selection of a delimiter - */ - protected void informDelimiterSelected() - { - for (int i=0; i<(_delimiterRadios.length-1); i++) + else if (fileExtension.equals(".kmz") || fileExtension.equals(".zip")) { - if (_delimiterRadios[i].isSelected()) - { - int numRecords = _delimiterInfos[i].getNumRecords(); - if (numRecords == 0) - { - _statusLabel.setText(I18nManager.getText("dialog.openoptions.deliminfo.norecords")); - } - else - { - _statusLabel.setText("" + numRecords + " " + I18nManager.getText("dialog.openoptions.deliminfo.records") - + _delimiterInfos[i].getMaxFields() + " " + I18nManager.getText("dialog.openoptions.deliminfo.fields")); - } - } + // Use zip loader for zipped kml (or zipped gpx) + _zipFileLoader.openFile(inFile); } - if (_delimiterRadios[_delimiterRadios.length-1].isSelected()) + else if (fileExtension.endsWith(".gz") || fileExtension.equals("gzip")) { - _statusLabel.setText(""); + // Use gzip loader for gzipped xml + _gzipFileLoader.openFile(inFile); } - // enable/disable next button - _nextButton.setEnabled(_delimiterRadios[4].isSelected() == false - || _otherDelimiterText.getText().length() == 1); - } - - - /** - * Get the delimiter info from the first step - * @return delimiter information object for the selected delimiter - */ - public DelimiterInfo getSelectedDelimiterInfo() - { - for (int i=0; i<4; i++) - if (_delimiterRadios[i].isSelected()) return _delimiterInfos[i]; - // must be "other" - build info if necessary - if (_delimiterInfos[4] == null) - _delimiterInfos[4] = new DelimiterInfo(_otherDelimiterText.getText().charAt(0)); - return _delimiterInfos[4]; - } - - - /** - * Use the delimiter selected to determine the fields in the file - * and prepare the second panel accordingly - */ - private void prepareSecondPanel() - { - DelimiterInfo info = getSelectedDelimiterInfo(); - FileSplitter splitter = new FileSplitter(_fileCacher); - // Check info makes sense - num fields > 0, num records > 0 - // set "Finished" button to disabled if not ok - // TODO: Work out if there are header rows or not, save? - // Try to match header rows with fields - // Try to match data with fields - // Add data to GUI elements - Object[][] tableData = splitter.splitFieldData(info.getDelimiter()); - // possible to ignore blank columns here - _currentDelimiter = info.getDelimiter(); - _fileExtractTableModel.updateData(tableData); - _fieldTableModel = new FieldSelectionTableModel(); - - // Check number of fields and use last ones if count matches - Field[] startFieldArray = null; - if (_lastSelectedFields != null && splitter.getNumColumns() == _lastSelectedFields.length) - startFieldArray = _lastSelectedFields; - else - startFieldArray = splitter.makeDefaultFields(); - _fieldTableModel.updateData(startFieldArray); - _fieldTable.setModel(_fieldTableModel); - // add dropdowns to second column - JComboBox fieldTypesBox = new JComboBox(); - for (int i=0; i photoSet = new TreeSet(new MediaSorter()); + photoSet.add(photo); + _app.informPhotosLoaded(photoSet); + _app.informNoDataLoaded(); // To trigger load of next file if any } - _lastAltitudeFormat = altitudeFormat; - // give data to App - _app.informDataLoaded(_fieldTableModel.getFieldArray(), - _fileExtractTableModel.getData(), altitudeFormat, - _file.getName()); - // clear up file cacher - _fileCacher.clear(); - // dispose of dialog - _dialog.dispose(); - } - - - /** - * Make a panel with a label and a component - * @param inLabelKey label key to use - * @param inComponent component for main area of panel - * @return labelled Panel - */ - private static JPanel makeLabelledPanel(String inLabelKey, JComponent inComponent) - { - JPanel panel = new JPanel(); - panel.setLayout(new BorderLayout()); - panel.add(new JLabel(I18nManager.getText(inLabelKey)), BorderLayout.NORTH); - panel.add(inComponent, BorderLayout.CENTER); - return panel; - } - - - /** - * An entry in the field list has been selected - * @param inFieldNum index of field, starting with 0 - */ - private void selectField(int inFieldNum) - { - if (inFieldNum == -1 || inFieldNum != _selectedField) + else { - _selectedField = inFieldNum; - _moveUpButton.setEnabled(inFieldNum > 0); - _moveDownButton.setEnabled(inFieldNum >= 0 - && inFieldNum < (_fieldTableModel.getRowCount()-1)); + // Use text loader for everything else + _textFileLoader.openFile(inFile); } } - /** - * @return the last delimiter character used for a load + * @return the last delimiter character used for a text file load */ public char getLastUsedDelimiter() { - return _lastUsedDelimiter; + return _textFileLoader.getLastUsedDelimiter(); } }