RomRaider/src/com/romraider/ECUEditor.java

425 lines
15 KiB
Java

/*
*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2008 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;
import com.romraider.logger.ecu.ui.handler.table.TableUpdateHandler;
import com.romraider.maps.Rom;
import com.romraider.maps.Table;
import com.romraider.net.URL;
import com.romraider.swing.ECUEditorMenuBar;
import com.romraider.swing.ECUEditorToolBar;
import com.romraider.swing.JProgressPane;
import com.romraider.swing.MDIDesktopPane;
import com.romraider.swing.RomTree;
import com.romraider.swing.RomTreeNode;
import com.romraider.swing.RomTreeRootNode;
import com.romraider.swing.TableFrame;
import com.romraider.util.SettingsManager;
import com.romraider.util.SettingsManagerImpl;
import com.romraider.xml.DOMRomUnmarshaller;
import com.romraider.xml.RomNotFoundException;
import com.sun.org.apache.xerces.internal.parsers.DOMParser;
import com.sun.org.apache.xerces.internal.xni.parser.XMLParseException;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import javax.swing.ImageIcon;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.tree.TreePath;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.Vector;
public class ECUEditor extends JFrame implements WindowListener, PropertyChangeListener {
private String titleText = Version.PRODUCT_NAME + " v" + Version.VERSION;
private static final String NEW_LINE = System.getProperty("line.separator");
private final SettingsManager settingsManager = new SettingsManagerImpl();
private RomTreeRootNode imageRoot = new RomTreeRootNode("Open Images");
private RomTree imageList = new RomTree(imageRoot);
public MDIDesktopPane rightPanel = new MDIDesktopPane();
private JProgressPane statusPanel = new JProgressPane();
private JSplitPane splitPane = new JSplitPane();
private Rom lastSelectedRom = null;
private ECUEditorToolBar toolBar;
private ECUEditorMenuBar menuBar;
private Settings settings;
public ECUEditor() {
// get settings from xml
settings = settingsManager.load("A new file will be created.");
if (!settings.getRecentVersion().equalsIgnoreCase(Version.VERSION)) {
showReleaseNotes();
}
setSize(getSettings().getWindowSize());
setLocation(getSettings().getWindowLocation());
if (getSettings().isWindowMaximized()) {
setExtendedState(MAXIMIZED_BOTH);
}
JScrollPane rightScrollPane = new JScrollPane(rightPanel,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
JScrollPane leftScrollPane = new JScrollPane(imageList,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftScrollPane, rightScrollPane);
splitPane.setDividerSize(2);
splitPane.setDividerLocation(getSettings().getSplitPaneLocation());
splitPane.addPropertyChangeListener(this);
getContentPane().add(splitPane);
rightPanel.setBackground(Color.BLACK);
imageList.setScrollsOnExpand(true);
imageList.setContainer(this);
//create menubar and toolbar
menuBar = new ECUEditorMenuBar(this);
this.setJMenuBar(menuBar);
toolBar = new ECUEditorToolBar(this);
this.add(toolBar, BorderLayout.NORTH);
this.add(statusPanel, BorderLayout.SOUTH);
//set remaining window properties
setIconImage(new ImageIcon("./graphics/romraider-ico.gif").getImage());
setDefaultCloseOperation(EXIT_ON_CLOSE);
addWindowListener(this);
setTitle(titleText);
setVisible(true);
}
private void showReleaseNotes() {
try {
BufferedReader br = new BufferedReader(new FileReader(settings.getReleaseNotes()));
try {
// new version being used, display release notes
JTextArea releaseNotes = new JTextArea();
releaseNotes.setEditable(false);
releaseNotes.setWrapStyleWord(true);
releaseNotes.setLineWrap(true);
releaseNotes.setFont(new Font("Tahoma", Font.PLAIN, 12));
JScrollPane scroller = new JScrollPane(releaseNotes,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scroller.setPreferredSize(new Dimension(600, 500));
StringBuffer sb = new StringBuffer();
while (br.ready()) {
sb.append(br.readLine()).append(NEW_LINE);
}
releaseNotes.setText(sb.toString());
JOptionPane.showMessageDialog(this, scroller,
Version.PRODUCT_NAME + Version.VERSION + " Release Notes", JOptionPane.INFORMATION_MESSAGE);
} finally {
br.close();
}
} catch (Exception e) {
/* Ignore */
}
}
public void handleExit() {
settings.setSplitPaneLocation(splitPane.getDividerLocation());
settings.setWindowMaximized(getExtendedState() == MAXIMIZED_BOTH);
settings.setWindowSize(getSize());
settings.setWindowLocation(getLocation());
settingsManager.save(settings, statusPanel);
statusPanel.update("Ready...", 0);
repaint();
}
public void windowClosing(WindowEvent e) {
handleExit();
}
public void windowOpened(WindowEvent e) {
}
public void windowClosed(WindowEvent e) {
}
public void windowIconified(WindowEvent e) {
}
public void windowDeiconified(WindowEvent e) {
}
public void windowActivated(WindowEvent e) {
}
public void windowDeactivated(WindowEvent e) {
}
public String getVersion() {
return Version.VERSION;
}
public Settings getSettings() {
return settings;
}
public void addRom(Rom input) {
// add to ecu image list pane
RomTreeNode romNode = new RomTreeNode(input, settings.getUserLevel(), settings.isDisplayHighTables());
imageRoot.add(romNode);
imageList.updateUI();
imageList.expandRow(imageList.getRowCount() - 1);
imageList.updateUI();
setLastSelectedRom(input);
if (input.getRomID().isObsolete() && settings.isObsoleteWarning()) {
JPanel infoPanel = new JPanel();
infoPanel.setLayout(new GridLayout(3, 1));
infoPanel.add(new JLabel("A newer version of this ECU revision exists. " +
"Please visit the following link to download the latest revision:"));
infoPanel.add(new URL(settings.getRomRevisionURL()));
JCheckBox check = new JCheckBox("Always display this message", true);
check.setHorizontalAlignment(JCheckBox.RIGHT);
check.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
settings.setObsoleteWarning(((JCheckBox) e.getSource()).isSelected());
}
}
);
infoPanel.add(check);
JOptionPane.showMessageDialog(this, infoPanel, "ECU Revision is Obsolete", JOptionPane.INFORMATION_MESSAGE);
}
input.setContainer(this);
imageList.updateUI();
}
public void displayTable(TableFrame frame) {
frame.setVisible(true);
try {
rightPanel.add(frame);
} catch (IllegalArgumentException ex) {
// table is already open, so set focus
frame.requestFocus();
}
//frame.setSize(frame.getTable().getFrameSize());
frame.pack();
rightPanel.repaint();
}
public void removeDisplayTable(TableFrame frame) {
frame.setVisible(false);
rightPanel.remove(frame);
rightPanel.repaint();
}
public void closeImage() {
for (int i = 0; i < imageRoot.getChildCount(); i++) {
RomTreeNode romTreeNode = (RomTreeNode) imageRoot.getChildAt(i);
Rom rom = romTreeNode.getRom();
if (rom == lastSelectedRom) {
Vector<Table> romTables = rom.getTables();
for (Table t : romTables) {
rightPanel.remove(t.getFrame());
TableUpdateHandler.getInstance().deregisterTable(t);
}
Vector<TreePath> path = new Vector<TreePath>();
path.add(new TreePath(romTreeNode.getPath()));
imageRoot.remove(i);
imageList.removeDescendantToggledPaths(path.elements());
break;
}
}
imageList.updateUI();
if (imageRoot.getChildCount() > 0) {
setLastSelectedRom(((RomTreeNode) imageRoot.getChildAt(0)).getRom());
} else {
// no other images open
setLastSelectedRom(null);
}
rightPanel.repaint();
}
public void closeAllImages() {
while (imageRoot.getChildCount() > 0) {
closeImage();
}
}
public Rom getLastSelectedRom() {
return lastSelectedRom;
}
public void setLastSelectedRom(Rom lastSelectedRom) {
this.lastSelectedRom = lastSelectedRom;
if (lastSelectedRom == null) {
setTitle(titleText);
} else {
setTitle(titleText + " - " + lastSelectedRom.getFileName());
}
// update filenames
for (int i = 0; i < imageRoot.getChildCount(); i++) {
((RomTreeNode) imageRoot.getChildAt(i)).updateFileName();
}
toolBar.updateButtons();
menuBar.updateMenu();
imageList.updateUI();
}
public ECUEditorToolBar getToolBar() {
return toolBar;
}
public void setToolBar(ECUEditorToolBar toolBar) {
this.toolBar = toolBar;
}
public void setSettings(Settings settings) {
this.settings = settings;
for (int i = 0; i < imageRoot.getChildCount(); i++) {
RomTreeNode rtn = (RomTreeNode) imageRoot.getChildAt(i);
rtn.getRom().setContainer(this);
}
}
public void setUserLevel(int userLevel) {
settings.setUserLevel(userLevel);
imageRoot.setUserLevel(userLevel, settings.isDisplayHighTables());
imageList.updateUI();
}
public Vector<Rom> getImages() {
Vector<Rom> images = new Vector<Rom>();
for (int i = 0; i < imageRoot.getChildCount(); i++) {
RomTreeNode rtn = (RomTreeNode) imageRoot.getChildAt(i);
images.add(rtn.getRom());
}
return images;
}
public void propertyChange(PropertyChangeEvent evt) {
imageList.updateUI();
imageList.repaint();
}
public void openImage(File inputFile) throws XMLParseException, Exception {
try {
update(getGraphics());
statusPanel.update("Parsing ECU definitions...", 0);
repaint();
byte[] input = readFile(inputFile);
DOMRomUnmarshaller domUms = new DOMRomUnmarshaller(settings, this);
DOMParser parser = new DOMParser();
statusPanel.update("Finding ECU definition...", 10);
repaint();
Rom rom;
// parse ecu definition files until result found
for (int i = 0; i < settings.getEcuDefinitionFiles().size(); i++) {
InputSource src = new InputSource(new FileInputStream(settings.getEcuDefinitionFiles().get(i)));
parser.parse(src);
Document doc = parser.getDocument();
try {
rom = domUms.unmarshallXMLDefinition(doc.getDocumentElement(), input, statusPanel);
statusPanel.update("Populating tables...", 50);
repaint();
rom.populateTables(input, statusPanel);
rom.setFileName(inputFile.getName());
statusPanel.update("Finalizing...", 90);
repaint();
addRom(rom);
rom.setFullFileName(inputFile);
return;
} catch (RomNotFoundException ex) {
// rom was not found in current file, skip to next
}
}
// if code executes to this point, no ROM was found, report to user
JOptionPane.showMessageDialog(this, "ECU Definition Not Found", "Error Loading " + inputFile.getName(), JOptionPane.ERROR_MESSAGE);
} catch (StackOverflowError ex) {
// handles looped inheritance, which will use up all available memory
JOptionPane.showMessageDialog(this, "Looped \"base\" attribute in XML definitions.", "Error Loading ROM", JOptionPane.ERROR_MESSAGE);
} finally {
// remove progress bar
//progress.dispose();
statusPanel.update("Ready...", 0);
}
}
private byte[] readFile(File inputFile) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
FileInputStream fis = new FileInputStream(inputFile);
try {
byte[] buf = new byte[8192];
int bytesRead;
while ((bytesRead = fis.read(buf)) != -1) {
baos.write(buf, 0, bytesRead);
}
} finally {
fis.close();
}
return baos.toByteArray();
}
}