/*
* 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.Color;
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.text.DecimalFormat;
import java.text.Format;
import java.util.ArrayList;
import java.util.Collections;
import java.util.regex.Pattern;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.ScrollPaneConstants;
import javax.swing.SpinnerNumberModel;
import javax.swing.border.LineBorder;
import javax.swing.border.TitledBorder;
import javax.swing.table.DefaultTableModel;
import org.apache.log4j.Logger;
public class LogStatsFixedAxis implements ActionListener {
private static final Logger logger = Logger.getLogger(LogStatsFixedAxis.class);
private enum Axis {XAXIS, YAXIS};
private final static int ColumnWidth = 55;
private final static int AxisColumnCount = 25;
private ExcelAdapter excelAdapter = new ExcelAdapter();
private JTable xAxisTable = null;
private JTable yAxisTable = null;
private JTable templateTable = null;
private JPanel dataPanel = null;
private JSpinner distanceSpinner = null;
private JComboBox<String> xAxisList = null;
private JComboBox<String> yAxisList = null;
private ArrayList<Double> xAxisArray;
private ArrayList<Double> yAxisArray;
private ArrayList<Integer> distance;
private Insets insets0 = new Insets(0, 0, 0, 0);
private Insets insets3 = new Insets(3, 3, 3, 3);
public LogStatsFixedAxis(ArrayList<Integer> distancePct, ArrayList<Double> xAxis, ArrayList<Double> yAxis) {
xAxisArray = xAxis;
yAxisArray = yAxis;
distance = distancePct;
initialize();
}
private void initialize() {
String templNames;
dataPanel = new JPanel();
GridBagLayout gbl_dataPanel = new GridBagLayout();
gbl_dataPanel.columnWidths = new int[]{0, 0, 0, 0, 0};
gbl_dataPanel.rowHeights = new int[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
gbl_dataPanel.columnWeights = new double[]{0.0, 0.0, 1.0, 0.0, 0.0};
gbl_dataPanel.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
dataPanel.setLayout(gbl_dataPanel);
dataPanel.setPreferredSize(new Dimension(620, 550));
GridBagConstraints gbc_fullWidth = new GridBagConstraints();
gbc_fullWidth.anchor = GridBagConstraints.PAGE_START;
gbc_fullWidth.fill = GridBagConstraints.HORIZONTAL;
gbc_fullWidth.insets = insets3;
gbc_fullWidth.gridwidth = 5;
gbc_fullWidth.gridx = 0;
gbc_fullWidth.gridy = 0;
JLabel noteLabel = new JLabel("Select saved, manually enter, or paste axis values into tables below");
noteLabel.setForeground(Color.BLUE);
dataPanel.add(noteLabel, gbc_fullWidth);
// add controls for x-axis
templNames = Config.getXAxisTemplates();
if (templNames.isEmpty())
templNames = ",";
gbc_fullWidth.gridy++;
addLabel(gbc_fullWidth.gridy, 0, "Saved X-Axis");
xAxisList = addComboBox(gbc_fullWidth.gridy, 1, templNames, "xaxis");
addButton(gbc_fullWidth.gridy, 2, "Clear", "clearxaxis");
addButton(gbc_fullWidth.gridy, 3, "Save", "savexaxis");
addButton(gbc_fullWidth.gridy, 4, "Remove", "remxtempl");
// add x-axis table
gbc_fullWidth.gridy++;
xAxisTable = createAxisPanel(gbc_fullWidth.gridy, "X-Axis");
gbc_fullWidth.gridy++;
dataPanel.add(new JLabel(" "), gbc_fullWidth);
// add controls for y-axis
templNames = Config.getYAxisTemplates();
if (templNames.isEmpty())
templNames = ",";
gbc_fullWidth.gridy++;
addLabel(gbc_fullWidth.gridy, 0, "Saved Y-Axis");
yAxisList = addComboBox(gbc_fullWidth.gridy, 1, templNames, "yaxis");
addButton(gbc_fullWidth.gridy, 2, "Clear", "clearyaxis");
addButton(gbc_fullWidth.gridy, 3, "Save", "saveyaxis");
addButton(gbc_fullWidth.gridy, 4, "Remove", "remytempl");
// add y-axis table
gbc_fullWidth.gridy++;
yAxisTable = createAxisPanel(gbc_fullWidth.gridy, "Y-Axis");
gbc_fullWidth.gridy++;
noteLabel = new JLabel("You can paste a table below and first row / first column will be used as axis");
noteLabel.setForeground(Color.BLUE);
dataPanel.add(noteLabel, gbc_fullWidth);
gbc_fullWidth.gridy++;
addButton(gbc_fullWidth.gridy, 3, "Clear", "cleartempl");
addButton(gbc_fullWidth.gridy, 4, "Validate", "validate");
gbc_fullWidth.gridy++;
createAxisTablePanel(gbc_fullWidth.gridy);
gbc_fullWidth.gridy++;
noteLabel = new JLabel("<html>You can set specific distance % to get data that falls as close the the axis points as possible (where 50% is the mid-point between two axis points)<html>");
noteLabel.setForeground(Color.BLUE);
dataPanel.add(noteLabel, gbc_fullWidth);
gbc_fullWidth.gridy++;
addLabel(gbc_fullWidth.gridy, 0, "Distance %");
distanceSpinner = addSpinnerFilter(gbc_fullWidth.gridy, 1, distance.get(0).intValue(), 1, 50, 1);
setAxisTables();
JComponent[] inputs = new JComponent[] { dataPanel };
do {
if (JOptionPane.OK_OPTION != JOptionPane.showConfirmDialog(null, inputs, "Fixed size axis", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE))
return;
}
while (!validateAxisData());
}
private JTable createAxisPanel(int row, String tableName) {
JTable axisTable = new JTable();
axisTable.setColumnSelectionAllowed(true);
axisTable.setCellSelectionEnabled(true);
axisTable.setBorder(new LineBorder(Color.GRAY));
axisTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
axisTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
axisTable.setModel(new DefaultTableModel(1, AxisColumnCount));
axisTable.setTableHeader(null);
Utils.initializeTable(axisTable, ColumnWidth);
excelAdapter.addTable(axisTable, false, false, false, false, true, false, true, false, true);
JScrollPane axisScrollPane = new JScrollPane(axisTable);
axisScrollPane.setViewportBorder(new TitledBorder(null, tableName, TitledBorder.LEADING, TitledBorder.TOP, null, null));
axisScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
axisScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
GridBagConstraints gbc_axisScrollPane = new GridBagConstraints();
gbc_axisScrollPane.insets = insets0;
gbc_axisScrollPane.anchor = GridBagConstraints.NORTH;
gbc_axisScrollPane.fill = GridBagConstraints.HORIZONTAL;
gbc_axisScrollPane.weightx = 1.0;
gbc_axisScrollPane.gridx = 0;
gbc_axisScrollPane.gridy = row;
gbc_axisScrollPane.gridwidth = 5;
gbc_axisScrollPane.ipady = 10;
dataPanel.add(axisScrollPane, gbc_axisScrollPane);
return axisTable;
}
public void createAxisTablePanel(int row) {
templateTable = new JTable();
templateTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
templateTable.setColumnSelectionAllowed(true);
templateTable.setCellSelectionEnabled(true);
templateTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
templateTable.setTableHeader(null);
templateTable.setModel(new DefaultTableModel(20, 15));
Utils.initializeTable(templateTable, ColumnWidth);
Format[][] formatMatrix = { { new DecimalFormat("#"), new DecimalFormat("0.00") } };
NumberFormatRenderer renderer = (NumberFormatRenderer)templateTable.getDefaultRenderer(Object.class);
renderer.setFormats(formatMatrix);
excelAdapter.addTable(templateTable, true, true);
GridBagConstraints gbc_templTable = new GridBagConstraints();
gbc_templTable.insets = new Insets(5, 0, 0, 0);
gbc_templTable.fill = GridBagConstraints.BOTH;
gbc_templTable.weightx = 1.0;
gbc_templTable.weighty = 1.0;
gbc_templTable.gridx = 0;
gbc_templTable.gridy = row;
gbc_templTable.gridwidth = 5;
JScrollPane scrollPane = new JScrollPane(templateTable);
dataPanel.add(scrollPane, gbc_templTable);
}
private void addLabel(int row, int column, String text) {
JLabel label = new JLabel(text);
GridBagConstraints gbc_label = new GridBagConstraints();
gbc_label.anchor = GridBagConstraints.EAST;
gbc_label.insets = new Insets(3, 0, 3, 0);
gbc_label.gridx = column;
gbc_label.gridy = row;
dataPanel.add(label, gbc_label);
}
private JComboBox<String> addComboBox(int row, int column, String names, String action) {
JComboBox<String> combo = new JComboBox<String>(names.split(","));
combo.setActionCommand(action);
combo.addActionListener(this);
combo.setPrototypeDisplayValue("XXXXXXXXXXXXXXXXXXXXXXXXXXX");
GridBagConstraints gbc_combo = new GridBagConstraints();
gbc_combo.anchor = GridBagConstraints.WEST;
gbc_combo.insets = new Insets(1, 5, 1, 1);
gbc_combo.gridx = column;
gbc_combo.gridy = row;
dataPanel.add(combo, gbc_combo);
return combo;
}
private JSpinner addSpinnerFilter(int row, int column, int value, int min, int max, int step) {
JSpinner spinner = new JSpinner(new SpinnerNumberModel(value, min, max, step));
GridBagConstraints gbc_spinner = new GridBagConstraints();
gbc_spinner.anchor = GridBagConstraints.WEST;
gbc_spinner.insets = new Insets(1, 5, 1, 1);
gbc_spinner.gridx = column;
gbc_spinner.gridy = row;
dataPanel.add(spinner, gbc_spinner);
return spinner;
}
private void addButton(int row, int column, String name, String action) {
JButton button = new JButton(name);
GridBagConstraints gbc_button = new GridBagConstraints();
gbc_button.anchor = GridBagConstraints.EAST;
gbc_button.insets = new Insets(1, 5, 1, 1);
gbc_button.gridx = column;
gbc_button.gridy = row;
button.setActionCommand(action);
button.addActionListener(this);
dataPanel.add(button, gbc_button);
}
/**
* Methods sets the axis table from axis array if they have been set before
*/
private void setAxisTables() {
try {
if (xAxisArray.size() > 0) {
Utils.ensureColumnCount(xAxisArray.size(), xAxisTable);
Utils.clearTable(xAxisTable);
for (int i = 0; i < xAxisArray.size(); ++i)
xAxisTable.setValueAt(xAxisArray.get(i), 0, i);
for (int i = xAxisTable.getColumnCount() - 1; i >= 0 && xAxisTable.getValueAt(0, i).toString().equals(""); --i)
Utils.removeColumn(i, xAxisTable);
}
if (yAxisArray.size() > 0) {
Utils.ensureColumnCount(yAxisArray.size(), yAxisTable);
Utils.clearTable(yAxisTable);
for (int i = 0; i < yAxisArray.size(); ++i)
yAxisTable.setValueAt(yAxisArray.get(i), 0, i);
for (int i = yAxisTable.getColumnCount() - 1; i >= 0 && yAxisTable.getValueAt(0, i).toString().equals(""); --i)
Utils.removeColumn(i, yAxisTable);
}
}
catch (Exception e) {
logger.error(e);
}
}
/**
* Method validates that all data is populated and valid.
* @return
*/
private boolean validateTemplateData() {
try {
if (!Utils.validateTableHeader(templateTable))
return false;
Utils.colorTableHeaders(templateTable);
// copy axis
Utils.clearTable(xAxisTable);
Utils.clearTable(yAxisTable);
Utils.ensureColumnCount(templateTable.getColumnCount() - 1, xAxisTable);
Utils.ensureColumnCount(templateTable.getRowCount() - 1, yAxisTable);
for (int i = 1; i < templateTable.getColumnCount(); ++i)
xAxisTable.setValueAt(templateTable.getValueAt(0, i), 0, i - 1);
for (int i = 1; i < templateTable.getRowCount(); ++i)
yAxisTable.setValueAt(templateTable.getValueAt(i, 0), 0, i - 1);
// remove extra columns
for (int i = xAxisTable.getColumnCount() - 1; i >= 0 && xAxisTable.getValueAt(0, i).toString().equals(""); --i)
Utils.removeColumn(i, xAxisTable);
for (int i = yAxisTable.getColumnCount() - 1; i >= 0 && yAxisTable.getValueAt(0, i).toString().equals(""); --i)
Utils.removeColumn(i, yAxisTable);
return true;
}
catch (Exception e) {
logger.error(e);
JOptionPane.showMessageDialog(null, e, "Error validation table data", JOptionPane.ERROR_MESSAGE);
}
return false;
}
/**
* Methods saves axis table into config and adds a menu item in the template dropdown
* @param type
*/
private void save(Axis type) {
try {
JTable axisTable = xAxisTable;
JComboBox<String> axisList = xAxisList;
if (type == Axis.YAXIS) {
axisTable = yAxisTable;
axisList = yAxisList;
}
if (Utils.isTableEmpty(axisTable)) {
JOptionPane.showMessageDialog(null, "Table is empty or not properly populated", "Error", JOptionPane.ERROR_MESSAGE);
return;
}
String axisName = "";
JTextField nameTextField = new JTextField();
JComponent[] inputs = new JComponent[] { new JLabel("Set unique name"), nameTextField };
do {
if (JOptionPane.OK_OPTION != JOptionPane.showConfirmDialog(null, inputs, "Axis template name", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE))
return;
axisName = nameTextField.getText().trim();
boolean found = false;
for (int i = 0; i < xAxisList.getItemCount() && !found; ++i) {
if (xAxisList.getItemAt(i).toString().equals(axisName))
found = true;
}
if (found) {
JOptionPane.showMessageDialog(null, "This name is being used for X-Axis template", "Error", JOptionPane.ERROR_MESSAGE);
axisName = "";
}
else {
for (int i = 0; i < yAxisList.getItemCount() && !found; ++i) {
if (yAxisList.getItemAt(i).toString().equals(axisName))
found = true;
}
if (found) {
JOptionPane.showMessageDialog(null, "This name is being used for Y-Axis template", "Error", JOptionPane.ERROR_MESSAGE);
axisName = "";
}
}
}
while (axisName.isEmpty());
String axisValues = "";
String val;
int i = 0;
for (; i < axisTable.getColumnCount(); ++i) {
val = axisTable.getValueAt(0, i).toString();
if (val.isEmpty())
break;
else if (!Pattern.matches(Utils.fpRegex, val)) {
JOptionPane.showMessageDialog(null, "Invalid data in table, column " + (i + 1), "Error", JOptionPane.ERROR_MESSAGE);
return;
}
if (i > 0)
axisValues += ",";
axisValues += val;
}
for (; i < axisTable.getColumnCount(); ++i)
axisTable.setValueAt("", 0, i);
if (type == Axis.XAXIS) {
String s = Config.getXAxisTemplates();
if (s.endsWith(","))
Config.setXAxisTemplates(s + axisName);
else
Config.setXAxisTemplates(s + "," + axisName);
}
else {
String s = Config.getYAxisTemplates();
if (s.endsWith(","))
Config.setYAxisTemplates(s + axisName);
else
Config.setYAxisTemplates(s + "," + axisName);
}
Config.setProperty(axisName, axisValues);
if (axisList.getItemCount() == 0)
axisList.addItem("");
axisList.addItem(axisName);
axisList.setSelectedItem(axisName);
}
catch (Exception e) {
logger.error(e);
JOptionPane.showMessageDialog(null, e, "Error saving axis", JOptionPane.ERROR_MESSAGE);
}
}
/**
* Method removes current axis template from templates dropdown and config
* @param type
*/
private void remove(Axis type) {
try {
String newNames = "";
String[] axisNames = Config.getXAxisTemplates().split(",");
JComboBox<String> axisList = xAxisList;
if (type == Axis.YAXIS) {
axisList = yAxisList;
axisNames = Config.getYAxisTemplates().split(",");
}
if (axisList.getSelectedItem() == null)
return;
String axisName = axisList.getSelectedItem().toString();
if (axisName.isEmpty())
return;
if (axisList.getItemCount() == 0)
axisList.addItem("");
axisList.setSelectedItem("");
axisList.removeItem(axisName);
Config.removeProperty(axisName);
for (String s : axisNames) {
if (s.isEmpty() || s.equals(axisName))
continue;
newNames += ("," + s);
}
if (newNames.isEmpty())
newNames = ",";
if (type == Axis.XAXIS)
Config.setXAxisTemplates(newNames);
else
Config.setYAxisTemplates(newNames);
}
catch (Exception e) {
logger.error(e);
JOptionPane.showMessageDialog(null, e, "Error removing axis template", JOptionPane.ERROR_MESSAGE);
}
}
/**
* Method loads from config selected axis template into axis table
* @param type
*/
private void load(Axis type) {
try {
JTable axisTable = xAxisTable;
JComboBox<String> axisList = xAxisList;
if (type == Axis.YAXIS) {
axisTable = yAxisTable;
axisList = yAxisList;
}
if (axisList.getSelectedItem() == null)
return;
String axisName = axisList.getSelectedItem().toString();
if (axisName.isEmpty())
return;
String[] values = Config.getProperty(axisName).split(",");
Utils.ensureColumnCount(values.length, axisTable);
Utils.clearTable(axisTable);
for (int i = 0; i < values.length; ++i)
axisTable.setValueAt(values[i], 0, i);
for (int i = axisTable.getColumnCount() - 1; i >= 0 && axisTable.getValueAt(0, i).toString().equals(""); --i)
Utils.removeColumn(i, axisTable);
}
catch (Exception e) {
logger.error(e);
JOptionPane.showMessageDialog(null, e, "Error load axis template", JOptionPane.ERROR_MESSAGE);
}
}
/**
* Methods validates axis table and makes sure at least one axes is specified
* @return
*/
private boolean validateAxisData() {
try {
if (Utils.isTableEmpty(xAxisTable) && Utils.isTableEmpty(yAxisTable)) {
JOptionPane.showMessageDialog(null, "Both axis tables are either empty or not properly populated", "Error", JOptionPane.ERROR_MESSAGE);
return false;
}
String val;
int i = 0;
ArrayList<Double> tempArray = new ArrayList<Double>();
if (!Utils.isTableEmpty(xAxisTable)) {
for (i = 0; i < xAxisTable.getColumnCount(); ++i) {
val = xAxisTable.getValueAt(0, i).toString();
if (val.isEmpty())
break;
else if (!Pattern.matches(Utils.fpRegex, val)) {
JOptionPane.showMessageDialog(null, "Invalid data in X-Axis table, column " + (i + 1), "Error", JOptionPane.ERROR_MESSAGE);
return false;
}
tempArray.add(Double.valueOf(val));
}
for (; i < xAxisTable.getColumnCount(); ++i)
xAxisTable.setValueAt("", 0, i);
xAxisArray.clear();
for (Double d : tempArray)
xAxisArray.add(d);
Collections.sort(xAxisArray);
}
tempArray.clear();
if (!Utils.isTableEmpty(yAxisTable)) {
for (i = 0; i < yAxisTable.getColumnCount(); ++i) {
val = yAxisTable.getValueAt(0, i).toString();
if (val.isEmpty())
break;
if (!Pattern.matches(Utils.fpRegex, val)) {
JOptionPane.showMessageDialog(null, "Invalid data in Y-Axis table, column " + (i + 1), "Error", JOptionPane.ERROR_MESSAGE);
return false;
}
tempArray.add(Double.valueOf(val));
}
for (; i < yAxisTable.getColumnCount(); ++i)
yAxisTable.setValueAt("", 0, i);
yAxisArray.clear();
for (Double d : tempArray)
yAxisArray.add(d);
Collections.sort(yAxisArray);
}
distance.set(0, (Integer)distanceSpinner.getValue());
return true;
}
catch (Exception e) {
logger.error(e);
JOptionPane.showMessageDialog(null, e, "Error setting axis", JOptionPane.ERROR_MESSAGE);
}
return false;
}
@Override
public void actionPerformed(ActionEvent e) {
if ("clearxaxis".equals(e.getActionCommand())) {
xAxisTable.setModel(new DefaultTableModel(1, AxisColumnCount));
Utils.initializeTable(xAxisTable, ColumnWidth);
xAxisList.setSelectedIndex(-1);
}
else if ("clearyaxis".equals(e.getActionCommand())) {
yAxisTable.setModel(new DefaultTableModel(1, AxisColumnCount));
Utils.initializeTable(yAxisTable, ColumnWidth);
yAxisList.setSelectedIndex(-1);
}
else if ("cleartempl".equals(e.getActionCommand()))
Utils.clearTable(templateTable);
else if ("validate".equals(e.getActionCommand()))
validateTemplateData();
else if ("savexaxis".equals(e.getActionCommand()))
save(Axis.XAXIS);
else if ("saveyaxis".equals(e.getActionCommand()))
save(Axis.YAXIS);
else if ("remxtempl".equals(e.getActionCommand()))
remove(Axis.XAXIS);
else if ("remytempl".equals(e.getActionCommand()))
remove(Axis.YAXIS);
else if ("xaxis".equals(e.getActionCommand()))
load(Axis.XAXIS);
else if ("yaxis".equals(e.getActionCommand()))
load(Axis.YAXIS);
}
}