/*******************************************************************************
* This file is part of logisim-evolution.
*
* logisim-evolution 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 3 of the License, or
* (at your option) any later version.
*
* logisim-evolution 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 logisim-evolution. If not, see <http://www.gnu.org/licenses/>.
*
* Original code by Carl Burch (http://www.cburch.com), 2011.
* Subsequent modifications by :
* + Haute École Spécialisée Bernoise
* http://www.bfh.ch
* + Haute École du paysage, d'ingénierie et d'architecture de Genève
* http://hepia.hesge.ch/
* + Haute École d'Ingénierie et de Gestion du Canton de Vaud
* http://www.heig-vd.ch/
* The project is currently maintained by :
* + REDS Institute - HEIG-VD
* Yverdon-les-Bains, Switzerland
* http://reds.heig-vd.ch
*******************************************************************************/
/**
* Code taken from Cornell's version of Logisim:
* http://www.cs.cornell.edu/courses/cs3410/2015sp/
*/
package com.cburch.logisim.gui.test;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import com.cburch.logisim.circuit.Circuit;
import com.cburch.logisim.circuit.Simulator;
import com.cburch.logisim.circuit.SimulatorEvent;
import com.cburch.logisim.circuit.SimulatorListener;
import com.cburch.logisim.data.TestException;
import com.cburch.logisim.data.TestVector;
import com.cburch.logisim.gui.menu.LogisimMenuBar;
import com.cburch.logisim.proj.Project;
import com.cburch.logisim.proj.ProjectEvent;
import com.cburch.logisim.proj.ProjectListener;
import com.cburch.logisim.util.LocaleListener;
import com.cburch.logisim.util.LocaleManager;
import com.cburch.logisim.util.StringUtil;
import com.cburch.logisim.util.WindowMenuItemManager;
public class TestFrame extends JFrame {
private class MyListener implements ActionListener, ProjectListener,
SimulatorListener, LocaleListener, ModelListener {
public void actionPerformed(ActionEvent event) {
Object src = event.getSource();
if (src == close) {
WindowEvent e = new WindowEvent(TestFrame.this,
WindowEvent.WINDOW_CLOSING);
TestFrame.this.processWindowEvent(e);
} else if (src == load) {
int result = chooser.showOpenDialog(TestFrame.this);
if (result != JFileChooser.APPROVE_OPTION)
return;
File file = chooser.getSelectedFile();
if (!file.exists() || !file.canRead() || file.isDirectory()) {
JOptionPane.showMessageDialog(
TestFrame.this,
StringUtil.format(
Strings.get("fileCannotReadMessage"),
file.getName()),
Strings.get("fileCannotReadTitle"),
JOptionPane.OK_OPTION);
return;
}
try {
TestVector vec = new TestVector(file);
finished = 0;
count = vec.data.size();
getModel().setVector(vec);
curFile = file;
getModel().setPaused(true);
getModel().start();
} catch (IOException e) {
JOptionPane.showMessageDialog(
TestFrame.this,
StringUtil.format(
Strings.get("fileCannotParseMessage"),
file.getName(), e.getMessage()),
Strings.get("fileCannotReadTitle"),
JOptionPane.OK_OPTION);
} catch (TestException e) {
JOptionPane.showMessageDialog(
TestFrame.this,
StringUtil.format(
Strings.get("fileWrongPinsMessage"),
file.getName(), e.getMessage()),
Strings.get("fileWrongPinsTitle"),
JOptionPane.OK_OPTION);
}
} else if (src == run) {
try {
getModel().start();
} catch (TestException e) {
JOptionPane.showMessageDialog(TestFrame.this, StringUtil
.format(Strings.get("fileWrongPinsMessage"),
curFile.getName(), e.getMessage()), Strings
.get("fileWrongPinsTitle"), JOptionPane.OK_OPTION);
}
} else if (src == stop) {
getModel().setPaused(true);
} else if (src == reset) {
getModel().clearResults();
testingChanged();
}
}
public void localeChanged() {
setTitle(computeTitle(curModel, project));
panel.localeChanged();
load.setText(Strings.get("loadButton"));
run.setText(Strings.get("runButton"));
stop.setText(Strings.get("stopButton"));
reset.setText(Strings.get("resetButton"));
close.setText(Strings.get("closeButton"));
myListener.testResultsChanged(getModel().getPass(), getModel()
.getFail());
windowManager.localeChanged();
}
public void projectChanged(ProjectEvent event) {
int action = event.getAction();
if (action == ProjectEvent.ACTION_SET_STATE) {
setSimulator(event.getProject().getSimulator(), event
.getProject().getCircuitState().getCircuit());
} else if (action == ProjectEvent.ACTION_SET_FILE) {
setTitle(computeTitle(curModel, project));
}
}
public void propagationCompleted(SimulatorEvent e) {
// curModel.propagationCompleted();
}
public void simulatorStateChanged(SimulatorEvent e) {
}
public void testingChanged() {
if (getModel().isRunning() && !getModel().isPaused()) {
run.setEnabled(false);
stop.setEnabled(true);
} else if (getModel().getVector() != null && finished != count) {
run.setEnabled(true);
stop.setEnabled(false);
} else {
run.setEnabled(false);
stop.setEnabled(false);
}
reset.setEnabled(getModel().getVector() != null && finished > 0);
}
public void testResultsChanged(int numPass, int numFail) {
pass.setText(StringUtil.format(Strings.get("passMessage"),
Integer.toString(numPass)));
fail.setText(StringUtil.format(Strings.get("failMessage"),
Integer.toString(numFail)));
finished = numPass + numFail;
}
public void tickCompleted(SimulatorEvent e) {
}
public void vectorChanged() {
}
}
private class WindowMenuManager extends WindowMenuItemManager implements
LocaleListener, ProjectListener {
WindowMenuManager() {
super(Strings.get("logFrameMenuItem"), false);
project.addProjectListener(this);
}
public JFrame getJFrame(boolean create) {
return TestFrame.this;
}
public void localeChanged() {
String title = project.getLogisimFile().getDisplayName();
setText(StringUtil.format(Strings.get("testFrameMenuItem"), title));
}
public void projectChanged(ProjectEvent event) {
if (event.getAction() == ProjectEvent.ACTION_SET_FILE) {
localeChanged();
}
}
}
private static String computeTitle(Model data, Project proj) {
String name = data == null ? "???" : data.getCircuit().getName();
return StringUtil.format(Strings.get("testFrameTitle"), name, proj
.getLogisimFile().getDisplayName());
}
private static final long serialVersionUID = 1L;
private Project project;
private Simulator curSimulator = null;
private Model curModel;
private Map<Circuit, Model> modelMap = new HashMap<Circuit, Model>();
private MyListener myListener = new MyListener();
private WindowMenuManager windowManager;
private int finished, count;
private File curFile;
private JFileChooser chooser = new JFileChooser();
private TestPanel panel;
private JButton load = new JButton();
private JButton run = new JButton();
private JButton stop = new JButton();
private JButton reset = new JButton();
private JButton close = new JButton();
private JLabel pass = new JLabel();
private JLabel fail = new JLabel();
public TestFrame(Project project) {
this.project = project;
this.windowManager = new WindowMenuManager();
project.addProjectListener(myListener);
setDefaultCloseOperation(HIDE_ON_CLOSE);
setJMenuBar(new LogisimMenuBar(this, project));
setSimulator(project.getSimulator(), project.getCircuitState()
.getCircuit());
chooser.addChoosableFileFilter(chooser.getAcceptAllFileFilter());
chooser.addChoosableFileFilter(TestVector.FILE_FILTER);
chooser.setFileFilter(TestVector.FILE_FILTER);
panel = new TestPanel(this);
JPanel statusPanel = new JPanel();
statusPanel.add(pass);
statusPanel.add(fail);
JPanel buttonPanel = new JPanel();
buttonPanel.add(load);
buttonPanel.add(run);
buttonPanel.add(stop);
buttonPanel.add(reset);
buttonPanel.add(close);
load.addActionListener(myListener);
run.addActionListener(myListener);
stop.addActionListener(myListener);
reset.addActionListener(myListener);
close.addActionListener(myListener);
run.setEnabled(false);
stop.setEnabled(false);
reset.setEnabled(false);
Container contents = getContentPane();
panel.setPreferredSize(new Dimension(450, 300));
contents.add(statusPanel, BorderLayout.NORTH);
contents.add(panel, BorderLayout.CENTER);
contents.add(buttonPanel, BorderLayout.SOUTH);
LocaleManager.addLocaleListener(myListener);
myListener.localeChanged();
pack();
}
Model getModel() {
return curModel;
}
public Project getProject() {
return project;
}
private void setSimulator(Simulator value, Circuit circuit) {
if ((value == null) == (curModel == null)) {
if (value == null
|| value.getCircuitState().getCircuit() == curModel
.getCircuit())
return;
}
// LogisimMenuBar menubar = (LogisimMenuBar) getJMenuBar();
// menubar.setCircuitState(value, state);
if (curSimulator != null)
curSimulator.removeSimulatorListener(myListener);
if (curModel != null)
curModel.setSelected(false);
if (curModel != null)
curModel.removeModelListener(myListener);
Model oldModel = curModel;
Model data = null;
if (value != null) {
data = modelMap.get(value.getCircuitState().getCircuit());
if (data == null) {
data = new Model(project, value.getCircuitState().getCircuit());
modelMap.put(data.getCircuit(), data);
}
}
curSimulator = value;
curModel = data;
if (curSimulator != null)
curSimulator.addSimulatorListener(myListener);
if (curModel != null)
curModel.setSelected(true);
if (curModel != null)
curModel.addModelListener(myListener);
setTitle(computeTitle(curModel, project));
if (panel != null)
panel.modelChanged(oldModel, curModel);
}
public void setVisible(boolean value) {
if (value)
windowManager.frameOpened(this);
super.setVisible(value);
}
}