/* * Open-Source tuning tools * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package com.vgi.mafscaling; import java.awt.Component; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Writer; import java.text.DecimalFormat; import java.text.Format; import javax.swing.Box; import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.ListSelectionModel; import javax.swing.border.TitledBorder; import javax.swing.filechooser.FileSystemView; import javax.swing.table.DefaultTableModel; import org.apache.log4j.Logger; public class PrimaryOpenLoopFuelingTable implements ActionListener { private static final Logger logger = Logger.getLogger(PrimaryOpenLoopFuelingTable.class); private final static int ColumnWidth = 45; private ExcelAdapter excelAdapter = new ExcelAdapter(); private JFileChooser fileChooser = null; private JTable fuelingTable = null; private JTable tempFuelingTable = null; private JButton btnSetDefault = null; private JComboBox<String> loadList = null; private String fileName = ""; private String tempFileName = ""; private JCheckBox checkBoxMap = null; private boolean isPolfMap = false; public PrimaryOpenLoopFuelingTable() { checkBoxMap = new JCheckBox("This fueling table has MAP (psi abs) axis"); File appdir = new File("."); FileSystemView fsv = new RestrictedFileSystemView(appdir); fileChooser = new JFileChooser(fsv); fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); fileName = Config.getDefaultPOLFueling(); btnSetDefault = new JButton("Set Default"); btnSetDefault.addActionListener(this); if (!fileName.isEmpty()) { fuelingTable = loadPolFueling(fuelingTable, fileName); if (fuelingTable != null) btnSetDefault.setText("Unset Default"); else { Config.setDefaultPOLFueling(""); resetPOLFuelingFiles(fileName, ""); } } } public boolean getSetUserFueling() { JPanel fuelingPanel = new JPanel(); GridBagLayout gbl_dataPanel = new GridBagLayout(); gbl_dataPanel.columnWidths = new int[]{0, 0, 0, 0, 0, 0}; gbl_dataPanel.rowHeights = new int[] {0, 0, 0}; gbl_dataPanel.columnWeights = new double[]{0.0, 1.0, 0.0, 0.0, 0.0, 0.0}; gbl_dataPanel.rowWeights = new double[]{0.0, 0.0, 0.0}; fuelingPanel.setLayout(gbl_dataPanel); loadList = new JComboBox<String>(Config.getPOLFuelingFiles().split(Utils.fileFieldSplitter)); GridBagConstraints gbc_loadList = new GridBagConstraints(); gbc_loadList.anchor = GridBagConstraints.EAST; gbc_loadList.insets = new Insets(1, 5, 1, 1); gbc_loadList.gridx = 0; gbc_loadList.gridy = 0; loadList.setSelectedItem(fileName); loadList.setActionCommand("polselected"); loadList.addActionListener(this); loadList.setPrototypeDisplayValue("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); fuelingPanel.add(loadList, gbc_loadList); Component horizontalGlue = Box.createHorizontalGlue(); GridBagConstraints gbc_horizontalGlue = new GridBagConstraints(); gbc_horizontalGlue.fill = GridBagConstraints.HORIZONTAL; gbc_horizontalGlue.insets = new Insets(1, 5, 1, 1); gbc_horizontalGlue.gridx = 1; gbc_horizontalGlue.gridy = 0; fuelingPanel.add(horizontalGlue, gbc_horizontalGlue); JButton btnSave = new JButton("Save"); GridBagConstraints gbc_btnSave = new GridBagConstraints(); gbc_btnSave.anchor = GridBagConstraints.EAST; gbc_btnSave.insets = new Insets(1, 5, 1, 1); gbc_btnSave.gridx = 2; gbc_btnSave.gridy = 0; btnSave.setActionCommand("save"); btnSave.addActionListener(this); fuelingPanel.add(btnSave, gbc_btnSave); GridBagConstraints gbc_btnSetDefault = new GridBagConstraints(); gbc_btnSetDefault.anchor = GridBagConstraints.EAST; gbc_btnSetDefault.insets = new Insets(1, 5, 1, 1); gbc_btnSetDefault.gridx = 3; gbc_btnSetDefault.gridy = 0; btnSetDefault.setActionCommand("setdefault"); fuelingPanel.add(btnSetDefault, gbc_btnSetDefault); JButton btnClearData = new JButton("Clear"); GridBagConstraints gbc_btnClearData = new GridBagConstraints(); gbc_btnClearData.anchor = GridBagConstraints.EAST; gbc_btnClearData.insets = new Insets(1, 5, 1, 1); gbc_btnClearData.gridx = 4; gbc_btnClearData.gridy = 0; btnClearData.setActionCommand("clear"); btnClearData.addActionListener(this); fuelingPanel.add(btnClearData, gbc_btnClearData); JButton btnValidateData = new JButton("Validate"); GridBagConstraints gbc_btnValidateData = new GridBagConstraints(); gbc_btnValidateData.anchor = GridBagConstraints.EAST; gbc_btnValidateData.insets = new Insets(1, 5, 1, 1); gbc_btnValidateData.gridx = 5; gbc_btnValidateData.gridy = 0; btnValidateData.setActionCommand("check"); btnValidateData.addActionListener(this); fuelingPanel.add(btnValidateData, gbc_btnValidateData); tempFuelingTable = createFuelingTable(); tempFileName = fileName; if (btnSetDefault.getText().equals("Unset Default") && !Config.getDefaultPOLFueling().equals(tempFileName)) btnSetDefault.setText("Set Default"); GridBagConstraints gbc_fuelingTable = new GridBagConstraints(); gbc_fuelingTable.insets = new Insets(5, 0, 0, 0); gbc_fuelingTable.fill = GridBagConstraints.BOTH; gbc_fuelingTable.weightx = 1.0; gbc_fuelingTable.weighty = 1.0; gbc_fuelingTable.gridx = 0; gbc_fuelingTable.gridy = 1; gbc_fuelingTable.gridwidth = 6; JScrollPane scrollPane = new JScrollPane(tempFuelingTable); scrollPane.setViewportBorder(new TitledBorder(null, "Primary Open Loop Fueling", TitledBorder.LEADING, TitledBorder.TOP, null, null)); fuelingPanel.add(scrollPane, gbc_fuelingTable); fuelingPanel.setPreferredSize(new Dimension(620, 500)); GridBagConstraints gbc_checkBoxMap = new GridBagConstraints(); gbc_checkBoxMap.anchor = GridBagConstraints.WEST; gbc_checkBoxMap.insets = new Insets(5, 0, 0, 0); gbc_checkBoxMap.gridx = 0; gbc_checkBoxMap.gridy = 2; fuelingPanel.add(checkBoxMap, gbc_checkBoxMap); JComponent[] inputs = new JComponent[] { fuelingPanel }; do { if (JOptionPane.OK_OPTION != JOptionPane.showConfirmDialog(null, inputs, "Fueling settings", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE)) { excelAdapter.removeTable(tempFuelingTable); Utils.clearTable(tempFuelingTable); tempFuelingTable = null; tempFileName = ""; checkBoxMap.setSelected(isPolfMap); return false; } } while (!validateFuelingData(tempFuelingTable)); if (tempFuelingTable != null) { if (fuelingTable != null) excelAdapter.removeTable(fuelingTable); if (Utils.isTableEmpty(tempFuelingTable)) { fuelingTable = null; tempFuelingTable = null; tempFileName = ""; fileName = ""; checkBoxMap.setSelected(isPolfMap); } else { fuelingTable = tempFuelingTable; fileName = tempFileName; isPolfMap = checkBoxMap.isSelected(); } } return true; } /** * Method resets POL Fueling files list to encounter for removed files */ public void resetPOLFuelingFiles(String remFileName, String addFileName) { String[] files = Config.getPOLFuelingFiles().split(Utils.fileFieldSplitter); String fs = ""; for (String fn : files) { if (fn.equals(remFileName) || fn.isEmpty()) continue; fs += ("," + fn); } if (!addFileName.isEmpty()) fs += ("," + addFileName); Config.setPOLFuelingFiles(fs); } /** * Method clears cells and resets background color */ public void clear() { Utils.clearTable(tempFuelingTable); tempFileName = ""; loadList.setSelectedIndex(0); resetMapState(); } /** * Method validates that fueling table exists and all data is populated. * @return */ public boolean validate() { return validateFuelingData(fuelingTable); } /** * Method returns true if fueling table is set, false otherwise. * @return */ public boolean isSet() { // TODO: I don't think the validateFuelingData call is necessary here - if a table has been set it SHOULD always be valid return fuelingTable != null && !Utils.isTableEmpty(fuelingTable) && validateFuelingData(fuelingTable); } /** * Method returns true if fueling table has MAP axis, false otherwise. * @return */ public boolean isMap() { return isPolfMap; } /** * Method sets values for the row. * If current table row count is less than specified row, a new row is added. * If current table column count is less than number of columns in elements array, a new column is added. * @param row * @param elements */ public void setValueAtRow(int row, String[] elements) { fuelingTable = setValueAtRow(fuelingTable, row, elements); } /** * Method sets values for the row. * If current table row count is less than specified row, a new row is added. * If current table column count is less than number of columns in elements array, a new column is added. * @param fuelingTable * @param row * @param elements * @return */ private JTable setValueAtRow(JTable fuelingTable, int row, String[] elements) { if (fuelingTable == null) fuelingTable = createFuelingTable(); Utils.ensureRowCount(row + 1, fuelingTable); Utils.ensureColumnCount(elements.length - 1, fuelingTable); for (int i = 0; i < elements.length - 1; ++i) fuelingTable.setValueAt(elements[i], row, i); return fuelingTable; } public Object getValueAt(int row, int column) { return fuelingTable.getValueAt(row, column); } /** * Method return row count * @return row count */ public int getRowCount() { return fuelingTable.getRowCount(); } /** * Method return row count * @return column count */ public int getColumnCount() { return fuelingTable.getColumnCount(); } /** * Method write data in current primary open loop fueling table to provide file handler * @param out, file handler * @throws IOException */ public void write(Writer out) throws IOException { write(fuelingTable, out); } /** * Method resets the MAP checkbox and flag states. * @return */ private void resetMapState() { checkBoxMap.setSelected(false); checkBoxMap.setEnabled(true); isPolfMap = false; } /** * Method write data in current primary open loop fueling table to provide file handler * @param fuelingTable * @param out, file handler * @throws IOException */ private void write(JTable fuelingTable, Writer out) throws IOException { if (fuelingTable != null) { if (checkBoxMap.isSelected()) out.write("MAP\n"); int i, j; for (i = 0; i < fuelingTable.getRowCount(); ++i) { for (j = 0; j < fuelingTable.getColumnCount(); ++j) out.write(fuelingTable.getValueAt(i, j).toString() + ","); out.write("\n"); } } } /** * Function creates new fueling table * @return */ private JTable createFuelingTable() { JTable table = new JTable(); table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); table.setColumnSelectionAllowed(true); table.setCellSelectionEnabled(true); table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); table.setTableHeader(null); table.putClientProperty("terminateEditOnFocusLost", true); if (fuelingTable != null) { table.setModel(new DefaultTableModel(fuelingTable.getRowCount(), fuelingTable.getColumnCount())); Utils.initializeTable(table, ColumnWidth); for (int i = 0; i < fuelingTable.getRowCount(); ++i) { for (int j = 0; j < fuelingTable.getColumnCount(); ++j) { if (fuelingTable.getValueAt(i, j) != null) table.setValueAt(fuelingTable.getValueAt(i, j).toString(), i, j); } } Utils.colorTable(table); } else { table.setModel(new DefaultTableModel(20, 15)); Utils.initializeTable(table, ColumnWidth); } Format[][] formatMatrix = { { new DecimalFormat("#"), new DecimalFormat("0.00") } }; NumberFormatRenderer renderer = (NumberFormatRenderer)table.getDefaultRenderer(Object.class); renderer.setFormats(formatMatrix); excelAdapter.addTable(table, true, true); return table; } /** * Method validates that provided table exists and all data is populated. * @param fuelingTable, table to be checked * @return */ private boolean validateFuelingData(JTable fuelingTable) { if (fuelingTable != null && Utils.isTableEmpty(fuelingTable)) return true; if (fuelingTable == null || !Utils.validateTable(fuelingTable)) return false; validateMapLoadFuelingData(fuelingTable); return true; } /** * Method validates that proper selection of MAP or Load POLF is made. * @param fuelingTable, table to be checked * @return */ private void validateMapLoadFuelingData(JTable fuelingTable) { final double maxLoad = 10.0; double firstRowLastColumnValue = Double.parseDouble(fuelingTable.getValueAt(0, fuelingTable.getColumnCount() - 1).toString()); if (checkBoxMap.isSelected() && firstRowLastColumnValue < maxLoad) { JOptionPane.showMessageDialog(null, "The data looks like it's Load based POLF table. Unsetting the checkbox.", "Warning", JOptionPane.WARNING_MESSAGE); checkBoxMap.setSelected(false); } else if (!checkBoxMap.isSelected() && firstRowLastColumnValue >= maxLoad) { JOptionPane.showMessageDialog(null, "This data looks like it's MAP (psi) based POLF table. Setting the checkbox.", "Warning", JOptionPane.WARNING_MESSAGE); checkBoxMap.setSelected(true); } } /** * Function to load POL Fueling table from file */ private JTable loadPolFueling(JTable fuelingTable, String fileName) { File file = new File("./" + fileName); BufferedReader br = null; try { br = new BufferedReader(new InputStreamReader(new FileInputStream(file.getAbsoluteFile()), Config.getEncoding())); int i = 0; String line = br.readLine(); while (line != null) { if (0 == i && line.equals("MAP")) { checkBoxMap.setSelected(true); checkBoxMap.setEnabled(false); isPolfMap = true; } else fuelingTable = setValueAtRow(fuelingTable, i++, line.split(Utils.fileFieldSplitter, -1)); line = br.readLine(); } if (i > 0 && validateFuelingData(fuelingTable)) return fuelingTable; } catch (FileNotFoundException e) { logger.error(e); } catch (Exception e) { e.printStackTrace(); logger.error(e); } finally { if (br != null) { try { br.close(); } catch (IOException e) { logger.error(e); } } } return null; } /** * Function sets current POL table as default. If the current POL table not saved - it saves it. * @param fuelingTable * @return */ private void setDefault(JTable fuelingTable) { if (btnSetDefault.getText().equals("Unset Default")) { Config.setDefaultPOLFueling(""); btnSetDefault.setText("Set Default"); } else if (!save(fuelingTable).isEmpty()) { Config.setDefaultPOLFueling(tempFileName); btnSetDefault.setText("Unset Default"); } } /** * Function save POL table. * @param fuelingTable * @return */ private String save(JTable fuelingTable) { if (fuelingTable == null || Utils.isTableEmpty(fuelingTable) || !validateFuelingData(fuelingTable)) return ""; File file = null; if (tempFileName.isEmpty()) { if (JFileChooser.APPROVE_OPTION != fileChooser.showSaveDialog(null)) return ""; file = fileChooser.getSelectedFile(); tempFileName = file.getName(); } else file = new File(tempFileName); Writer out = null; try { out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), Config.getEncoding())); write(fuelingTable, out); } catch (Exception e) { JOptionPane.showMessageDialog(null, "Failed to save file " + tempFileName + ": " + e.toString(), "Error", JOptionPane.ERROR_MESSAGE); tempFileName = ""; } finally { if (out != null) { try { out.close(); } catch (IOException e) { logger.error(e); } } } if (!tempFileName.isEmpty()) { resetPOLFuelingFiles(tempFileName, tempFileName); if (((DefaultComboBoxModel<String>)loadList.getModel()).getIndexOf(tempFileName) == -1) loadList.addItem(tempFileName); loadList.setSelectedItem(tempFileName); } return tempFileName; } /** * Loads POL fueling table from file. * @param fuelingTable */ private void load() { Utils.clearTable(tempFuelingTable); tempFileName = (String)loadList.getSelectedItem(); btnSetDefault.setText("Set Default"); resetMapState(); // needed even when tempFileName == "" (blank table selected) so load log will display columns correctly if (!tempFileName.isEmpty()) { if (loadPolFueling(tempFuelingTable, tempFileName) != null) { loadList.setSelectedItem(tempFileName); if (Config.getDefaultPOLFueling().equals(tempFileName)) btnSetDefault.setText("Unset Default"); } else { loadList.removeItem(tempFileName); loadList.setSelectedItem(""); resetPOLFuelingFiles(tempFileName, ""); } } } @Override public void actionPerformed(ActionEvent e) { if ("clear".equals(e.getActionCommand())) clear(); else if ("check".equals(e.getActionCommand())) validateFuelingData(tempFuelingTable); else if ("setdefault".equals(e.getActionCommand())) setDefault(tempFuelingTable); else if ("save".equals(e.getActionCommand())) save(tempFuelingTable); else if ("polselected".equals(e.getActionCommand())) load(); } }