/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2016 RomRaider.com
*
* 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.romraider.logger.ecu.ui.swing.tools;
import static com.romraider.Settings.COMMA;
import static javax.swing.JOptionPane.ERROR_MESSAGE;
import static javax.swing.JOptionPane.INFORMATION_MESSAGE;
import static javax.swing.JOptionPane.showMessageDialog;
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.border.EtchedBorder;
import javax.swing.border.TitledBorder;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumn;
import com.romraider.logger.ecu.EcuLogger;
import com.romraider.logger.ecu.comms.query.EcuQuery;
import com.romraider.logger.ecu.ui.swing.tools.tablemodels.AirFuelLearningTableModel;
import com.romraider.logger.ecu.ui.swing.tools.tablemodels.FineLearningKnockCorrectionTableModel;
import com.romraider.logger.ecu.ui.swing.tools.tablemodels.VehicleInformationTableModel;
import com.romraider.logger.ecu.ui.swing.tools.tablemodels.renderers.CentreRenderer;
import com.romraider.logger.ecu.ui.swing.tools.tablemodels.renderers.LtvCellRenderer;
import com.romraider.logger.ecu.ui.swing.vertical.VerticalLabelUI;
import com.romraider.swing.SetFont;
import com.romraider.util.FormatFilename;
import com.romraider.util.SettingsManager;
/**
* This class is used to build and display the Adaptation Table Values
* retrieved from the ECU.
*/
public class DS2LearningTableValuesResultsPanel extends JDialog {
private static final long serialVersionUID = 6716454294436022709L;
private final String DIALOG_TITLE = "Adaptation Table Values";
private final String DT_FORMAT = "%1$tY%1$tm%1$td-%1$tH%1$tM%1$tS";
private final int LTV_WIDTH = 720;
private final int LTV_HEIGHT = 595;
private final JPanel contentPanel = new JPanel();
private JTable vehicleInfoTable;
private JTable afLearningTable;
private List<JTable> knockTables = new ArrayList<JTable>();
private final String FLKC_NAME = "Knock Adaptation (\u00B0 of correction)";
public DS2LearningTableValuesResultsPanel(
EcuLogger logger,
Map<String, Object> vehicleInfo,
String[] afRanges,
List<List<Object>> afLearning,
String[] flkcLoad,
String[] flkcRpm,
List<List<List<EcuQuery>>> flkcQueryTables) {
super(logger, false);
setIconImage(logger.getIconImage());
setTitle(DIALOG_TITLE);
setBounds(
(logger.getWidth() > LTV_WIDTH) ?
logger.getX() + (logger.getWidth() - LTV_WIDTH) / 2 : 0,
(logger.getHeight() > LTV_HEIGHT) ?
logger.getY() + ((logger.getHeight() - LTV_HEIGHT) / 2) : 0,
LTV_WIDTH,
LTV_HEIGHT);
getContentPane().setLayout(new BorderLayout());
contentPanel.setBorder(new EmptyBorder(2, 2, 2, 2));
contentPanel.setLayout(null);
contentPanel.add(buildVehicleInfoPanel(vehicleInfo));
contentPanel.add(buildAfLearningPanel(afRanges, afLearning));
contentPanel.add(buildFlkcPanel(flkcLoad, flkcRpm, flkcQueryTables));
getContentPane().add(contentPanel, BorderLayout.CENTER);
getContentPane().add(buildSaveReultsPanel(), BorderLayout.SOUTH);
}
/**
* This method is called to display the Adaptation Table Values
* retrieved from the ECU.
*/
public final void displayLearningResultsPanel() {
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
setVisible(true);
}
private final JPanel buildVehicleInfoPanel(
Map<String, Object> vehicleInfo) {
final JPanel vehicleInfoTitlePanel = new JPanel();
vehicleInfoTitlePanel.setBorder(
BorderFactory.createTitledBorder("Vehicle Information"));
vehicleInfoTitlePanel.setBounds(10, 2, 692, 70);
vehicleInfoTitlePanel.setLayout(new BorderLayout(0, 0));
JPanel vehicleInfoTablePanel = new JPanel();
vehicleInfoTablePanel.setBorder(
new EtchedBorder(EtchedBorder.LOWERED, null, null));
vehicleInfoTablePanel.setLayout(new BorderLayout(0, 0));
final VehicleInformationTableModel tableModel =
new VehicleInformationTableModel();
tableModel.setVehicleInfo(vehicleInfo);
vehicleInfoTable = new JTable(tableModel);
setTableBehaviour(vehicleInfoTable);
TableColumn column = null;
for (int i = 0; i < vehicleInfoTable.getColumnCount(); i++) {
column = vehicleInfoTable.getColumnModel().getColumn(i);
if (i == 0 || i ==1) {
column.setPreferredWidth(85);
}
else if (i == 2) {
column.setPreferredWidth(200);
}
}
vehicleInfoTablePanel.add(
formatTableHeader(vehicleInfoTable),
BorderLayout.PAGE_START);
vehicleInfoTablePanel.add(vehicleInfoTable);
vehicleInfoTitlePanel.add(vehicleInfoTablePanel, BorderLayout.CENTER);
return vehicleInfoTitlePanel;
}
private final JPanel buildAfLearningPanel(
String[] afRanges,
List<List<Object>> afLearning) {
final JPanel afLearningTitlePanel = new JPanel();
afLearningTitlePanel.setBorder(
new TitledBorder(null,
"A/F Adaptation (Stored)",
TitledBorder.LEADING,
TitledBorder.TOP, null, null));
afLearningTitlePanel.setBounds(10, 72, 450, 100);
afLearningTitlePanel.setLayout(new BorderLayout(0, 0));
final JLabel xLabel = new JLabel("Applied Adaptations");
SetFont.plain(xLabel);
xLabel.setHorizontalAlignment(SwingConstants.CENTER);
afLearningTitlePanel.add(xLabel, BorderLayout.NORTH);
final JLabel yLabel = new JLabel("Bank");
SetFont.plain(yLabel);
yLabel.setUI(new VerticalLabelUI(false));
afLearningTitlePanel.add(yLabel, BorderLayout.WEST);
final JPanel afLearningTablePanel = new JPanel();
afLearningTablePanel.setBorder(
new EtchedBorder(EtchedBorder.LOWERED, null, null));
afLearningTablePanel.setLayout(new BorderLayout(0, 0));
final AirFuelLearningTableModel tableModel =
new AirFuelLearningTableModel();
tableModel.setColumnHeadings(afRanges);
tableModel.setAfLearningInfo(afLearning);
afLearningTable = new JTable(tableModel);
setTableBehaviour(afLearningTable);
TableColumn column = null;
for (int i = 0; i < afLearningTable.getColumnCount(); i++) {
column = afLearningTable.getColumnModel().getColumn(i);
if (i == 0) {
column.setPreferredWidth(40);
}
else {
column.setPreferredWidth(120);
}
}
afLearningTablePanel.add(
formatTableHeader(afLearningTable),
BorderLayout.PAGE_START);
if (afLearning.size() > 0) {
afLearningTablePanel.add(afLearningTable);
}
else {
afLearningTablePanel.add(new JLabel(
" No data - A/F Adaptation parameter IDs not defined"));
}
afLearningTitlePanel.add(afLearningTablePanel, BorderLayout.CENTER);
return afLearningTitlePanel;
}
private final JPanel buildFlkcPanel(
String[] flkcLoad,
String[] flkcRpm,
List<List<List<EcuQuery>>> flkcQueryTables) {
final JPanel flkcTitlePanel = new JPanel();
flkcTitlePanel.setBorder(
new TitledBorder(null,
FLKC_NAME,
TitledBorder.LEADING,
TitledBorder.TOP, null, null));
flkcTitlePanel.setBounds(10, 172, 692, 354);
flkcTitlePanel.setLayout(new BorderLayout(0, 0));
final JLabel xLabel = new JLabel("Engine Load (mg/stroke)");
SetFont.plain(xLabel);
xLabel.setHorizontalAlignment(SwingConstants.CENTER);
flkcTitlePanel.add(xLabel, BorderLayout.NORTH);
final JLabel yLabel = new JLabel("Engine Speed (RPM)");
SetFont.plain(yLabel);
yLabel.setUI(new VerticalLabelUI(false));
flkcTitlePanel.add(yLabel, BorderLayout.WEST);
final JTabbedPane tabs = new JTabbedPane();
for (int i = 0; i < flkcQueryTables.size(); i++) {
final FineLearningKnockCorrectionTableModel tableModel =
new FineLearningKnockCorrectionTableModel();
tableModel.setColumnHeadings(flkcLoad);
tableModel.setRomHeadings(flkcRpm);
tableModel.setFlkcData(flkcQueryTables.get(i));
final JTable knockTable = new JTable(tableModel);
knockTables.add(knockTable);
setTableBehaviour(knockTable);
formatTableHeader(knockTable);
final JScrollPane flkcTablePanel = new JScrollPane(knockTable);
flkcTablePanel.setBorder(
new EtchedBorder(EtchedBorder.LOWERED, null, null));
tabs.addTab("Table " + (i + 1), flkcTablePanel);
}
if (flkcQueryTables.size() > 0) {
flkcTitlePanel.add(tabs, BorderLayout.CENTER);
}
else {
flkcTitlePanel.removeAll();
flkcTitlePanel.add(new JLabel(
" No data - Knock Adaptation parameter ID not defined"),
BorderLayout.CENTER);
}
return flkcTitlePanel;
}
private final void setTableBehaviour(JTable table) {
table.setBorder(null);
table.setColumnSelectionAllowed(false);
table.setRowSelectionAllowed(false);
table.setFont(new Font("Tahoma", Font.PLAIN, 11));
table.setFillsViewportHeight(true);
table.setDefaultRenderer(Double.class, new LtvCellRenderer());
table.setDefaultRenderer(String.class, new LtvCellRenderer());
}
private final JTableHeader formatTableHeader(JTable table) {
final JTableHeader th = table.getTableHeader();
th.setReorderingAllowed(false);
th.setDefaultRenderer(new CentreRenderer(table));
SetFont.bold(th, 11);
return th;
}
private final JPanel buildSaveReultsPanel() {
final JPanel controlPanel = new JPanel();
final JButton toFile = new JButton("Save to File");
toFile.setToolTipText("Save tables to a text file");
toFile.setMnemonic(KeyEvent.VK_F);
toFile.addActionListener(new ActionListener() {
@Override
public final void actionPerformed(ActionEvent actionEvent) {
saveTableText();
}
});
final JButton toImage = new JButton("Save as Image");
toImage.setToolTipText("Save tables as an image");
toImage.setMnemonic(KeyEvent.VK_I);
toImage.addActionListener(new ActionListener() {
@Override
public final void actionPerformed(ActionEvent actionEvent) {
saveTableImage();
}
});
controlPanel.add(toFile);
controlPanel.add(toImage);
return controlPanel;
}
private final void saveTableText() {
final String nowStr = String.format(DT_FORMAT, System.currentTimeMillis());
final String fileName = String.format("%s%sromraiderADPT_%s.csv",
SettingsManager.getSettings().getLoggerOutputDirPath(),
File.separator,
nowStr);
try {
final File csvFile = new File(fileName);
final String EOL = System.getProperty("line.separator");
final BufferedWriter bw = new BufferedWriter(
new FileWriter(csvFile));
bw.write("Adaptation Table Values" + EOL);
Object result = 0;
int columnCount = vehicleInfoTable.getColumnCount();
for (int i = 0; i < columnCount; i++ ) {
result = vehicleInfoTable.getTableHeader().getColumnModel().
getColumn(i).getHeaderValue();
bw.append(result.toString());
bw.append(COMMA);
}
bw.append(EOL);
for (int i = 0; i < columnCount; i++ ) {
result = vehicleInfoTable.getValueAt(0, i);
bw.append(result.toString());
bw.append(COMMA);
}
bw.append(EOL + EOL);
bw.write("A/F Adaptation (Stored)" + EOL);
columnCount = afLearningTable.getColumnCount();
int rowCount = afLearningTable.getRowCount();
for (int i = 0; i < columnCount; i++) {
result = afLearningTable.getTableHeader().getColumnModel().
getColumn(i).getHeaderValue();
bw.append(result.toString());
bw.append(COMMA);
}
bw.append(EOL);
for (int i = 0; i < rowCount; i++) {
for (int j = 0; j < columnCount; j++) {
result = afLearningTable.getValueAt(i, j);
bw.append(result.toString());
bw.append(COMMA);
}
bw.append(EOL);
}
bw.append(EOL);
bw.write(FLKC_NAME + EOL);
int k = 1;
for (JTable knockTable : knockTables) {
columnCount = knockTable.getColumnCount();
for (int i = 0; i < columnCount; i++) {
result = knockTable.getTableHeader().getColumnModel().
getColumn(i).getHeaderValue();
if (result.toString().equals(" ")) {
result = String.format("Table %d", k);
}
bw.append(result.toString());
bw.append(COMMA);
}
k++;
}
bw.append(EOL);
rowCount = knockTables.get(0).getRowCount();
for (int i = 0; i < rowCount; i++) {
for (JTable knockTable : knockTables) {
columnCount = knockTable.getColumnCount();
for (int j = 0; j < columnCount; j++) {
result = knockTable.getValueAt(i, j);
bw.append(result.toString());
bw.append(COMMA);
}
}
bw.append(EOL);
}
bw.close();
final String shortName = FormatFilename.getShortName(fileName);
showMessageDialog(
null,
"Table's text saved to: " + shortName,
"Save Success",
INFORMATION_MESSAGE);
}
catch (Exception e) {
showMessageDialog(
null,
"Failed to save tables, check path:\n" + fileName,
"Save Failed",
ERROR_MESSAGE);
}
}
private final void saveTableImage() {
final BufferedImage resultsImage = new BufferedImage(
contentPanel.getWidth(),
contentPanel.getHeight(),
BufferedImage.TYPE_INT_ARGB);
contentPanel.paint(resultsImage.createGraphics());
final String nowStr = String.format(DT_FORMAT, System.currentTimeMillis());
final String fileName = String.format("%s%sromraiderADPT_%s.png",
SettingsManager.getSettings().getLoggerOutputDirPath(),
File.separator,
nowStr);
final String shortName = FormatFilename.getShortName(fileName);
try {
final File imageFile = new File(fileName);
ImageIO.write(
resultsImage,
"png",
imageFile);
showMessageDialog(
null,
"Adaptation Table Values image saved to: " + shortName,
"Save Success",
INFORMATION_MESSAGE);
}
catch (Exception e) {
showMessageDialog(
null,
"Failed to save image, check path:\n" + fileName,
"Save Failed",
ERROR_MESSAGE);
}
}
}