/* * RomRaider Open-Source Tuning, Logging and Reflashing * Copyright (C) 2006-2017 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.swing; import static com.romraider.Settings.COMMA; import static javax.swing.BorderFactory.createLineBorder; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Image; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.beans.PropertyVetoException; import java.math.BigDecimal; import java.net.URL; import java.text.DecimalFormat; import java.text.ParseException; import java.util.Vector; import javax.naming.NameNotFoundException; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.InputMap; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JFormattedTextField; import javax.swing.JInternalFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextArea; import javax.swing.JToolBar; import javax.swing.KeyStroke; import javax.swing.border.Border; import javax.swing.border.TitledBorder; import org.apache.log4j.Logger; import com.ecm.graphics.Graph3dFrameManager; import com.ecm.graphics.data.GraphData; import com.ecm.graphics.data.GraphDataListener; import com.romraider.Settings; import com.romraider.editor.ecu.ECUEditorManager; import com.romraider.maps.DataCell; import com.romraider.maps.Scale; import com.romraider.maps.Table; import com.romraider.maps.Table1D; import com.romraider.maps.Table3D; import com.romraider.util.NumberUtil; import com.romraider.util.SettingsManager; public class TableToolBar extends JToolBar implements MouseListener, ItemListener, ActionListener, GraphDataListener { private static final long serialVersionUID = 8697645329367637930L; private static final Logger LOGGER = Logger.getLogger(TableToolBar.class); private final JButton incrementFine = new JButton(); private final JButton decrementFine = new JButton(); private final JButton incrementCoarse = new JButton(); private final JButton decrementCoarse = new JButton(); private final JButton enable3d = new JButton(); private final JButton colorCells = new JButton(); private final JButton refreshCompare = new JButton(); private final JButton setValue = new JButton("Set"); private final JButton multiply = new JButton("Mul"); private final JFormattedTextField incrementByFine = new JFormattedTextField(new DecimalFormat("#.####")); private final JFormattedTextField incrementByCoarse = new JFormattedTextField(new DecimalFormat("#.####")); private final JFormattedTextField setValueText = new JFormattedTextField(new DecimalFormat("#.####")); private final JComboBox scaleSelection = new JComboBox(); private final JPanel liveDataPanel = new JPanel(); private final JCheckBox overlayLog = new JCheckBox("Overlay Log"); private final JButton clearOverlay = new JButton("Clear Overlay"); private final JLabel liveDataValue = new JLabel(); private final URL incrementFineImage = getClass().getResource("/graphics/icon-incfine.png"); private final URL decrementFineImage = getClass().getResource("/graphics/icon-decfine.png"); private final URL incrementCoarseImage = getClass().getResource("/graphics/icon-inccoarse.png"); private final URL decrementCoarseImage = getClass().getResource("/graphics/icon-deccoarse.png"); private final URL enable3dImage = getClass().getResource("/graphics/3d_render.png"); private final URL colorCellImage = getClass().getResource("/graphics/icon-palette.png"); private final URL refreshCompareImage = getClass().getResource("/graphics/table_refresh.png"); private final TitledBorder toolbarBorder = BorderFactory.createTitledBorder(Settings.defaultTableToolBarName); private Table selectedTable = null; public TableToolBar() { super(Settings.defaultTableToolBarName); this.setFloatable(true); this.setRollover(true); FlowLayout toolBarLayout = new FlowLayout(FlowLayout.LEFT, 0, 0); this.setLayout(toolBarLayout); setBorder(toolbarBorder); this.updateIcons(); JPanel finePanel = new JPanel(); finePanel.add(incrementFine); finePanel.add(decrementFine); finePanel.add(incrementByFine); this.add(finePanel); JPanel coarsePanel = new JPanel(); coarsePanel.add(incrementCoarse); coarsePanel.add(decrementCoarse); coarsePanel.add(incrementByCoarse); this.add(coarsePanel); JPanel setValuePanel = new JPanel(); setValuePanel.add(setValueText); setValuePanel.add(setValue); setValuePanel.add(multiply); this.add(setValuePanel); colorCells.setEnabled(false); refreshCompare.setEnabled(false); enable3d.setEnabled(false); JPanel otherPanel = new JPanel(); otherPanel.add(colorCells); otherPanel.add(refreshCompare); otherPanel.add(enable3d); this.add(otherPanel); JPanel scaleSelectionPanel = new JPanel(); scaleSelectionPanel.add(scaleSelection); this.add(scaleSelectionPanel); incrementFine.setBorder(createLineBorder(new Color(150, 150, 150), 1)); decrementFine.setBorder(createLineBorder(new Color(150, 150, 150), 1)); incrementCoarse.setBorder(createLineBorder(new Color(150, 150, 150), 1)); decrementCoarse.setBorder(createLineBorder(new Color(150, 150, 150), 1)); enable3d.setBorder(createLineBorder(new Color(150, 150, 150), 1)); setValue.setPreferredSize(new Dimension(33, 23)); setValue.setBorder(createLineBorder(new Color(150, 150, 150), 1)); multiply.setPreferredSize(new Dimension(33, 23)); multiply.setBorder(createLineBorder(new Color(150, 150, 150), 1)); colorCells.setBorder(createLineBorder(new Color(150, 150, 150), 1)); refreshCompare.setBorder(createLineBorder(new Color(150, 150, 150), 1)); scaleSelection.setPreferredSize(new Dimension(80, 23)); clearOverlay.setPreferredSize(new Dimension(75, 23)); clearOverlay.setBorder(createLineBorder(new Color(150, 150, 150), 1)); incrementByFine.setAlignmentX(JTextArea.CENTER_ALIGNMENT); incrementByFine.setAlignmentY(JTextArea.CENTER_ALIGNMENT); incrementByFine.setPreferredSize(new Dimension(45, 23)); incrementByCoarse.setAlignmentX(JTextArea.CENTER_ALIGNMENT); incrementByCoarse.setAlignmentY(JTextArea.CENTER_ALIGNMENT); incrementByCoarse.setPreferredSize(new Dimension(45, 23)); setValueText.setAlignmentX(JTextArea.CENTER_ALIGNMENT); setValueText.setAlignmentY(JTextArea.CENTER_ALIGNMENT); setValueText.setPreferredSize(new Dimension(45, 23)); incrementFine.setToolTipText("Increment Value (Fine)"); decrementFine.setToolTipText("Decrement Value (Fine)"); incrementCoarse.setToolTipText("Increment Value (Coarse)"); decrementCoarse.setToolTipText("Decrement Value (Coarse)"); enable3d.setToolTipText("Render data in 3d"); setValue.setToolTipText("Set Absolute Value"); setValueText.setToolTipText("Set Absolute Value"); incrementByFine.setToolTipText("Fine Value Adjustment"); incrementByCoarse.setToolTipText("Coarse Value Adjustment"); multiply.setToolTipText("Multiply Value"); overlayLog.setToolTipText("Enable Overlay Of Real Time Log Data"); clearOverlay.setToolTipText("Clear Log Data Overlay Highlights"); colorCells.setToolTipText("Color Table Cells"); refreshCompare.setToolTipText("Refresh Table Compare"); incrementFine.addMouseListener(this); decrementFine.addMouseListener(this); incrementCoarse.addMouseListener(this); decrementCoarse.addMouseListener(this); enable3d.addMouseListener(this); setValue.addMouseListener(this); multiply.addMouseListener(this); scaleSelection.addItemListener(this); overlayLog.addItemListener(this); clearOverlay.addActionListener(this); colorCells.addMouseListener(this); refreshCompare.addMouseListener(this); // key binding actions Action enterAction = new AbstractAction() { private static final long serialVersionUID = -6008026264821746092L; @Override public void actionPerformed(ActionEvent e) { JInternalFrame selectedFrame = ECUEditorManager.getECUEditor().getRightPanel().getSelectedFrame(); if(selectedFrame == null || !(selectedFrame instanceof TableFrame)) { return; } TableFrame frame = (TableFrame)selectedFrame; frame.toFront(); try { frame.setSelected(true); } catch (PropertyVetoException ex) { } frame.requestFocusInWindow(); setValue(frame.getTable()); } }; // set input mapping InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW); KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0); im.put(enter, "enterAction"); getActionMap().put(im.get(enter), enterAction); liveDataPanel.add(overlayLog); liveDataPanel.add(clearOverlay); //liveDataPanel.add(liveDataValue); this.add(liveDataPanel); overlayLog.setEnabled(false); clearOverlay.setEnabled(false); incrementFine.getInputMap().put(enter, "enterAction"); decrementFine.getInputMap().put(enter, "enterAction"); incrementCoarse.getInputMap().put(enter, "enterAction"); decrementCoarse.getInputMap().put(enter, "enterAction"); incrementByFine.getInputMap().put(enter, "enterAction"); incrementByCoarse.getInputMap().put(enter, "enterAction"); setValueText.getInputMap().put(enter, "enterAction"); setValue.getInputMap().put(enter, "enterAction"); this.setEnabled(true); } public void updateIcons() { Settings settings = SettingsManager.getSettings(); incrementFine.setIcon(rescaleImageIcon(new ImageIcon(incrementFineImage), settings.getTableIconScale())); decrementFine.setIcon(rescaleImageIcon(new ImageIcon(decrementFineImage), settings.getTableIconScale())); incrementCoarse.setIcon(rescaleImageIcon(new ImageIcon(incrementCoarseImage), settings.getTableIconScale())); decrementCoarse.setIcon(rescaleImageIcon(new ImageIcon(decrementCoarseImage), settings.getTableIconScale())); enable3d.setIcon(rescaleImageIcon(new ImageIcon(enable3dImage), settings.getTableIconScale())); colorCells.setIcon(rescaleImageIcon(new ImageIcon(colorCellImage), settings.getTableIconScale())); refreshCompare.setIcon(rescaleImageIcon(new ImageIcon(refreshCompareImage), settings.getTableIconScale())); } private ImageIcon rescaleImageIcon(ImageIcon imageIcon, int percentOfOriginal) { int newHeight = (int) (imageIcon.getImage().getHeight(this) * (percentOfOriginal * .01)); int newWidth = (int) (imageIcon.getImage().getWidth(this) * (percentOfOriginal * .01)); imageIcon.setImage(imageIcon.getImage().getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH)); return imageIcon; } public Table getTable() { JInternalFrame frame = ECUEditorManager.getECUEditor().getRightPanel().getSelectedFrame(); if(null == frame) { return null; } if( !(frame instanceof TableFrame) ) { return null; } return ((TableFrame)frame).getTable(); } @Override public void setBorder(Border border) { if(SettingsManager.getSettings().isShowTableToolbarBorder()) { super.setBorder(toolbarBorder); } else { super.setBorder(BorderFactory.createEmptyBorder()); } } public void updateTableToolBar() { this.updateTableToolBar(getTable()); } public void updateTableToolBar(Table selectedTable) { if(selectedTable == null && this.selectedTable == null) { // Skip if the table is the same to avoid multiple updates return; } else if(selectedTable == null || this.selectedTable == null) { // Update the toolbar. } else if(this.selectedTable.equals(selectedTable)) { // Skip if the table is the same to avoid multiple updates return; } this.selectedTable = selectedTable; setBorder(toolbarBorder); if(null == selectedTable) { // disable the toolbar. toggleTableToolBar(selectedTable); return; } updateToolbarIncrementDecrementValues(); this.overlayLog.setSelected(selectedTable.getOverlayLog()); this.enable3d.setEnabled(selectedTable.getType() == Settings.TABLE_3D); setScales(selectedTable.getScales()); if(null == selectedTable.getCurrentScale()) { this.scaleSelection.setSelectedItem("Default"); } else { this.scaleSelection.setSelectedItem(selectedTable.getCurrentScale().getName()); } toggleTableToolBar(selectedTable); } private void updateToolbarIncrementDecrementValues() { if(null == selectedTable) { return; } double fineIncrement = 0; double coarseIncrement = 0; try { // enable the toolbar. fineIncrement = Math.abs(selectedTable.getCurrentScale().getFineIncrement()); coarseIncrement = Math.abs(selectedTable.getCurrentScale().getCoarseIncrement()); } catch (Exception ex) { // scaling units haven't been added yet -- no problem } incrementByFine.setValue(fineIncrement); incrementByCoarse.setValue(coarseIncrement); } private void toggleTableToolBar(Table currentTable) { String newTitle = ""; boolean enabled; if(null == currentTable) { enabled = false; } else { if(currentTable instanceof Table1D) { Table1D cur1DTable = (Table1D)currentTable; if(cur1DTable.isAxis()) { newTitle = cur1DTable.getAxisParent().getName() + " ("+ cur1DTable.getName() +")"; } else { newTitle = currentTable.getName(); } } else { newTitle = currentTable.getName(); } enabled = true; } toolbarBorder.setTitle(newTitle); incrementFine.setEnabled(enabled); decrementFine.setEnabled(enabled); incrementCoarse.setEnabled(enabled); decrementCoarse.setEnabled(enabled); setValue.setEnabled(enabled); multiply.setEnabled(enabled); incrementByFine.setEnabled(enabled); incrementByCoarse.setEnabled(enabled); setValueText.setEnabled(enabled); scaleSelection.setEnabled(enabled); liveDataValue.setEnabled(enabled); colorCells.setEnabled(enabled); refreshCompare.setEnabled(enabled); //Only enable the 3d button if table includes 3d data if (null != currentTable && currentTable.getType() == Settings.TABLE_3D && enabled) { enable3d.setEnabled(true); } else{ enable3d.setEnabled(false); } if(null != currentTable && null != currentTable.getCompareTable() && enabled) { refreshCompare.setEnabled(true); } else { refreshCompare.setEnabled(false); } if (null != currentTable && currentTable.isLiveDataSupported() && enabled) { overlayLog.setEnabled(true); clearOverlay.setEnabled(true); } else{ overlayLog.setEnabled(false); clearOverlay.setEnabled(false); } if(null != currentTable && currentTable.isStaticDataTable()) { if(enabled) { scaleSelection.setEnabled(true); } else { scaleSelection.setEnabled(false); } // Disable everything that does not apply to static value tables. colorCells.setEnabled(false); refreshCompare.setEnabled(false); incrementFine.setEnabled(false); decrementFine.setEnabled(false); incrementCoarse.setEnabled(false); decrementCoarse.setEnabled(false); incrementByFine.setEnabled(false); incrementByCoarse.setEnabled(false); setValue.setEnabled(false); setValueText.setEnabled(false); multiply.setEnabled(false); enable3d.setEnabled(false); } repaint(); } public void setScales(Vector<Scale> scales) { // remove item listener to avoid null pointer exception when populating scaleSelection.removeItemListener(this); scaleSelection.removeAllItems(); for (Scale scale : scales) { scaleSelection.addItem(scale.getName()); } // and put it back scaleSelection.addItemListener(this); } @Override public void mouseClicked(MouseEvent e) { Table curTable = getSelectedTable(); if(null == curTable) { return; } if (e.getSource() == incrementCoarse) { incrementCoarse(curTable); } else if (e.getSource() == decrementCoarse) { decrementCoarse(curTable); } else if (e.getSource() == enable3d) { enable3d(curTable); } else if (e.getSource() == incrementFine) { incrementFine(curTable); } else if (e.getSource() == decrementFine) { decrementFine(curTable); } else if (e.getSource() == multiply) { multiply(curTable); } else if (e.getSource() == setValue) { setValue(curTable); } else if (e.getSource() == colorCells) { colorCells(curTable); } else if (e.getSource() == refreshCompare) { refreshCompare(curTable); } } public void setValue(Table currentTable) { currentTable.setRealValue(setValueText.getText()); } public void multiply() { Table curTable = getSelectedTable(); if(null == curTable) { return; } multiply(curTable); } public void multiply(Table currentTable) { try{ currentTable.multiply(NumberUtil.doubleValue(setValueText.getText())); }catch(ParseException nex) { LOGGER.error(this.getClass().getName() + ".multiply(" + currentTable + ") " + nex); } } public void incrementFine() { Table curTable = getSelectedTable(); if(null == curTable) { return; } incrementFine(curTable); } public void incrementFine(Table currentTable) { currentTable.increment(Double.parseDouble(String.valueOf(incrementByFine.getValue()))); } public void decrementFine() { Table curTable = getSelectedTable(); if(null == curTable) { return; } decrementFine(curTable); } public void decrementFine(Table currentTable) { currentTable.increment(0 - Double.parseDouble(String.valueOf(incrementByFine.getValue()))); } public void incrementCoarse() { Table curTable = getSelectedTable(); if(null == curTable) { return; } incrementCoarse(curTable); } public void incrementCoarse(Table currentTable) { currentTable.increment(Double.parseDouble(String.valueOf(incrementByCoarse.getValue()))); } public void decrementCoarse() { Table curTable = getSelectedTable(); if(null == curTable) { return; } decrementCoarse(curTable); } public void decrementCoarse(Table currentTable) { currentTable.increment(0 - Double.parseDouble(String.valueOf(incrementByCoarse.getValue()))); } /** * Method launches a 3d Frame. */ public void enable3d(Table currentTable) { int rowCount = 0; int valueCount = 0; //Pull data into format 3d graph understands Vector<float[]> graphValues = new Vector<float[]>(); graphValues.clear(); if (currentTable.getType() == Settings.TABLE_3D) { Table3D table3d = (Table3D) currentTable; DataCell[][] tableData = table3d.get3dData(); valueCount = tableData.length; DataCell[] dataRow = tableData[0]; rowCount = dataRow.length; for (int j = (rowCount - 1); j >= 0; j--) { float[] rowValues = new float[valueCount]; for (int i = 0; i < valueCount; i++) { DataCell theCell = tableData[i][j]; rowValues[i] = (float) theCell.getRealValue(); } graphValues.add(rowValues); } Table1D xAxisTable1D = table3d.getXAxis(); Table1D yAxisTable1D = table3d.getYAxis(); //Gather x axis values DataCell[] dataCells = xAxisTable1D.getData(); int length = dataCells.length; double[] xValues = new double[length]; for (int i = 0; i < length; i++) { xValues[i] = dataCells[i].getRealValue(); } //Gather y/z axis values dataCells = yAxisTable1D.getData(); length = dataCells.length; double[] yValues = new double[length]; for (int i = 0; i < length; i++) { double theValue = dataCells[i].getRealValue(); BigDecimal finalRoundedValue = new BigDecimal(theValue).setScale(2, BigDecimal.ROUND_HALF_UP); yValues[i] = finalRoundedValue.doubleValue(); } //Define Labels for graph String xLabel = table3d.getXAxis().getName(); String zLabel = table3d.getYAxis().getName(); String yLabel = table3d.getCategory(); //TODO Figure out mix between heavy weight and lightweight components //Below is initial work on making graph3d a JInternal Frame /* Graph3dJPanel graph3dJPanel = new Graph3dJPanel(graphValues, testX, testZ,xLabel, yLabel, zLabel); graph3dJPanel.addModifiedDataListener(this); JInternalFrame graphFrame = new JInternalFrame(); graphFrame.add(graph3dJPanel); graphFrame.setSize(200, 200); graphFrame.setFrameIcon(null); graphFrame.setBorder(BorderFactory.createBevelBorder(0)); graphFrame.setVisible(true); graphFrame.setDefaultCloseOperation(JInternalFrame.HIDE_ON_CLOSE); ECUEditorManager.getECUEditor().rightPanel.add(graphFrame); */ // TODO: do we want to get the max/min allowed or the max/min current? table3d.calcCellRanges(); double maxV = table3d.getMaxReal(); double minV = table3d.getMinReal(); //TODO Remove this when above is working //*********** /*minV = 0.0; maxV = 13.01;*/ LOGGER.debug("Scale: " + maxV + COMMA + minV); //*********** Graph3dFrameManager.openGraph3dFrame(graphValues, minV, maxV, xValues, yValues, xLabel, yLabel, zLabel, currentTable.getName()); GraphData.addGraphDataListener(this); } } public void colorCells(Table currentTable) { currentTable.colorCells(); } public void refreshCompare(Table currentTable) { currentTable.populateCompareValues(currentTable.getCompareTable()); } public void setCoarseValue(double input) { incrementByCoarse.setText(String.valueOf(input)); try { incrementByCoarse.commitEdit(); } catch (ParseException ex) { } } public void setFineValue(double input) { incrementByFine.setText(String.valueOf(input)); try { incrementByFine.commitEdit(); } catch (ParseException ex) { } } public void focusSetValue(char input) { setValueText.requestFocus(); setValueText.setText(String.valueOf(input)); } public void setInputMap(InputMap im) { incrementFine.setInputMap(WHEN_FOCUSED, im); decrementFine.setInputMap(WHEN_FOCUSED, im); incrementCoarse.setInputMap(WHEN_FOCUSED, im); decrementCoarse.setInputMap(WHEN_FOCUSED, im); setValue.setInputMap(WHEN_FOCUSED, im); } @Override public void mousePressed(MouseEvent e) { } @Override public void mouseReleased(MouseEvent e) { } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } @Override public void itemStateChanged(ItemEvent e) { Table curTable = getSelectedTable(); if(null == curTable) { return; } if (e.getSource() == scaleSelection) { // scale changed try { curTable.setScaleByName((String)scaleSelection.getSelectedItem()); updateToolbarIncrementDecrementValues(); } catch (NameNotFoundException e1) { e1.printStackTrace(); } } else if (e.getSource() == overlayLog) { // enable/disable log overlay and live data display curTable.setOverlayLog(overlayLog.isSelected()); } } @Override public void actionPerformed(ActionEvent e) { Table curTable = getSelectedTable(); if(null == curTable) { return; } if (e.getSource() == clearOverlay) { // clear log overlay curTable.clearLiveDataTrace(); } } public void setLiveDataValue(String value) { liveDataValue.setText(value); } // ****************************************** // Code for listening to graph3d data changes // ****************************************** @Override public void newGraphData(int x, int z, float value) { Table curTable = getSelectedTable(); if(null == curTable) { return; } if(curTable.getType() == Settings.TABLE_3D) { Table3D table3d = (Table3D) curTable; table3d.selectCellAt(x, table3d.getSizeY() - z - 1); //Set the value table3d.setRealValue(String.valueOf(value)); } } @Override public void selectStateChange(int x, int z, boolean value) { Table curTable = getSelectedTable(); if(null == curTable) { return; } if(curTable.getType() == Settings.TABLE_3D) { if (value) { Table3D table3d = (Table3D) curTable; table3d.selectCellAtWithoutClear(x, table3d.getSizeY() - z - 1); } else { Table3D table3d = (Table3D) curTable; table3d.deSelectCellAt(x, table3d.getSizeY() - z - 1); } } } public Table getSelectedTable() { return this.selectedTable; } }