/*
* 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.maps;
import static com.romraider.util.ParamChecker.isNullOrEmpty;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.GridLayout;
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.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import com.romraider.Settings;
import com.romraider.editor.ecu.ECUEditorManager;
import com.romraider.logger.ecu.ui.swing.vertical.VerticalLabelUI;
import com.romraider.util.NumberUtil;
import com.romraider.util.SettingsManager;
import com.romraider.xml.RomAttributeParser;
public class Table3D extends Table {
private static final long serialVersionUID = 3103448753263606599L;
private Table1D xAxis = new Table1D();
private Table1D yAxis = new Table1D();
private JLabel xAxisLabel;
private JLabel yAxisLabel;
DataCell[][] data = new DataCell[1][1];
private boolean swapXY = false;
private boolean flipX = false;
private boolean flipY = false;
CopyTable3DWorker copyTable3DWorker;
CopySelection3DWorker copySelection3DWorker;
public Table3D() {
super();
verticalOverhead += 39;
horizontalOverhead += 10;
}
public Table1D getXAxis() {
return xAxis;
}
public void setXAxis(Table1D xAxis) {
this.xAxis = xAxis;
xAxis.setAxisParent(this);
}
public Table1D getYAxis() {
return yAxis;
}
public void setYAxis(Table1D yAxis) {
this.yAxis = yAxis;
yAxis.setAxisParent(this);
}
public boolean getSwapXY() {
return swapXY;
}
public void setSwapXY(boolean swapXY) {
this.swapXY = swapXY;
}
public boolean getFlipX() {
return flipX;
}
public void setFlipX(boolean flipX) {
this.flipX = flipX;
}
public boolean getFlipY() {
return flipY;
}
public void setFlipY(boolean flipY) {
this.flipY = flipY;
}
public void setSizeX(int size) {
data = new DataCell[size][data[0].length];
centerLayout.setColumns(size + 1);
}
public int getSizeX() {
return data.length;
}
public void setSizeY(int size) {
data = new DataCell[data.length][size];
centerLayout.setRows(size + 1);
}
public int getSizeY() {
return data[0].length;
}
@Override
public void drawTable() {
for(DataCell[] column : data) {
for(DataCell cell : column) {
if(null != cell) {
cell.drawCell();
}
}
}
xAxis.drawTable();
yAxis.drawTable();
}
@Override
public void populateTable(byte[] input, int romRamOffset) throws NullPointerException, ArrayIndexOutOfBoundsException, IndexOutOfBoundsException {
// fill first empty cell
centerPanel.add(new JLabel());
if (!beforeRam) {
this.ramOffset = romRamOffset;
}
// temporarily remove lock
boolean tempLock = locked;
locked = false;
// populate axes
try {
xAxis.populateTable(input, romRamOffset);
yAxis.populateTable(input, romRamOffset);
} catch (ArrayIndexOutOfBoundsException ex) {
throw new ArrayIndexOutOfBoundsException();
}
for (int x = 0; x < xAxis.getDataSize(); x++) {
centerPanel.add(xAxis.getDataCell(x));
}
int offset = 0;
int iMax = swapXY ? xAxis.getDataSize() : yAxis.getDataSize();
int jMax = swapXY ? yAxis.getDataSize() : xAxis.getDataSize();
for (int i = 0; i < iMax; i++) {
for (int j = 0; j < jMax; j++) {
int x = flipY ? jMax - j - 1 : j;
int y = flipX ? iMax - i - 1 : i;
if (swapXY) {
int z = x;
x = y;
y = z;
}
double cellBinValue;
// populate data cells
if (storageType == Settings.STORAGE_TYPE_FLOAT) { //float storage type
byte[] byteValue = new byte[4];
byteValue[0] = input[getStorageAddress() + offset * 4 - ramOffset];
byteValue[1] = input[getStorageAddress() + offset * 4 - ramOffset + 1];
byteValue[2] = input[getStorageAddress() + offset * 4 - ramOffset + 2];
byteValue[3] = input[getStorageAddress() + offset * 4 - ramOffset + 3];
cellBinValue = RomAttributeParser.byteToFloat(byteValue, endian, memModelEndian);
} else if (storageType == Settings.STORAGE_TYPE_MOVI20 ||
storageType == Settings.STORAGE_TYPE_MOVI20S) { // when data is in MOVI20 instruction
cellBinValue = RomAttributeParser.parseByteValue(input,
endian,
getStorageAddress() + i * 3 - ramOffset,
storageType,
signed);
} else { // integer storage type
cellBinValue = RomAttributeParser.parseByteValue(input,
endian,
getStorageAddress() + offset * storageType - ramOffset,
storageType,
signed);
}
// show locked cell
if (tempLock) {
data[x][y].setForeground(Color.GRAY);
}
data[x][y] = new DataCell(this, cellBinValue, x, y);
offset++;
}
}
for (int y = 0; y < yAxis.getDataSize(); y++) {
centerPanel.add(yAxis.getDataCell(y));
for (int x = 0; x < xAxis.getDataSize(); x++) {
centerPanel.add(data[x][y]);
}
}
// reset locked status
locked = tempLock;
GridLayout topLayout = new GridLayout(2, 1);
JPanel topPanel = new JPanel(topLayout);
this.add(topPanel, BorderLayout.NORTH);
topPanel.add(new JLabel(getName(), JLabel.CENTER), BorderLayout.NORTH);
if(null == xAxis.getName() || xAxis.getName().length() < 1 || Settings.BLANK == xAxis.getName()) {
;// Do not add label.
} else if(null == xAxis.getCurrentScale() || "0x" == xAxis.getCurrentScale().getUnit()) {
// static or no scale exists.
xAxisLabel = new JLabel(xAxis.getName(), JLabel.CENTER);
topPanel.add(xAxisLabel, BorderLayout.NORTH);
} else {
xAxisLabel = new JLabel(xAxis.getName() + " (" + xAxis.getCurrentScale().getUnit() + ")", JLabel.CENTER);
topPanel.add(xAxisLabel, BorderLayout.NORTH);
}
yAxisLabel = null;
if(null == yAxis.getName() || yAxis.getName().length() < 1 || Settings.BLANK == yAxis.getName()) {
;// Do not add label.
} else if(null == yAxis.getCurrentScale() || "0x" == yAxis.getCurrentScale().getUnit()) {
// static or no scale exists.
yAxisLabel = new JLabel(yAxis.getName());
} else {
yAxisLabel = new JLabel(yAxis.getName() + " (" + yAxis.getCurrentScale().getUnit() + ")");
}
yAxisLabel.setUI(new VerticalLabelUI(false));
add(yAxisLabel, BorderLayout.WEST);
tableLabel = new JLabel(getCurrentScale().getUnit(), JLabel.CENTER);
add(tableLabel, BorderLayout.SOUTH);
calcCellRanges();
}
@Override
public void updateTableLabel() {
if(null == xAxis.getName() || xAxis.getName().length() < 1 || Settings.BLANK == xAxis.getName()) {
;// Do not update label.
} else if(null == xAxis.getCurrentScale() || "0x" == xAxis.getCurrentScale().getUnit()) {
// static or no scale exists.
xAxisLabel.setText(xAxis.getName());
} else {
xAxisLabel.setText(xAxis.getName() + " (" + xAxis.getCurrentScale().getUnit() + ")");
}
if(null == yAxis.getName() || yAxis.getName().length() < 1 || Settings.BLANK == yAxis.getName()) {
;// Do not update label.
} else if(null == yAxis.getCurrentScale() || "0x" == yAxis.getCurrentScale().getUnit()) {
// static or no scale exists.
yAxisLabel.setText(yAxis.getName());
} else {
yAxisLabel.setText(yAxis.getName() + " (" + yAxis.getCurrentScale().getUnit() + ")");
}
tableLabel.setText(getCurrentScale().getUnit());
}
@Override
public void calcCellRanges() {
double binMax = data[0][0].getBinValue();
double binMin = data[0][0].getBinValue();
double compareMax = data[0][0].getCompareValue();
double compareMin = data[0][0].getCompareValue();
for(DataCell[] column : data) {
for(DataCell cell : column) {
// Calc bin
if(binMax < cell.getBinValue()) {
binMax = cell.getBinValue();
}
if(binMin > cell.getBinValue()) {
binMin = cell.getBinValue();
}
// Calc compare
double compareValue = cell.getCompareValue();
if(compareMax < compareValue) {
compareMax = compareValue;
}
if(compareMin > compareValue) {
compareMin = compareValue;
}
}
}
setMaxBin(binMax);
setMinBin(binMin);
setMaxCompare(compareMax);
setMinCompare(compareMin);
}
@Override
public StringBuffer getTableAsString() {
StringBuffer output = new StringBuffer(Settings.BLANK);
output.append(xAxis.getTableAsString());
output.append(Settings.NEW_LINE);
for (int y = 0; y < getSizeY(); y++) {
output.append(NumberUtil.stringValue(yAxis.data[y].getRealValue()));
output.append(Settings.TAB);
for (int x = 0; x < getSizeX(); x++) {
if (overlayLog) {
output.append(data[x][y].getCellText());
}
else {
output.append(NumberUtil.stringValue(data[x][y].getRealValue()));
}
if (x < getSizeX() - 1) {
output.append(Settings.TAB);
}
}
if (y < getSizeY() - 1) {
output.append(Settings.NEW_LINE);
}
}
return output;
}
@Override
public void populateCompareValues(Table otherTable) {
if(null == otherTable || !(otherTable instanceof Table3D)) {
return;
}
Table3D compareTable3D = (Table3D) otherTable;
if(data.length != compareTable3D.data.length ||
data[0].length != compareTable3D.data[0].length ||
xAxis.getDataSize() != compareTable3D.xAxis.getDataSize() ||
yAxis.getDataSize() != compareTable3D.yAxis.getDataSize()) {
return;
}
clearLiveDataTrace();
int x=0;
for (DataCell[] column : data) {
int y = 0;
for(DataCell cell : column) {
cell.setCompareValue(compareTable3D.data[x][y]);
y++;
}
x++;
}
xAxis.populateCompareValues(compareTable3D.getXAxis());
yAxis.populateCompareValues(compareTable3D.getYAxis());
calcCellRanges();
drawTable();
}
@Override
public void refreshCompare() {
populateCompareValues(getCompareTable());
xAxis.refreshCompare();
yAxis.refreshCompare();
}
@Override
public Dimension getFrameSize() {
int height = verticalOverhead + cellHeight * data[0].length;
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 String toString() {
return super.toString() + " (3D)";/* +
"\n Flip X: " + flipX +
"\n Size X: " + data.length +
"\n Flip Y: " + flipY +
"\n Size Y: " + data[0].length +
"\n Swap X/Y: " + swapXY +
xAxis +
yAxis;*/
}
@Override
public void increment(double increment) {
if (!locked) {
for (int x = 0; x < this.getSizeX(); x++) {
for (int y = 0; y < this.getSizeY(); y++) {
if (data[x][y].isSelected()) {
data[x][y].increment(increment);
}
}
}
}
}
@Override
public void multiply(double factor) {
if (!locked) {
for (int x = 0; x < this.getSizeX(); x++) {
for (int y = 0; y < this.getSizeY(); y++) {
if (data[x][y].isSelected()) {
data[x][y].multiply(factor);
}
}
}
}
}
@Override
public void clearSelection() {
xAxis.clearSelectedData();
yAxis.clearSelectedData();
clearSelectedData();
}
@Override
public void clearSelectedData() {
for (int x = 0; x < this.getSizeX(); x++) {
for (int y = 0; y < this.getSizeY(); y++) {
data[x][y].setSelected(false);
}
}
}
@Override
public void highlight(int xCoord, int yCoord) {
if (highlight) {
for (int x = 0; x < this.getSizeX(); x++) {
for (int y = 0; y < this.getSizeY(); y++) {
if (((y >= highlightY && y <= yCoord) ||
(y <= highlightY && y >= yCoord)) &&
((x >= highlightX && x <= xCoord) ||
(x <= highlightX && x >= xCoord))) {
data[x][y].setHighlighted(true);
} else {
data[x][y].setHighlighted(false);
}
}
}
}
}
@Override
public void stopHighlight() {
highlight = false;
// loop through, selected and un-highlight
for (int x = 0; x < this.getSizeX(); x++) {
for (int y = 0; y < this.getSizeY(); y++) {
if (data[x][y].isHighlighted()) {
data[x][y].setSelected(true);
data[x][y].setHighlighted(false);
}
}
}
}
@Override
public void setRevertPoint() {
for (int x = 0; x < this.getSizeX(); x++) {
for (int y = 0; y < this.getSizeY(); y++) {
data[x][y].setRevertPoint();
}
}
yAxis.setRevertPoint();
xAxis.setRevertPoint();
}
@Override
public void undoAll() {
clearLiveDataTrace();
for (int x = 0; x < this.getSizeX(); x++) {
for (int y = 0; y < this.getSizeY(); y++) {
data[x][y].undo();
}
}
yAxis.undoAll();
xAxis.undoAll();
}
@Override
public void undoSelected() {
clearLiveDataTrace();
for (int x = 0; x < this.getSizeX(); x++) {
for (int y = 0; y < this.getSizeY(); y++) {
if (data[x][y].isSelected()) {
data[x][y].undo();
}
}
}
}
@Override
public byte[] saveFile(byte[] binData) {
if ( userLevel <= getSettings().getUserLevel() && (userLevel < 5 || getSettings().isSaveDebugTables()) ) {
binData = xAxis.saveFile(binData);
binData = yAxis.saveFile(binData);
int offset = 0;
int iMax = swapXY ? xAxis.getDataSize() : yAxis.getDataSize();
int jMax = swapXY ? yAxis.getDataSize() : xAxis.getDataSize();
for (int i = 0; i < iMax; i++) {
for (int j = 0; j < jMax; j++) {
int x = flipY ? jMax - j - 1 : j;
int y = flipX ? iMax - i - 1 : i;
if (swapXY) {
int z = x;
x = y;
y = z;
}
// determine output byte values
byte[] output;
if (storageType != Settings.STORAGE_TYPE_FLOAT) {
output = RomAttributeParser.parseIntegerValue((int) data[x][y].getBinValue(), endian, storageType);
int byteLength = storageType;
if (storageType == Settings.STORAGE_TYPE_MOVI20 ||
storageType == Settings.STORAGE_TYPE_MOVI20S) { // when data is in MOVI20 instruction
byteLength = 3;
}
for (int z = 0; z < byteLength; z++) {
binData[offset * byteLength + z + getStorageAddress() - ramOffset] = output[z];
}
} else { // float
output = RomAttributeParser.floatToByte((float) data[x][y].getBinValue(), endian, memModelEndian);
for (int z = 0; z < 4; z++) {
binData[offset * 4 + z + getStorageAddress() - ramOffset] = output[z];
}
}
offset++;
}
}
}
return binData;
}
@Override
public void setRealValue(String realValue) {
if (!locked && !(userLevel > getSettings().getUserLevel()) ) {
for(DataCell[] column : data) {
for(DataCell cell : column) {
if(cell.isSelected()) {
cell.setRealValue(realValue);
}
}
}
} else if (userLevel > getSettings().getUserLevel()) {
JOptionPane.showMessageDialog(this, "This table can only be modified by users with a userlevel of \n" +
userLevel + " or greater. Click View->User Level to change your userlevel.",
"Table cannot be modified",
JOptionPane.INFORMATION_MESSAGE);
}
xAxis.setRealValue(realValue);
yAxis.setRealValue(realValue);
}
@Override
public void addKeyListener(KeyListener listener) {
xAxis.addKeyListener(listener);
yAxis.addKeyListener(listener);
for (int x = 0; x < this.getSizeX(); x++) {
for (int y = 0; y < this.getSizeY(); y++) {
data[x][y].addKeyListener(listener);
}
}
}
public void selectCellAt(int y, Table1D axisType) {
if (axisType.getType() == Settings.TABLE_Y_AXIS) {
selectCellAt(0, y);
} else { // y axis
selectCellAt(y, 0);
}
ECUEditorManager.getECUEditor().getTableToolBar().updateTableToolBar(this);
}
public void deSelectCellAt(int x, int y) {
clearSelection();
data[x][y].setSelected(false);
highlightX = x;
highlightY = y;
}
public void selectCellAt(int x, int y) {
clearSelection();
data[x][y].setSelected(true);
highlightX = x;
highlightY = y;
}
public void selectCellAtWithoutClear(int x, int y) {
data[x][y].setSelected(true);
highlightX = x;
highlightY = y;
}
@Override
public void cursorUp() {
if (highlightY > 0 && data[highlightX][highlightY].isSelected()) {
selectCellAt(highlightX, highlightY - 1);
} else if (data[highlightX][highlightY].isSelected()) {
xAxis.selectCellAt(highlightX);
} else {
xAxis.cursorUp();
yAxis.cursorUp();
}
}
@Override
public void cursorDown() {
if (highlightY < getSizeY() - 1 && data[highlightX][highlightY].isSelected()) {
selectCellAt(highlightX, highlightY + 1);
} else {
xAxis.cursorDown();
yAxis.cursorDown();
}
}
@Override
public void cursorLeft() {
if (highlightX > 0 && data[highlightX][highlightY].isSelected()) {
selectCellAt(highlightX - 1, highlightY);
} else if (data[highlightX][highlightY].isSelected()) {
yAxis.selectCellAt(highlightY);
} else {
xAxis.cursorLeft();
yAxis.cursorLeft();
}
}
@Override
public void cursorRight() {
if (highlightX < getSizeX() - 1 && data[highlightX][highlightY].isSelected()) {
selectCellAt(highlightX + 1, highlightY);
} else {
xAxis.cursorRight();
yAxis.cursorRight();
}
}
@Override
public void shiftCursorUp() {
if (highlightY > 0 && data[highlightX][highlightY].isSelected()) {
selectCellAtWithoutClear(highlightX, highlightY - 1);
} else if (data[highlightX][highlightY].isSelected()) {
data[highlightX][highlightY].setSelected(false);
xAxis.selectCellAt(highlightX);
} else {
xAxis.cursorUp();
yAxis.shiftCursorUp();
}
}
@Override
public void shiftCursorDown() {
if (highlightY < getSizeY() - 1 && data[highlightX][highlightY].isSelected()) {
selectCellAtWithoutClear(highlightX, highlightY + 1);
} else {
xAxis.shiftCursorDown();
yAxis.shiftCursorDown();
}
}
@Override
public void shiftCursorLeft() {
if (highlightX > 0 && data[highlightX][highlightY].isSelected()) {
selectCellAtWithoutClear(highlightX - 1, highlightY);
} else if (data[highlightX][highlightY].isSelected()) {
yAxis.selectCellAt(highlightY);
} else {
xAxis.shiftCursorLeft();
yAxis.shiftCursorLeft();
}
}
@Override
public void shiftCursorRight() {
if (highlightX < getSizeX() - 1 && data[highlightX][highlightY].isSelected()) {
selectCellAtWithoutClear(highlightX + 1, highlightY);
} else {
xAxis.shiftCursorRight();
yAxis.shiftCursorRight();
}
}
@Override
public void startHighlight(int x, int y) {
xAxis.clearSelectedData();
yAxis.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));
copySelection3DWorker = new CopySelection3DWorker(this);
copySelection3DWorker.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));
copyTable3DWorker = new CopyTable3DWorker(this);
copyTable3DWorker.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 ("[Table3D]".equalsIgnoreCase(pasteType)) { // Paste table
String currentToken = st.nextToken(Settings.NEW_LINE);
if (currentToken.endsWith("\t")) {
currentToken = st.nextToken(Settings.NEW_LINE);
}
String xAxisValues = "[Table1D]" + Settings.NEW_LINE + currentToken;
// build y axis and data values
StringBuffer yAxisValues = new StringBuffer("[Table1D]" + Settings.NEW_LINE + st.nextToken("\t"));
StringBuffer dataValues = new StringBuffer("[Table3D]" + Settings.NEW_LINE + st.nextToken("\t") + st.nextToken(Settings.NEW_LINE));
while (st.hasMoreTokens()) {
yAxisValues.append("\t").append(st.nextToken("\t"));
dataValues.append(Settings.NEW_LINE).append(st.nextToken("\t")).append(st.nextToken(Settings.NEW_LINE));
}
// put x axis in clipboard and paste
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(xAxisValues), null);
xAxis.paste();
// put y axis in clipboard and paste
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(String.valueOf(yAxisValues)), null);
yAxis.paste();
// put datavalues in clipboard and paste
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(String.valueOf(dataValues)), null);
pasteValues();
// reset clipboard
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(input), null);
} else if ("[Selection3D]".equalsIgnoreCase(pasteType)) { // paste selection
pasteValues();
} else if ("[Selection1D]".equalsIgnoreCase(pasteType)) { // paste selection
xAxis.paste();
yAxis.paste();
}
}
public void pasteValues() {
StringTokenizer st = new StringTokenizer(Settings.BLANK);
try {
String 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();
// figure paste start cell
int startX = 0;
int startY = 0;
// if pasting a table, startX and Y at 0, else highlight is start
if ("[Selection3D]".equalsIgnoreCase(pasteType)) {
startX = highlightX;
startY = highlightY;
}
// set values
for (int y = startY; st.hasMoreTokens() && y < getSizeY(); y++) {
String checkToken = st.nextToken(Settings.NEW_LINE);
if (y==startY && checkToken.endsWith("\t")) {
checkToken = st.nextToken(Settings.NEW_LINE);
}
StringTokenizer currentLine = new StringTokenizer(checkToken, ST_DELIMITER);
for (int x = startX; currentLine.hasMoreTokens() && x < getSizeX(); x++) {
String currentToken = currentLine.nextToken();
try {
if (!data[x][y].getText().equalsIgnoreCase(currentToken)) {
data[x][y].setRealValue(currentToken);
}
} catch (ArrayIndexOutOfBoundsException ex) { /* copied table is larger than current table*/ }
}
}
}
@Override
public void verticalInterpolate() {
int[] coords = { getSizeX(), getSizeY(), 0, 0};
DataCell[][] tableData = get3dData();
DataCell[] axisData = getYAxis().getData();
int i, j;
for (i = 0; i < getSizeX(); ++i) {
for (j = 0; j < getSizeY(); ++j) {
if (tableData[i][j].isSelected()) {
if (i < coords[0])
coords[0] = i;
if (i > coords[2])
coords[2] = i;
if (j < coords[1])
coords[1] = j;
if (j > coords[3])
coords[3] = j;
}
}
}
if (coords[3] - coords[1] > 1) {
double x, x1, x2, y1, y2;
x1 = axisData[coords[1]].getBinValue();
x2 = axisData[coords[3]].getBinValue();
for (i = coords[0]; i <= coords[2]; ++i) {
y1 = tableData[i][coords[1]].getBinValue();
y2 = tableData[i][coords[3]].getBinValue();
for (j = coords[1] + 1; j < coords[3]; ++j) {
x = axisData[j].getBinValue();
tableData[i][j].setBinValue(linearInterpolation(x, x1, x2, y1, y2));
}
}
}
// Interpolate y axis in case the y axis in selected.
this.getYAxis().verticalInterpolate();
}
@Override
public void horizontalInterpolate() {
int[] coords = { getSizeX(), getSizeY(), 0, 0 };
DataCell[][] tableData = get3dData();
DataCell[] axisData = getXAxis().getData();
int i, j;
for (i = 0; i < getSizeX(); ++i) {
for (j = 0; j < getSizeY(); ++j) {
if (tableData[i][j].isSelected()) {
if (i < coords[0])
coords[0] = i;
if (i > coords[2])
coords[2] = i;
if (j < coords[1])
coords[1] = j;
if (j > coords[3])
coords[3] = j;
}
}
}
if (coords[2] - coords[0] > 1) {
double x, x1, x2, y1, y2;
x1 = axisData[coords[0]].getBinValue();
x2 = axisData[coords[2]].getBinValue();
for (i = coords[1]; i <= coords[3]; ++i) {
y1 = tableData[coords[0]][i].getBinValue();
y2 = tableData[coords[2]][i].getBinValue();
for (j = coords[0] + 1; j < coords[2]; ++j) {
x = axisData[j].getBinValue();
tableData[j][i].setBinValue(linearInterpolation(x, x1, x2, y1, y2));
}
}
}
// Interpolate x axis in case the x axis in selected.
this.getXAxis().horizontalInterpolate();
}
@Override
public void interpolate() {
verticalInterpolate();
horizontalInterpolate();
}
@Override
public boolean isLiveDataSupported() {
return !isNullOrEmpty(xAxis.getLogParam()) && !isNullOrEmpty(yAxis.getLogParam());
}
@Override
public boolean isButtonSelected() {
return true;
}
@Override
public void highlightLiveData(String liveValue) {
if (getOverlayLog()) {
int x = xAxis.getLiveDataIndex();
int y = yAxis.getLiveDataIndex();
DataCell cell = data[x][y];
cell.setLiveDataTrace(true);
cell.setLiveDataTraceValue(liveValue);
getToolbar().setLiveDataValue(liveValue);
}
}
@Override
public void updateLiveDataHighlight() {
if (getOverlayLog()) {
int x = xAxis.getLiveDataIndex();
int y = yAxis.getLiveDataIndex();
data[x][y].setLiveDataTrace(true);
}
}
@Override
public void clearLiveDataTrace() {
xAxis.clearLiveDataTrace();
yAxis.clearLiveDataTrace();
for (int x = 0; x < getSizeX(); x++) {
for (int y = 0; y < getSizeY(); y++) {
data[x][y].setLiveDataTrace(false);
}
}
}
public DataCell[][] get3dData() {
return data;
}
@Override
public void setCompareDisplay(int compareDisplay) {
super.setCompareDisplay(compareDisplay);
xAxis.setCompareDisplay(compareDisplay);
yAxis.setCompareDisplay(compareDisplay);
}
@Override
public void setCompareValueType(int compareValueType) {
super.setCompareValueType(compareValueType);
xAxis.setCompareValueType(compareValueType);
yAxis.setCompareValueType(compareValueType);
}
@Override
public void setCurrentScale(Scale curScale) {
if(SettingsManager.getSettings().isScaleHeadersAndData()) {
if(!xAxis.isStaticDataTable()) {
try {
this.xAxis.setScaleByName(curScale.getName());
} catch (NameNotFoundException e) {
try {
this.xAxis.setScaleByName(SettingsManager.getSettings().getDefaultScale());
} catch (NameNotFoundException e1) {
}
}
}
if(!yAxis.isStaticDataTable()) {
try {
this.yAxis.setScaleByName(curScale.getName());
} catch (NameNotFoundException e) {
try {
this.yAxis.setScaleByName(SettingsManager.getSettings().getDefaultScale());
} catch (NameNotFoundException e1) {
}
}
}
}
this.curScale = curScale;
updateTableLabel();
drawTable();
}
@Override
public String getLogParamString() {
StringBuilder sb = new StringBuilder();
sb.append(xAxis.getLogParamString()+", ");
sb.append(yAxis.getLogParamString()+", ");
sb.append(getName()+ ":" + getLogParam());
return sb.toString();
}
@Override
public void setOverlayLog(boolean overlayLog) {
super.setOverlayLog(overlayLog);
xAxis.setOverlayLog(overlayLog);
yAxis.setOverlayLog(overlayLog);
}
@Override
public boolean equals(Object other) {
try {
if(null == other) {
return false;
}
if(other == this) {
return true;
}
if(!(other instanceof Table3D)) {
return false;
}
Table3D otherTable = (Table3D)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.xAxis.equals(otherTable.xAxis)) {
return false;
}
if(! this.yAxis.equals(otherTable.yAxis)) {
return false;
}
if(this.data.length != otherTable.data.length || this.data[0].length != otherTable.data[0].length)
{
return false;
}
if(this.data.equals(otherTable.data))
{
return true;
}
// Compare Bin Values
for(int i = 0 ; i < this.data.length ; i++) {
for(int j = 0; j < this.data[i].length ; j++) {
if(! this.data[i][j].equals(otherTable.data[i][j]) ) {
return false;
}
}
}
return true;
} catch(Exception ex) {
// TODO: Log Exception.
return false;
}
}
@Override
public void repaint() {
super.repaint();
if(null != xAxis) {
xAxis.repaint();
}
if(null != yAxis) {
yAxis.repaint();
}
}
}
class CopySelection3DWorker extends SwingWorker<Void, Void> {
Table3D table;
public CopySelection3DWorker(Table3D table)
{
this.table = table;
}
@Override
protected Void doInBackground() throws Exception {
// find bounds of selection
// coords[0] = x min, y min, x max, y max
boolean copy = false;
int[] coords = new int[4];
coords[0] = table.getSizeX();
coords[1] = table.getSizeY();
for (int x = 0; x < table.getSizeX(); x++) {
for (int y = 0; y < table.getSizeY(); y++) {
if (table.get3dData()[x][y].isSelected()) {
if (x < coords[0]) {
coords[0] = x;
copy = true;
}
if (x > coords[2]) {
coords[2] = x;
copy = true;
}
if (y < coords[1]) {
coords[1] = y;
copy = true;
}
if (y > coords[3]) {
coords[3] = y;
copy = true;
}
}
}
}
// make string of selection
if (copy) {
StringBuffer output = new StringBuffer("[Selection3D]" + Settings.NEW_LINE);
for (int y = coords[1]; y <= coords[3]; y++) {
for (int x = coords[0]; x <= coords[2]; x++) {
if (table.get3dData()[x][y].isSelected()) {
output.append(NumberUtil.stringValue(table.get3dData()[x][y].getRealValue()));
} else {
output.append("x"); // x represents non-selected cell
}
if (x < coords[2]) {
output.append("\t");
}
}
if (y < coords[3]) {
output.append(Settings.NEW_LINE);
}
//copy to clipboard
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(String.valueOf(output)), null);
}
} else {
table.getXAxis().copySelection();
table.getYAxis().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 CopyTable3DWorker extends SwingWorker<Void, Void> {
Table3D table;
public CopyTable3DWorker(Table3D table)
{
this.table = table;
}
@Override
protected Void doInBackground() throws Exception {
String tableHeader = table.getSettings().getTable3DHeader();
StringBuffer output = new StringBuffer(tableHeader);
output.append(table.getTableAsString());
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(String.valueOf(output)), 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);
}
}