/*
* 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.maps;
import static com.romraider.util.ParamChecker.isNullOrEmpty;
import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.KeyListener;
import java.io.IOException;
import java.util.StringTokenizer;
import javax.naming.NameNotFoundException;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import com.romraider.Settings;
import com.romraider.editor.ecu.ECUEditorManager;
import com.romraider.util.SettingsManager;
public class Table2D extends Table {
private static final long serialVersionUID = -7684570967109324784L;
private Table1D axis = new Table1D();
private JLabel axisLabel;
private CopyTable2DWorker copyTable2DWorker;
private CopySelection2DWorker copySelection2DWorker;
public Table2D() {
super();
verticalOverhead += 18;
}
public Table1D getAxis() {
return axis;
}
public void setAxis(Table1D axis) {
this.axis = axis;
axis.setAxisParent(this);
}
@Override
public String toString() {
return super.toString() + " (2D)";// + axis;
}
@Override
public void populateCompareValues(Table otherTable) {
if(null == otherTable || !(otherTable instanceof Table2D)) {
return;
}
Table2D compareTable2D = (Table2D) otherTable;
if(data.length != compareTable2D.data.length ||
axis.data.length != compareTable2D.axis.data.length) {
return;
}
super.populateCompareValues(otherTable);
axis.populateCompareValues(compareTable2D.getAxis());
}
@Override
public void refreshCompare() {
populateCompareValues(getCompareTable());
axis.refreshCompare();
}
@Override
public StringBuffer getTableAsString() {
StringBuffer output = new StringBuffer(Settings.BLANK);
output.append(axis.getTableAsString());
output.append(Settings.NEW_LINE);
output.append(super.getTableAsString());
return output;
}
@Override
public Dimension getFrameSize() {
int height = verticalOverhead + cellHeight * 2;
int width = horizontalOverhead + data.length * cellWidth;
if (height < minHeight) {
height = minHeight;
}
int minWidth = isLiveDataSupported() ? minWidthOverlay : minWidthNoOverlay;
if (width < minWidth) {
width = minWidth;
}
return new Dimension(width, height);
}
@Override
public void populateTable(byte[] input, int romRamOffset) throws ArrayIndexOutOfBoundsException, IndexOutOfBoundsException {
centerLayout.setRows(2);
centerLayout.setColumns(this.getDataSize());
try {
axis.populateTable(input, romRamOffset);
super.populateTable(input, romRamOffset);
} catch (ArrayIndexOutOfBoundsException ex) {
throw new ArrayIndexOutOfBoundsException();
}
// add to table
for (int i = 0; i < this.getDataSize(); i++) {
centerPanel.add(axis.getDataCell(i));
}
if (flip) {
for (int i = this.getDataSize() - 1; i >= 0; i--) {
centerPanel.add(this.getDataCell(i));
}
} else {
for (int i = 0; i < this.getDataSize(); i++) {
centerPanel.add(this.getDataCell(i));
}
}
if(null == axis.getName() || axis.getName().isEmpty() || Settings.BLANK == axis.getName()) {
;// Do not add label.
} else if(null == axis.getCurrentScale() || "0x" == axis.getCurrentScale().getUnit()) {
// static or no scale exists.
axisLabel = new JLabel(axis.getName(), JLabel.CENTER);
add(axisLabel, BorderLayout.NORTH);
} else {
axisLabel = new JLabel(axis.getName() + " (" + axis.getCurrentScale().getUnit() + ")", JLabel.CENTER);
add(axisLabel, BorderLayout.NORTH);
}
tableLabel = new JLabel(getCurrentScale().getUnit(), JLabel.CENTER);
add(tableLabel, BorderLayout.SOUTH);
repaint();
}
@Override
public void updateTableLabel() {
if(null == axis.getName() || axis.getName().length() < 1 || Settings.BLANK == axis.getName()) {
;// Do not update label.
} else if(null == axis.getCurrentScale() || "0x" == axis.getCurrentScale().getUnit()) {
// static or no scale exists.
axisLabel.setText(axis.getName());
} else {
axisLabel.setText(axis.getName() + " (" + axis.getCurrentScale().getUnit() + ")");
}
tableLabel.setText(getCurrentScale().getUnit());
}
@Override
public void clearSelection() {
axis.clearSelectedData();
clearSelectedData();
}
@Override
public void setRevertPoint() {
super.setRevertPoint();
axis.setRevertPoint();
}
@Override
public void undoAll() {
super.undoAll();
axis.undoAll();
}
@Override
public byte[] saveFile(byte[] binData) {
binData = super.saveFile(binData);
binData = axis.saveFile(binData);
return binData;
}
@Override
public void addKeyListener(KeyListener listener) {
super.addKeyListener(listener);
axis.addKeyListener(listener);
}
@Override
public void cursorUp() {
if (data[highlightY].isSelected()) {
axis.selectCellAt(highlightY);
}
}
@Override
public void drawTable() {
super.drawTable();
axis.drawTable();
}
@Override
public void cursorDown() {
axis.cursorDown();
}
@Override
public void cursorLeft() {
if (highlightY > 0 && data[highlightY].isSelected()) {
selectCellAt(highlightY - 1);
} else {
axis.cursorLeft();
}
}
@Override
public void cursorRight() {
if (highlightY < data.length - 1 && data[highlightY].isSelected()) {
selectCellAt(highlightY + 1);
} else {
axis.cursorRight();
}
}
@Override
public void shiftCursorUp() {
if (data[highlightY].isSelected()) {
data[highlightY].setSelected(false);
}
axis.selectCellAt(highlightY);
}
@Override
public void shiftCursorDown() {
axis.cursorDown();
}
@Override
public void shiftCursorLeft() {
if (highlightY > 0 && data[highlightY].isSelected()) {
selectCellAtWithoutClear(highlightY - 1);
} else {
axis.shiftCursorLeft();
}
}
@Override
public void shiftCursorRight() {
if (highlightY < data.length - 1 && data[highlightY].isSelected()) {
selectCellAtWithoutClear(highlightY + 1);
} else {
axis.shiftCursorRight();
}
}
@Override
public void startHighlight(int x, int y) {
axis.clearSelectedData();
super.startHighlight(x, y);
}
@Override
public void copySelection() {
Window ancestorWindow = SwingUtilities.getWindowAncestor(this);
if(null != ancestorWindow) {
ancestorWindow.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
}
ECUEditorManager.getECUEditor().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
super.copySelection();
copySelection2DWorker = new CopySelection2DWorker(this);
copySelection2DWorker.execute();
}
@Override
public void copyTable() {
Window ancestorWindow = SwingUtilities.getWindowAncestor(this);
if(null != ancestorWindow) {
ancestorWindow.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
}
ECUEditorManager.getECUEditor().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
copyTable2DWorker = new CopyTable2DWorker(this);
copyTable2DWorker.execute();
}
@Override
public void paste() {
StringTokenizer st = new StringTokenizer(Settings.BLANK);
String input = Settings.BLANK;
try {
input = (String) Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null).getTransferData(DataFlavor.stringFlavor);
st = new StringTokenizer(input, ST_DELIMITER);
} catch (UnsupportedFlavorException ex) { /* wrong paste type -- do nothing */
} catch (IOException ex) {
}
String pasteType = st.nextToken();
if (pasteType.equalsIgnoreCase("[Table2D]")) { // Paste table
String currentToken = st.nextToken(Settings.NEW_LINE);
if (currentToken.endsWith("\t")) {
currentToken = st.nextToken(Settings.NEW_LINE);
}
String axisValues = "[Table1D]" + Settings.NEW_LINE + currentToken;
String dataValues = "[Table1D]" + Settings.NEW_LINE + st.nextToken(Settings.NEW_LINE);
// put axis in clipboard and paste
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(axisValues), null);
axis.paste();
// put datavalues in clipboard and paste
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(dataValues), null);
super.paste();
// reset clipboard
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(input), null);
} else if (pasteType.equalsIgnoreCase("[Selection1D]")) { // paste selection
if (data[highlightY].isSelected()) {
super.paste();
} else {
axis.paste();
}
}
}
@Override
public void interpolate() {
super.interpolate();
this.getAxis().interpolate();
}
@Override
public void verticalInterpolate() {
super.verticalInterpolate();
this.getAxis().verticalInterpolate();
}
@Override
public void horizontalInterpolate() {
int[] coords = { getDataSize(), 0};
DataCell[] tableData = getData();
DataCell[] axisData = getAxis().getData();
for (int i = 0; i < getDataSize(); ++i) {
if (tableData[i].isSelected()) {
if (i < coords[0])
coords[0] = i;
if (i > coords[1])
coords[1] = i;
}
}
if (coords[1] - coords[0] > 1) {
double x, x1, x2, y1, y2;
x1 = axisData[coords[0]].getBinValue();
y1 = tableData[coords[0]].getBinValue();
x2 = axisData[coords[1]].getBinValue();
y2 = tableData[coords[1]].getBinValue();
for (int i = coords[0] + 1; i < coords[1]; ++i) {
x = axisData[i].getBinValue();
data[i].setBinValue(linearInterpolation(x, x1, x2, y1, y2));
}
}
// Interpolate x axis in case the x axis in selected.
this.getAxis().horizontalInterpolate();
}
@Override
public boolean isLiveDataSupported() {
return !isNullOrEmpty(axis.getLogParam());
}
@Override
public boolean isButtonSelected() {
return true;
}
@Override
public void clearLiveDataTrace() {
super.clearLiveDataTrace();
axis.clearLiveDataTrace();
}
@Override
public void updateLiveDataHighlight() {
if (getOverlayLog()) {
data[axis.getLiveDataIndex()].setLiveDataTrace(true);
}
}
@Override
public String getLogParamString() {
StringBuilder sb = new StringBuilder();
sb.append(axis.getLogParamString()+ ", ");
sb.append(getName()+ ":" + getLogParam());
return sb.toString();
}
@Override
public void setOverlayLog(boolean overlayLog) {
super.setOverlayLog(overlayLog);
axis.setOverlayLog(overlayLog);
}
@Override
public void setCompareDisplay(int compareDisplay) {
super.setCompareDisplay(compareDisplay);
axis.setCompareDisplay(compareDisplay);
}
@Override
public void setCompareValueType(int compareValueType) {
super.setCompareValueType(compareValueType);
axis.setCompareValueType(compareValueType);
}
@Override
public void setCurrentScale(Scale curScale) {
if(SettingsManager.getSettings().isScaleHeadersAndData() && !axis.isStaticDataTable()) {
try {
this.axis.setScaleByName(curScale.getName());
} catch (NameNotFoundException e) {
try {
this.axis.setScaleByName(SettingsManager.getSettings().getDefaultScale());
} catch (NameNotFoundException e1) {
}
}
}
this.curScale = curScale;
updateTableLabel();
drawTable();
}
@Override
public boolean equals(Object other) {
try {
if(null == other) {
return false;
}
if(other == this) {
return true;
}
if(!(other instanceof Table2D)) {
return false;
}
Table2D otherTable = (Table2D)other;
if( (null == this.getName() && null == otherTable.getName())
|| (this.getName().isEmpty() && otherTable.getName().isEmpty()) ) {
;// Skip name compare if name is null or empty.
} else if (!this.getName().equalsIgnoreCase(otherTable.getName())) {
return false;
}
if(!this.axis.equals(otherTable.axis)) {
return false;
}
if(this.data.length != otherTable.data.length)
{
return false;
}
if(this.data.equals(otherTable.data))
{
return true;
}
// Compare Bin Values
for(int i = 0 ; i < this.data.length ; i++) {
if(! this.data[i].equals(otherTable.data[i])) {
return false;
}
}
return true;
} catch(Exception ex) {
// TODO: Log Exception.
return false;
}
}
@Override
public void repaint() {
super.repaint();
if(null != axis) {
axis.repaint();
}
}
}
class CopySelection2DWorker extends SwingWorker<Void, Void> {
Table2D table;
Table extendedTable;
public CopySelection2DWorker(Table2D table)
{
this.table = table;
}
@Override
protected Void doInBackground() throws Exception {
table.getAxis().copySelection();
return null;
}
@Override
public void done() {
Window ancestorWindow = SwingUtilities.getWindowAncestor(table);
if(null != ancestorWindow) {
ancestorWindow.setCursor(null);
}
table.setCursor(null);
ECUEditorManager.getECUEditor().setCursor(null);
}
}
class CopyTable2DWorker extends SwingWorker<Void, Void> {
Table2D table;
public CopyTable2DWorker(Table2D table)
{
this.table = table;
}
@Override
protected Void doInBackground() throws Exception {
String tableHeader = table.getSettings().getTable2DHeader();
StringBuffer output = new StringBuffer(tableHeader);
output.append(table.getTableAsString());
//copy to clipboard
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(output.toString()), null);
return null;
}
@Override
public void done() {
Window ancestorWindow = SwingUtilities.getWindowAncestor(table);
if(null != ancestorWindow) {
ancestorWindow.setCursor(null);
}
table.setCursor(null);
ECUEditorManager.getECUEditor().setCursor(null);
}
}