001package jmri.jmrit.operations.rollingstock; 002 003import java.io.*; 004import java.nio.charset.StandardCharsets; 005import java.util.Arrays; 006 007import javax.swing.*; 008import javax.swing.filechooser.FileNameExtensionFilter; 009 010import org.apache.commons.csv.*; 011import org.slf4j.Logger; 012import org.slf4j.LoggerFactory; 013 014import jmri.jmrit.operations.setup.Control; 015 016/** 017 * Provides common routes for importing cars and locomotives 018 * 019 * @author Dan Boudreau Copyright (C) 2013, 2025 020 */ 021public abstract class ImportCommon extends Thread { 022 023 protected static final String NEW_LINE = "\n"; // NOI18N 024 025 protected JLabel lineNumber = new JLabel(); 026 protected JLabel importLine = new JLabel(); 027 028 protected boolean importOkay = false; 029 protected static final String[] BREAK = new String[0]; 030 protected int lineNum = 0; 031 032 protected static final String LOCATION_TRACK_SEPARATOR = "-"; 033 034 protected jmri.util.JmriJFrame fstatus; 035 036 // Get file to read from 037 protected File getFile() { 038 JFileChooser fc = new jmri.util.swing.JmriJFileChooser(jmri.jmrit.operations.OperationsXml.getFileLocation()); 039 fc.setFileFilter(new FileNameExtensionFilter(Bundle.getMessage("Text&CSV"), "txt", "csv")); // NOI18N 040 int retVal = fc.showOpenDialog(null); 041 if (retVal != JFileChooser.APPROVE_OPTION) { 042 return null; // canceled 043 } 044 log.info("Importing from file: {}", fc.getSelectedFile()); 045 return fc.getSelectedFile(); 046 } 047 048 protected BufferedReader getBufferedReader(File file) { 049 try { 050 return new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8)); 051 } catch (FileNotFoundException e) { 052 return null; 053 } 054 } 055 056 // create a status frame showing line number and imported text 057 protected void createStatusFrame(String title) { 058 JPanel ps = new JPanel(); 059 ps.setLayout(new BoxLayout(ps, BoxLayout.Y_AXIS)); 060 fstatus = new jmri.util.JmriJFrame(title); 061 fstatus.setLocation(10, 10); 062 fstatus.setSize(Control.panelWidth1025, 100); 063 064 ps.add(lineNumber); 065 ps.add(importLine); 066 067 fstatus.getContentPane().add(ps); 068 fstatus.setVisible(true); 069 } 070 071 /* 072 * Needs to handle empty lines 073 */ 074 protected String[] parseCommaLine(String line) { 075 String[] outLine = new String[0]; 076 try { 077 CSVRecord record = CSVParser.parse(line, CSVFormat.DEFAULT).getRecords().get(0); 078 outLine = new String[record.size()]; 079 // load output array to prevent NPE 080 for (int i = 0; i < outLine.length; i++) { 081 outLine[i] = record.get(i); 082 } 083 } catch (IndexOutOfBoundsException e) { 084 // do nothing blank line 085 } catch (IOException ex) { 086 log.error("Error parsing CSV: {}, {}", line, ex.getLocalizedMessage()); 087 Arrays.fill(outLine, ""); // NOI18N 088 } 089 return outLine; 090 } 091 092 protected String[] readNextLine(BufferedReader rdr) { 093 String line = " "; 094 try { 095 line = rdr.readLine(); 096 } catch (IOException e) { 097 return BREAK; 098 } 099 if (line == null) { 100 importOkay = true; 101 return BREAK; 102 } 103 if (!fstatus.isShowing()) { 104 //user canceled input! 105 return BREAK; 106 } 107 lineNumber.setText(Bundle.getMessage("LineNumber", Integer.toString(++lineNum))); 108 line = line.trim(); 109 importLine.setText(line); 110 111 String[] inputLine = parseCommaLine(line); 112 log.debug("Import line number {} has {} elements", lineNum, inputLine.length); 113 114 return inputLine; 115 } 116 117 private final static Logger log = LoggerFactory.getLogger(ImportCommon.class); 118}