1 package tim.prune.load;
3 import java.awt.BorderLayout;
4 import java.awt.Component;
5 import java.awt.Dimension;
6 import java.awt.FlowLayout;
7 import java.awt.GridLayout;
8 import java.awt.event.ActionEvent;
9 import java.awt.event.ActionListener;
10 import java.awt.event.WindowAdapter;
11 import java.awt.event.WindowEvent;
14 import javax.swing.event.DocumentEvent;
15 import javax.swing.event.DocumentListener;
16 import javax.swing.event.ListSelectionEvent;
17 import javax.swing.event.ListSelectionListener;
18 import javax.swing.table.TableCellEditor;
23 import tim.prune.I18nManager;
24 import tim.prune.data.Field;
25 import tim.prune.data.PointCreateOptions;
26 import tim.prune.data.SourceInfo;
27 import tim.prune.data.Unit;
28 import tim.prune.data.UnitSetLibrary;
29 import tim.prune.gui.GuiGridLayout;
30 import tim.prune.gui.WizardLayout;
34 * Class to handle loading of text files including GUI options,
35 * and passing loaded data back to App object
37 public class TextFileLoader
39 private File _file = null;
40 private App _app = null;
41 private JFrame _parentFrame = null;
42 private JDialog _dialog = null;
43 private WizardLayout _wizard = null;
44 private JButton _backButton = null, _nextButton = null;
45 private JButton _finishButton = null;
46 private JButton _moveUpButton = null, _moveDownButton = null;
47 private JRadioButton[] _delimiterRadios = null;
48 private JTextField _otherDelimiterText = null;
49 private JLabel _statusLabel = null;
50 private DelimiterInfo[] _delimiterInfos = null;
51 private ContentCacher _contentCacher = null;
52 private JList<String> _snippetBox = null;
53 private FileExtractTableModel _fileExtractTableModel = null;
54 private JTable _fieldTable;
55 private FieldSelectionTableModel _fieldTableModel = null;
56 private JComboBox<String> _altitudeUnitsDropdown = null;
57 private JComboBox<String> _hSpeedUnitsDropdown = null;
58 private JComboBox<String> _vSpeedUnitsDropdown = null;
59 private JRadioButton _vSpeedUpwardsRadio = null;
60 private ComponentHider _componentHider = null;
61 private int _selectedField = -1;
62 private char _currentDelimiter = ',';
64 // previously selected values
65 private char _lastUsedDelimiter = ',';
66 private Field[] _lastSelectedFields = null;
67 private Unit _lastAltitudeUnit = null;
70 private static final int SNIPPET_SIZE = 6;
71 private static final int MAX_SNIPPET_WIDTH = 80;
72 private static final char[] DELIMITERS = {',', '\t', ';', ' '};
76 * Inner class to listen for delimiter change operations
78 private class DelimListener implements ActionListener, DocumentListener
80 public void actionPerformed(ActionEvent e)
82 informDelimiterSelected();
84 public void changedUpdate(DocumentEvent e)
86 informDelimiterSelected();
88 public void insertUpdate(DocumentEvent e)
90 informDelimiterSelected();
92 public void removeUpdate(DocumentEvent e)
94 informDelimiterSelected();
101 * @param inApp Application object to inform of track load
102 * @param inParentFrame parent frame to reference for dialogs
104 public TextFileLoader(App inApp, JFrame inParentFrame)
107 _parentFrame = inParentFrame;
112 * Open the selected file and show the GUI dialog to select load options
113 * @param inFile file to open
115 public void openFile(File inFile)
118 if (preCheckFile(_file))
124 // Didn't pass pre-check
125 _app.showErrorMessageNoLookup("error.load.dialogtitle",
126 I18nManager.getText("error.load.noread") + ": " + inFile.getName());
127 _app.informNoDataLoaded();
133 * Checks passed, so now build and show the dialog
135 private void showDialog()
137 _dialog = new JDialog(_parentFrame, I18nManager.getText("dialog.openoptions.title"), true);
138 _dialog.setLocationRelativeTo(_parentFrame);
139 _dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
140 // add closing listener
141 _dialog.addWindowListener(new WindowAdapter() {
142 public void windowClosing(WindowEvent e) {
144 _app.informNoDataLoaded();
147 _dialog.getContentPane().add(makeDialogComponents());
149 // select best separator according to row counts (more is better)
150 int bestDelim = getBestOption(_delimiterInfos[0].getNumWinningRecords(),
151 _delimiterInfos[1].getNumWinningRecords(), _delimiterInfos[2].getNumWinningRecords(),
152 _delimiterInfos[3].getNumWinningRecords());
154 _delimiterRadios[bestDelim].setSelected(true);
156 _delimiterRadios[_delimiterRadios.length-1].setSelected(true);
157 informDelimiterSelected();
159 _dialog.setVisible(true);
164 * Check the given file for validity
165 * @param inFile file to check
167 private boolean preCheckFile(File inFile)
169 // Check file exists and is readable
170 if (inFile == null || !inFile.exists() || !inFile.canRead())
174 // Use a FileCacher to read the file into an array
175 _contentCacher = new FileCacher(inFile);
177 return preCheckContents();
181 * Check the contents for readability and funny characters,
182 * and count the fields for the various separators
184 private boolean preCheckContents()
186 // Check each line of the file
187 String[] contents = _contentCacher.getContents();
188 if (contents == null) {
189 return false; // nothing cached, might be binary
191 boolean fileOK = true;
192 _delimiterInfos = new DelimiterInfo[5];
193 for (int i=0; i<4; i++) _delimiterInfos[i] = new DelimiterInfo(DELIMITERS[i]);
195 String currLine = null;
196 String[] splitFields = null;
197 int commaFields = 0, semicolonFields = 0, tabFields = 0, spaceFields = 0;
198 for (int lineNum=0; lineNum<contents.length && fileOK; lineNum++)
200 currLine = contents[lineNum];
201 // check for invalid characters
202 if (currLine.indexOf('\0') >= 0) {fileOK = false;}
204 splitFields = currLine.split(",");
205 commaFields = splitFields.length;
206 if (commaFields > 1) _delimiterInfos[0].incrementNumRecords();
207 _delimiterInfos[0].updateMaxFields(commaFields);
209 splitFields = currLine.split("\t");
210 tabFields = splitFields.length;
211 if (tabFields > 1) _delimiterInfos[1].incrementNumRecords();
212 _delimiterInfos[1].updateMaxFields(tabFields);
213 // check for semicolons
214 splitFields = currLine.split(";");
215 semicolonFields = splitFields.length;
216 if (semicolonFields > 1) _delimiterInfos[2].incrementNumRecords();
217 _delimiterInfos[2].updateMaxFields(semicolonFields);
219 splitFields = currLine.split(" ");
220 spaceFields = splitFields.length;
221 if (spaceFields > 1) _delimiterInfos[3].incrementNumRecords();
222 _delimiterInfos[3].updateMaxFields(spaceFields);
223 // increment counters
224 int bestScorer = getBestOption(commaFields, tabFields, semicolonFields, spaceFields);
226 _delimiterInfos[bestScorer].incrementNumWinningRecords();
232 * @param inText text to load (as if it came from a file)
234 public void loadText(String inText)
237 if (preCheckText(inText))
243 // Didn't pass pre-check
244 _app.showErrorMessage("error.load.dialogtitle", "error.load.nopointsintext");
249 * Check the given text for validity
250 * @param inText (pasted) text to check
252 private boolean preCheckText(String inText)
254 if (inText == null || inText.length() < 6)
258 // Use a cacher to split the text into an array
259 _contentCacher = new TextCacher(inText);
261 return preCheckContents();
266 * Get the index of the best one in the list
267 * @return the index of the maximum of the four given values
269 private static int getBestOption(int inOpt0, int inOpt1, int inOpt2, int inOpt3)
273 if (inOpt0 > maxScore) {bestIndex = 0; maxScore = inOpt0;}
274 if (inOpt1 > maxScore) {bestIndex = 1; maxScore = inOpt1;}
275 if (inOpt2 > maxScore) {bestIndex = 2; maxScore = inOpt2;}
276 if (inOpt3 > maxScore) {bestIndex = 3; maxScore = inOpt3;}
282 * Make the components for the open options dialog
283 * @return Component for all options
285 private Component makeDialogComponents()
287 JPanel wholePanel = new JPanel();
288 wholePanel.setLayout(new BorderLayout());
290 // add buttons to south
291 JPanel buttonPanel = new JPanel();
292 buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
293 _backButton = new JButton(I18nManager.getText("button.back"));
294 _backButton.addActionListener(new ActionListener() {
295 public void actionPerformed(ActionEvent e)
297 _wizard.showPreviousCard();
298 _nextButton.setEnabled(!_wizard.isLastCard());
299 _backButton.setEnabled(!_wizard.isFirstCard());
300 _finishButton.setEnabled(false);
303 _backButton.setEnabled(false);
304 buttonPanel.add(_backButton);
305 _nextButton = new JButton(I18nManager.getText("button.next"));
306 _nextButton.addActionListener(new ActionListener() {
307 public void actionPerformed(ActionEvent e)
309 prepareNextPanel(); // Maybe it needs to be initialized based on previous panels
310 _wizard.showNextCard();
311 _nextButton.setEnabled(!_wizard.isLastCard() && isCurrentCardValid());
312 _backButton.setEnabled(!_wizard.isFirstCard());
313 _finishButton.setEnabled(_wizard.isLastCard() && isCurrentCardValid());
316 buttonPanel.add(_nextButton);
317 _finishButton = new JButton(I18nManager.getText("button.finish"));
318 _finishButton.addActionListener(new ActionListener() {
319 public void actionPerformed(ActionEvent e)
324 _finishButton.setEnabled(false);
325 buttonPanel.add(_finishButton);
326 JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
327 cancelButton.addActionListener(new ActionListener() {
328 public void actionPerformed(ActionEvent e)
331 _app.informNoDataLoaded();
334 buttonPanel.add(cancelButton);
335 wholePanel.add(buttonPanel, BorderLayout.SOUTH);
337 // Make the card panel in the centre
338 JPanel cardPanel = new JPanel();
339 _wizard = new WizardLayout(cardPanel);
340 JPanel firstCard = new JPanel();
341 firstCard.setLayout(new BorderLayout());
342 firstCard.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15));
344 JPanel delimsPanel = new JPanel();
345 delimsPanel.setLayout(new GridLayout(0, 2));
346 delimsPanel.add(new JLabel(I18nManager.getText("dialog.delimiter.label")));
347 delimsPanel.add(new JLabel("")); // blank label to go to next grid row
349 _delimiterRadios = new JRadioButton[5];
350 _delimiterRadios[0] = new JRadioButton(I18nManager.getText("dialog.delimiter.comma"));
351 delimsPanel.add(_delimiterRadios[0]);
352 _delimiterRadios[1] = new JRadioButton(I18nManager.getText("dialog.delimiter.tab"));
353 delimsPanel.add(_delimiterRadios[1]);
354 _delimiterRadios[2] = new JRadioButton(I18nManager.getText("dialog.delimiter.semicolon"));
355 delimsPanel.add(_delimiterRadios[2]);
356 _delimiterRadios[3] = new JRadioButton(I18nManager.getText("dialog.delimiter.space"));
357 delimsPanel.add(_delimiterRadios[3]);
358 JPanel otherPanel = new JPanel();
359 otherPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
360 _delimiterRadios[4] = new JRadioButton(I18nManager.getText("dialog.delimiter.other"));
361 otherPanel.add(_delimiterRadios[4]);
362 _otherDelimiterText = new JTextField(new OneCharDocument(), null, 2);
363 otherPanel.add(_otherDelimiterText);
364 // Group radio buttons
365 ButtonGroup delimGroup = new ButtonGroup();
366 DelimListener delimListener = new DelimListener();
367 for (int i=0; i<_delimiterRadios.length; i++)
369 delimGroup.add(_delimiterRadios[i]);
370 _delimiterRadios[i].addActionListener(delimListener);
372 _otherDelimiterText.getDocument().addDocumentListener(delimListener);
373 delimsPanel.add(new JLabel(""));
374 delimsPanel.add(otherPanel);
375 _statusLabel = new JLabel("");
376 delimsPanel.add(_statusLabel);
377 firstCard.add(delimsPanel, BorderLayout.SOUTH);
378 // load snippet to show first few lines
379 _snippetBox = new JList<String>(_contentCacher.getSnippet(SNIPPET_SIZE, MAX_SNIPPET_WIDTH));
380 _snippetBox.setEnabled(false);
381 firstCard.add(makeLabelledPanel("dialog.openoptions.filesnippet", _snippetBox), BorderLayout.CENTER);
383 // Second screen, for field order selection
384 JPanel secondCard = new JPanel();
385 secondCard.setLayout(new BorderLayout());
386 secondCard.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15));
387 // table for file contents
388 _fileExtractTableModel = new FileExtractTableModel();
389 JTable extractTable = new JTable(_fileExtractTableModel);
390 JScrollPane tableScrollPane = new JScrollPane(extractTable);
391 extractTable.setPreferredScrollableViewportSize(new Dimension(350, 80));
392 extractTable.getTableHeader().setReorderingAllowed(false);
393 secondCard.add(makeLabelledPanel("dialog.openoptions.filesnippet", tableScrollPane), BorderLayout.NORTH);
394 JPanel innerPanel2 = new JPanel();
395 innerPanel2.setLayout(new BorderLayout());
396 innerPanel2.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
398 _fieldTable = new JTable(new FieldSelectionTableModel());
399 _fieldTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
400 // add listener for selected table row
401 _fieldTable.getSelectionModel().addListSelectionListener(
402 new ListSelectionListener() {
403 public void valueChanged(ListSelectionEvent e) {
404 ListSelectionModel lsm = (ListSelectionModel) e.getSource();
405 if (lsm.isSelectionEmpty()) {
406 //no rows are selected
409 selectField(lsm.getMinSelectionIndex());
413 JScrollPane lowerTablePane = new JScrollPane(_fieldTable);
414 lowerTablePane.setPreferredSize(new Dimension(300, 100));
415 innerPanel2.add(lowerTablePane, BorderLayout.CENTER);
417 JPanel innerPanel3 = new JPanel();
418 innerPanel3.setLayout(new BoxLayout(innerPanel3, BoxLayout.Y_AXIS));
419 _moveUpButton = new JButton(I18nManager.getText("button.moveup"));
420 _moveUpButton.addActionListener(new ActionListener() {
421 public void actionPerformed(ActionEvent e)
423 int currRow = _fieldTable.getSelectedRow();
424 closeTableComboBox(currRow);
425 _fieldTableModel.moveUp(currRow);
426 _fieldTable.setRowSelectionInterval(currRow-1, currRow-1);
429 innerPanel3.add(_moveUpButton);
430 _moveDownButton = new JButton(I18nManager.getText("button.movedown"));
431 _moveDownButton.addActionListener(new ActionListener() {
432 public void actionPerformed(ActionEvent e)
434 int currRow = _fieldTable.getSelectedRow();
435 closeTableComboBox(currRow);
436 _fieldTableModel.moveDown(currRow);
437 _fieldTable.setRowSelectionInterval(currRow+1, currRow+1);
440 innerPanel3.add(_moveDownButton);
441 innerPanel3.add(Box.createVerticalStrut(60));
442 JButton guessButton = new JButton(I18nManager.getText("button.guessfields"));
443 guessButton.addActionListener(new ActionListener() {
444 public void actionPerformed(ActionEvent e)
446 _lastSelectedFields = null;
447 prepareSecondPanel();
450 innerPanel3.add(guessButton);
452 innerPanel2.add(innerPanel3, BorderLayout.EAST);
453 secondCard.add(innerPanel2, BorderLayout.CENTER);
455 // Third card, for units selection of altitude and speeds
456 JPanel thirdCard = new JPanel();
457 thirdCard.setLayout(new BorderLayout(10, 10));
458 JPanel holderPanel = new JPanel();
459 holderPanel.setLayout(new BoxLayout(holderPanel, BoxLayout.Y_AXIS));
461 JPanel altUnitsPanel = new JPanel();
462 GuiGridLayout altGrid = new GuiGridLayout(altUnitsPanel);
463 altUnitsPanel.setBorder(BorderFactory.createTitledBorder(I18nManager.getText("fieldname.altitude")));
464 JLabel altLabel = new JLabel(I18nManager.getText("dialog.openoptions.altitudeunits") + ": ");
465 altGrid.add(altLabel);
466 String[] altUnits = {I18nManager.getText("units.metres"), I18nManager.getText("units.feet")};
467 _altitudeUnitsDropdown = new JComboBox<String>(altUnits);
468 altGrid.add(_altitudeUnitsDropdown);
469 holderPanel.add(altUnitsPanel);
471 JPanel speedPanel = new JPanel();
472 GuiGridLayout speedGrid = new GuiGridLayout(speedPanel);
473 speedPanel.setBorder(BorderFactory.createTitledBorder(I18nManager.getText("fieldname.speed")));
474 JLabel speedLabel = new JLabel(I18nManager.getText("dialog.openoptions.speedunits") + ": ");
475 speedGrid.add(speedLabel);
476 _hSpeedUnitsDropdown = new JComboBox<String>();
477 for (Unit spUnit : UnitSetLibrary.ALL_SPEED_UNITS) {
478 _hSpeedUnitsDropdown.addItem(I18nManager.getText(spUnit.getNameKey()));
480 speedGrid.add(_hSpeedUnitsDropdown);
481 holderPanel.add(speedPanel);
483 JPanel vSpeedPanel = new JPanel();
484 GuiGridLayout vSpeedGrid = new GuiGridLayout(vSpeedPanel);
485 vSpeedPanel.setBorder(BorderFactory.createTitledBorder(I18nManager.getText("fieldname.verticalspeed")));
486 JLabel vSpeedLabel = new JLabel(I18nManager.getText("dialog.openoptions.vertspeedunits") + ": ");
487 vSpeedGrid.add(vSpeedLabel);
488 _vSpeedUnitsDropdown = new JComboBox<String>();
489 for (Unit spUnit : UnitSetLibrary.ALL_SPEED_UNITS) {
490 _vSpeedUnitsDropdown.addItem(I18nManager.getText(spUnit.getNameKey()));
492 vSpeedGrid.add(_vSpeedUnitsDropdown);
493 final String vSpeedLabelText = I18nManager.getText("dialog.openoptions.vspeed.intro");
494 if (!vSpeedLabelText.isEmpty()) {
495 vSpeedGrid.add(new JLabel(vSpeedLabelText));
496 vSpeedGrid.add(new JLabel(""));
498 _vSpeedUpwardsRadio = new JRadioButton(I18nManager.getText("dialog.openoptions.vspeed.positiveup"));
499 JRadioButton vSpeedDownwardsRadio = new JRadioButton(I18nManager.getText("dialog.openoptions.vspeed.positivedown"));
500 ButtonGroup vSpeedDirGroup = new ButtonGroup();
501 vSpeedDirGroup.add(_vSpeedUpwardsRadio); vSpeedDirGroup.add(vSpeedDownwardsRadio);
502 vSpeedGrid.add(_vSpeedUpwardsRadio); vSpeedGrid.add(vSpeedDownwardsRadio);
503 _vSpeedUpwardsRadio.setSelected(true);
504 holderPanel.add(vSpeedPanel);
505 thirdCard.add(holderPanel, BorderLayout.NORTH);
507 // Make a hider to show and hide the components according to the selected fields
508 _componentHider = new ComponentHider();
509 _componentHider.addComponent(altLabel, Field.ALTITUDE);
510 _componentHider.addComponent(_altitudeUnitsDropdown, Field.ALTITUDE);
511 _componentHider.addComponent(speedLabel, Field.SPEED);
512 _componentHider.addComponent(_hSpeedUnitsDropdown, Field.SPEED);
513 _componentHider.addComponent(vSpeedLabel, Field.VERTICAL_SPEED);
514 _componentHider.addComponent(_vSpeedUnitsDropdown, Field.VERTICAL_SPEED);
515 _componentHider.addComponent(_vSpeedUpwardsRadio, Field.VERTICAL_SPEED);
516 _componentHider.addComponent(vSpeedDownwardsRadio, Field.VERTICAL_SPEED);
518 // Add cards to the wizard
519 _wizard.addCard(firstCard);
520 _wizard.addCard(secondCard);
521 _wizard.addCard(thirdCard);
523 wholePanel.add(cardPanel, BorderLayout.CENTER);
529 * Close the combo box on the selected row of the field table
530 * @param inRow currently selected row number
532 private void closeTableComboBox(int inRow)
534 TableCellEditor editor = _fieldTable.getCellEditor(inRow, 1);
537 editor.stopCellEditing();
543 * change the status based on selection of a delimiter
545 protected void informDelimiterSelected()
548 // Loop through radios to see which one is selected
549 for (int i=0; i<(_delimiterRadios.length-1); i++)
551 if (_delimiterRadios[i].isSelected())
553 // Set label text to describe records and fields
554 int numRecords = _delimiterInfos[i].getNumRecords();
557 _statusLabel.setText(I18nManager.getText("dialog.openoptions.deliminfo.norecords"));
561 fields = _delimiterInfos[i].getMaxFields();
562 _statusLabel.setText("" + numRecords + " " + I18nManager.getText("dialog.openoptions.deliminfo.records")
563 + " " + fields + " " + I18nManager.getText("dialog.openoptions.deliminfo.fields"));
567 // Don't show label if "other" delimiter is chosen (as records, fields are unknown)
568 if (_delimiterRadios[_delimiterRadios.length-1].isSelected())
570 _statusLabel.setText("");
572 // enable/disable next button
573 _nextButton.setEnabled((_delimiterRadios[4].isSelected() == false && fields > 1)
574 || _otherDelimiterText.getText().length() == 1);
579 * Get the delimiter info from the first step
580 * @return delimiter information object for the selected delimiter
582 public DelimiterInfo getSelectedDelimiterInfo()
584 for (int i=0; i<4; i++) {
585 if (_delimiterRadios[i].isSelected()) return _delimiterInfos[i];
587 // must be "other" - build info if necessary
588 if (_delimiterInfos[4] == null) {
589 _delimiterInfos[4] = new DelimiterInfo(_otherDelimiterText.getText().charAt(0));
591 return _delimiterInfos[4];
596 * Prepare the next panel to be shown, if necessary
598 private void prepareNextPanel()
600 int currPanel = _wizard.getCurrentCardIndex();
601 if (currPanel == 0) {
602 prepareSecondPanel();
604 else if (currPanel == 1)
606 Field[] selectedFields = _fieldTableModel.getFieldArray();
607 // Enable / disable controls based on whether altitude / speed / vspeed fields were chosen on second panel
608 _componentHider.enableComponents(Field.ALTITUDE, doesFieldArrayContain(selectedFields, Field.ALTITUDE));
609 _componentHider.enableComponents(Field.SPEED, doesFieldArrayContain(selectedFields, Field.SPEED));
610 _componentHider.enableComponents(Field.VERTICAL_SPEED, doesFieldArrayContain(selectedFields, Field.VERTICAL_SPEED));
611 // TODO: Also check ranges of altitudes, speeds, vert speeds to show them in the third panel
616 * Use the delimiter selected to determine the fields in the file
617 * and prepare the second panel accordingly
619 private void prepareSecondPanel()
621 DelimiterInfo info = getSelectedDelimiterInfo();
622 FileSplitter splitter = new FileSplitter(_contentCacher);
623 // Check info makes sense - num fields > 0, num records > 0
624 // set "Finished" button to disabled if not ok
625 // Add data to GUI elements
626 String[][] tableData = splitter.splitFieldData(info.getDelimiter());
627 // possible to ignore blank columns here
628 _currentDelimiter = info.getDelimiter();
629 _fileExtractTableModel.updateData(tableData);
630 _fieldTableModel = new FieldSelectionTableModel();
632 // Check number of fields and use last ones if count matches
633 Field[] startFieldArray = null;
634 if (_lastSelectedFields != null && splitter.getNumColumns() == _lastSelectedFields.length)
636 startFieldArray = _lastSelectedFields;
640 // Take first full row of file and use it to guess fields
641 startFieldArray = FieldGuesser.guessFields(splitter.getFirstFullRow());
644 _fieldTableModel.updateData(startFieldArray);
645 _fieldTable.setModel(_fieldTableModel);
646 // add dropdowns to second column
647 JComboBox<String> fieldTypesBox = new JComboBox<String>();
648 String[] fieldNames = Field.getFieldNames();
649 for (int i=0; i<fieldNames.length; i++)
651 fieldTypesBox.addItem(fieldNames[i]);
653 _fieldTable.getColumnModel().getColumn(1).setCellEditor(new DefaultCellEditor(fieldTypesBox));
655 // Set altitude format to same as last time if available
656 if (_lastAltitudeUnit == UnitSetLibrary.UNITS_METRES)
657 _altitudeUnitsDropdown.setSelectedIndex(0);
658 else if (_lastAltitudeUnit == UnitSetLibrary.UNITS_FEET)
659 _altitudeUnitsDropdown.setSelectedIndex(1);
660 // no selection on field list
665 * See if the given array of selected fields contains the specified one
666 * @param inFields array of fields selected by user in the second panel
667 * @param inCheck field to check
668 * @return true if the field is present in the array
670 private boolean doesFieldArrayContain(Field[] inFields, Field inCheck)
672 if (inFields != null) {
673 for (int i=0; i<inFields.length; i++) {
674 if (inFields[i] == inCheck) { // == check ok here because it only checks for built-in fields
683 * All options have been selected, so load file
685 private void finished()
687 // Save delimiter, field array and altitude format for later use
688 _lastUsedDelimiter = _currentDelimiter;
689 _lastSelectedFields = _fieldTableModel.getFieldArray();
690 // TODO: Remember all the units selections for next load?
691 // Get the selected units for altitudes and speeds
692 SourceInfo sourceInfo = (_file == null ? null : new SourceInfo(_file, SourceInfo.FILE_TYPE.TEXT));
693 PointCreateOptions options = new PointCreateOptions();
694 options.setAltitudeUnits(_altitudeUnitsDropdown.getSelectedIndex() == 0 ? UnitSetLibrary.UNITS_METRES : UnitSetLibrary.UNITS_FEET);
695 Unit hSpeedUnit = UnitSetLibrary.ALL_SPEED_UNITS[_hSpeedUnitsDropdown.getSelectedIndex()];
696 options.setSpeedUnits(hSpeedUnit);
697 Unit vSpeedUnit = UnitSetLibrary.ALL_SPEED_UNITS[_vSpeedUnitsDropdown.getSelectedIndex()];
698 options.setVerticalSpeedUnits(vSpeedUnit, _vSpeedUpwardsRadio.isSelected());
701 _app.informDataLoaded(_fieldTableModel.getFieldArray(),
702 _fileExtractTableModel.getData(), options, sourceInfo, null);
703 // clear up file cacher
704 _contentCacher.clear();
710 * @return true if the inputs on the current tab are valid, user is allowed to proceed
712 private boolean isCurrentCardValid()
714 int cardIndex = _wizard.getCurrentCardIndex();
717 // validate second panel
718 return _fieldTableModel.getRowCount() > 1;
720 // all other panels are always valid
725 * Make a panel with a label and a component
726 * @param inLabelKey label key to use
727 * @param inComponent component for main area of panel
728 * @return labelled Panel
730 private static JPanel makeLabelledPanel(String inLabelKey, JComponent inComponent)
732 JPanel panel = new JPanel();
733 panel.setLayout(new BorderLayout());
734 panel.add(new JLabel(I18nManager.getText(inLabelKey)), BorderLayout.NORTH);
735 panel.add(inComponent, BorderLayout.CENTER);
741 * An entry in the field list has been selected
742 * @param inFieldNum index of field, starting with 0
744 private void selectField(int inFieldNum)
746 if (inFieldNum == -1 || inFieldNum != _selectedField)
748 _selectedField = inFieldNum;
749 _moveUpButton.setEnabled(inFieldNum > 0);
750 _moveDownButton.setEnabled(inFieldNum >= 0
751 && inFieldNum < (_fieldTableModel.getRowCount()-1));
757 * @return the last delimiter character used for a load
759 public char getLastUsedDelimiter()
761 return _lastUsedDelimiter;