/******************************************************************************* * 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 *******************************************************************************/ /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package com.cburch.logisim.gui.menu; /*import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import javax.swing.text.BadLocationException; import javax.swing.text.Highlighter; import javax.swing.text.JTextComponent;*/ import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.io.File; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.Set; import java.util.prefs.Preferences; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComboBox; import javax.swing.JEditorPane; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.filechooser.FileFilter; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import com.cburch.logisim.circuit.Circuit; import com.cburch.logisim.circuit.CircuitState; import com.cburch.logisim.circuit.SimulatorEvent; import com.cburch.logisim.circuit.SimulatorListener; import com.cburch.logisim.comp.Component; import com.cburch.logisim.data.Value; import com.cburch.logisim.file.Options; import com.cburch.logisim.gui.generic.LFrame; import com.cburch.logisim.instance.StdAttr; import com.cburch.logisim.proj.Project; import com.cburch.logisim.std.memory.Register; import com.cburch.logisim.std.wiring.Clock; import java.awt.Color; import javax.swing.text.DefaultHighlighter; public class AssemblyWindow implements ActionListener, WindowListener, SimulatorListener, KeyListener { private Preferences prefs; private LFrame windows; private JMenuBar winMenuBar; private JCheckBoxMenuItem ontopItem; private JMenuItem openFileItem; private JMenuItem reloadFileItem; private JMenuItem close; private JButton refresh = new JButton("Get Registers"); private JLabel status = new JLabel(); private final JEditorPane document = new JEditorPane(); @SuppressWarnings("rawtypes") private JComboBox combo = new JComboBox<>(); private HashMap<String, Component> entry = new HashMap<String, Component>(); private Component selReg = null; private Project proj; private static Circuit curCircuit; private static CircuitState curCircuitState; private File file; public AssemblyWindow(Project proj) { this.proj = proj; curCircuit = proj.getCurrentCircuit(); curCircuitState = proj.getCircuitState(); winMenuBar = new JMenuBar(); JMenu windowMenu = new JMenu("Window"); JMenu fileMenu = new JMenu("File"); JPanel main = new JPanel(new BorderLayout()); JPanel north = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 2)); /* LinePainter painter = new LinePainter(document); */ windowMenu.setMnemonic('W'); fileMenu.setMnemonic('F'); combo.addActionListener(this); combo.setFocusable(false); refresh.addActionListener(this); refresh.setFocusable(false); refresh.setToolTipText("Get register list of current displayed circuit."); ontopItem = new JCheckBoxMenuItem("Set on top", true); ontopItem.addActionListener(this); openFileItem = new JMenuItem("Open lss file"); openFileItem.addActionListener(this); reloadFileItem = new JMenuItem("Reload lss file"); reloadFileItem.addActionListener(this); close = new JMenuItem("Close"); close.addActionListener(this); winMenuBar.add(fileMenu); winMenuBar.add(windowMenu); winMenuBar.setFocusable(false); windowMenu.add(ontopItem); fileMenu.add(openFileItem); fileMenu.add(reloadFileItem); fileMenu.addSeparator(); fileMenu.add(close); windows = new LFrame(); windows.setTitle("Assembly: " + proj.getLogisimFile().getDisplayName()); windows.setJMenuBar(winMenuBar); windows.toFront(); windows.setAlwaysOnTop(true); windows.setVisible(false); windows.addWindowListener(this); windows.addKeyListener(this); north.add(new JLabel("Register: ")); north.add(combo); north.add(refresh); document.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12)); document.setEditable(false); document.setPreferredSize(new Dimension(document.getWidth() * 4 / 5, Math.max(200, document.getHeight() * 2 / 3))); document.addKeyListener(this); main.add(new JScrollPane(document), BorderLayout.CENTER); main.add(north, BorderLayout.NORTH); main.add(status, BorderLayout.SOUTH); windows.setContentPane(main); proj.getSimulator().addSimulatorListener(this); windows.pack(); prefs = Preferences.userRoot().node(this.getClass().getName()); windows.setLocation(prefs.getInt("X", 0), prefs.getInt("Y", 0)); windows.setSize(prefs.getInt("W", windows.getSize().width), prefs.getInt("H", windows.getSize().height)); } @Override public void actionPerformed(ActionEvent e) { Object src = e.getSource(); if (src == ontopItem) { e.paramString(); windows.setAlwaysOnTop(ontopItem.getState()); } else if (src == openFileItem) { final JFileChooser fileChooser = proj.createChooser(); FileFilter ff = new FileFilter() { @Override public boolean accept(File f) { return f.isDirectory() || f.getName().toLowerCase().endsWith(".lss"); } @Override public String getDescription() { return ".lss disassembly file"; } }; fileChooser.setFileFilter(ff); fileChooser.setAcceptAllFileFilterUsed(false); int result = fileChooser.showOpenDialog(windows); if (result == JFileChooser.APPROVE_OPTION) { file = fileChooser.getSelectedFile(); try { if (file.getName().toLowerCase().endsWith(".lss")) { status.setText(""); document.setPage(file.toURI().toURL()); } else { status.setText("Wrong file selected !"); file = null; } } catch (Exception ex) { status.setText("Cannot open file !"); file = null; } } // Allow reload of same file document.getDocument().putProperty( Document.StreamDescriptionProperty, null); windows.invalidate(); } else if (src == reloadFileItem) { if (file != null) { try { document.setPage(file.toURI().toURL()); status.setText("File reloaded."); } catch (Exception ex) { status.setText("Cannot open file !"); file = null; } } windows.invalidate(); } else if (src == refresh) { curCircuit = proj.getCurrentCircuit(); curCircuitState = proj.getCircuitState(); fillCombo(); updateHighlightLine(); } else if (src == combo) { updateHighlightLine(); } else if (src == close) { setVisible(false); } } @SuppressWarnings("unchecked") private void fillCombo() { Set<Component> comps = curCircuit.getNonWires(); Iterator<Component> iter = comps.iterator(); entry.clear(); while (iter.hasNext()) { Component comp = iter.next(); if (comp.getFactory().getName().equals("Register")) { if (!comp.getAttributeSet().getValue(StdAttr.LABEL).equals("")) { entry.put(comp.getAttributeSet().getValue(StdAttr.LABEL), comp); } } } combo.removeAllItems(); if (entry.isEmpty()) { status.setText("No labeled registers found."); combo.setEnabled(false); } else { status.setText(""); combo.setEnabled(true); Object[] objArr = entry.keySet().toArray(); Arrays.sort(objArr); for (int i = 0; i < objArr.length; i++) { combo.addItem(objArr[i]); } } } public boolean isVisible() { if (windows != null) { return windows.isVisible(); } else { return false; } } @Override public void keyPressed(KeyEvent ke) { // throw new UnsupportedOperationException("Not supported yet."); } @Override public void keyReleased(KeyEvent ke) { int keyCode = ke.getKeyCode(); if (keyCode == KeyEvent.VK_F2) { int ticks = 0; for (com.cburch.logisim.comp.Component clock : proj .getLogisimFile().getMainCircuit().getClocks()) { if (clock.getAttributeSet().getValue(StdAttr.LABEL) .contentEquals("clk")) { if (proj.getOptions().getAttributeSet() .getValue(Options.ATTR_TICK_MAIN) .equals(Options.TICK_MAIN_HALF_PERIOD)) { if (proj.getCircuitState() .getValue(clock.getLocation()).toIntValue() == 0) { ticks = clock.getAttributeSet().getValue( Clock.ATTR_LOW); } else { ticks = clock.getAttributeSet().getValue( Clock.ATTR_HIGH); } } else { ticks = clock.getAttributeSet() .getValue(Clock.ATTR_LOW) + clock.getAttributeSet().getValue( Clock.ATTR_HIGH); } break; } } proj.getSimulator().tickMain(ticks); } } @Override public void keyTyped(KeyEvent ke) { // throw new UnsupportedOperationException("Not supported yet."); } @Override public void propagationCompleted(SimulatorEvent e) { if (e.getSource().isRunning()) { updateHighlightLine(); } } public void setTitle(String title) { windows.setTitle(title); } public void setVisible(boolean bool) { fillCombo(); windows.setVisible(bool); } @Override public void simulatorStateChanged(SimulatorEvent e) { } /* * Track the movement of the Caret by painting a background line at the * current caret position. */ @Override public void tickCompleted(SimulatorEvent e) { } public void toFront() { if (windows != null) { windows.toFront(); } } private void updateHighlightLine() { String where; if (combo.getSelectedItem() != null) { selReg = entry.get(combo.getSelectedItem().toString()); Value val = curCircuitState.getInstanceState(selReg).getPortValue( Register.OUT); if (val.isFullyDefined()) { where = val.toHexString().replaceAll("^0*", ""); if (where.isEmpty()) { where = "0"; } Pattern pattern = Pattern.compile("^[ ]+" + where + ":", Pattern.MULTILINE + Pattern.CASE_INSENSITIVE); Matcher m = pattern.matcher(document.getText().replaceAll("\r", "")); if (m.find()) { document.setCaretPosition(m.start()); status.setText(""); try { //bug fix, highligh active line document.getHighlighter().removeAllHighlights(); DefaultHighlighter.DefaultHighlightPainter highlightPainter = new DefaultHighlighter.DefaultHighlightPainter(Color.LIGHT_GRAY); document.getHighlighter().addHighlight(m.start(), m.end(), highlightPainter); } catch (BadLocationException ex) { ex.printStackTrace(); } } else { status.setText("Line (" + where + ") not found!"); } } } } @Override public void windowActivated(WindowEvent e) { } @Override public void windowClosed(WindowEvent e) { } @Override public void windowClosing(WindowEvent e) { } @Override public void windowDeactivated(WindowEvent e) { prefs.putInt("X", windows.getX()); prefs.putInt("Y", windows.getY()); prefs.putInt("W", windows.getWidth()); prefs.putInt("H", windows.getHeight()); } @Override public void windowDeiconified(WindowEvent e) { } @Override public void windowIconified(WindowEvent e) { } @Override public void windowOpened(WindowEvent e) { } }