Java tutorial
/* * Copyright (C) 2014 Raydac Research Group Ltd. * * 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 3 of the License, or * (at your option) any later version. * * This program is distributed getSignal 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, see <http://www.gnu.org/licenses/>. */ package com.igormaznitsa.zxpoly; import com.igormaznitsa.z80.Z80; import com.igormaznitsa.zxpoly.ui.SelectTapPosDialog; import com.igormaznitsa.zxpoly.utils.Utils; import com.igormaznitsa.zxpoly.components.*; import com.igormaznitsa.zxpoly.components.betadisk.BetaDiscInterface; import com.igormaznitsa.zxpoly.components.betadisk.TRDOSDisk; import com.igormaznitsa.zxpoly.formats.*; import com.igormaznitsa.zxpoly.tracer.TraceCPUForm; import com.igormaznitsa.zxpoly.ui.*; import com.igormaznitsa.zxpoly.utils.*; import java.awt.*; import java.awt.event.*; import java.awt.image.RenderedImage; import java.io.*; import java.lang.reflect.InvocationTargetException; import java.util.Locale; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Level; import java.util.logging.Logger; import javax.imageio.ImageIO; import javax.swing.*; import javax.swing.filechooser.FileFilter; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; public class MainForm extends javax.swing.JFrame implements Runnable, ActionListener { private static final Icon ICO_MOUSE = new ImageIcon(Utils.loadIcon("mouse.png")); private static final Icon ICO_MOUSE_DIS = UIManager.getLookAndFeel().getDisabledIcon(null, ICO_MOUSE); private static final Icon ICO_DISK = new ImageIcon(Utils.loadIcon("disk.png")); private static final Icon ICO_DISK_DIS = UIManager.getLookAndFeel().getDisabledIcon(null, ICO_DISK); private static final Icon ICO_TAPE = new ImageIcon(Utils.loadIcon("cassette.png")); private static final Icon ICO_TAPE_DIS = UIManager.getLookAndFeel().getDisabledIcon(null, ICO_TAPE); private static final Icon ICO_TURBO = new ImageIcon(Utils.loadIcon("turbo.png")); private static final Icon ICO_TURBO_DIS = UIManager.getLookAndFeel().getDisabledIcon(null, ICO_TURBO); private static final Icon ICO_ZX128 = new ImageIcon(Utils.loadIcon("zx128.png")); private static final Icon ICO_ZX128_DIS = UIManager.getLookAndFeel().getDisabledIcon(null, ICO_ZX128); private static final long TIMER_INT_DELAY_MILLISECONDS = 20L; private static final int HOW_MANY_INT_BETWEEN_SCREEN_REFRESH = 4; private volatile boolean turboMode = false; private File lastTapFolder; private File lastFloppyFolder; private File lastSnapshotFolder; private File lastScreenshotFolder; private final CPULoadIndicator indicatorCPU0 = new CPULoadIndicator(48, 14, 4, "CPU0", Color.GREEN, Color.DARK_GRAY, Color.WHITE); private final CPULoadIndicator indicatorCPU1 = new CPULoadIndicator(48, 14, 4, "CPU1", Color.GREEN, Color.DARK_GRAY, Color.WHITE); private final CPULoadIndicator indicatorCPU2 = new CPULoadIndicator(48, 14, 4, "CPU2", Color.GREEN, Color.DARK_GRAY, Color.WHITE); private final CPULoadIndicator indicatorCPU3 = new CPULoadIndicator(48, 14, 4, "CPU3", Color.GREEN, Color.DARK_GRAY, Color.WHITE); private final TraceCPUForm[] cpuTracers = new TraceCPUForm[4]; private final AtomicInteger activeTracerWindowCounter = new AtomicInteger(); private final Runnable traceWindowsUpdater = new Runnable() { @Override public void run() { int index = 0; for (final TraceCPUForm form : cpuTracers) { if (form != null) { final Z80 cpu = board.getZXPolyModules()[index++].getCPU(); if (cpu.getPrefixInProcessing() == 0 && !cpu.isInsideBlockLoop()) { form.refreshViewState(); } } } } }; private final Runnable infobarUpdater = new Runnable() { @Override public void run() { final Icon turboico = turboMode ? ICO_TURBO : ICO_TURBO_DIS; if (labelTurbo.getIcon() != turboico) { labelTurbo.setIcon(turboico); } final TapeFileReader reader = keyboardAndTapeModule.getTap(); final Icon tapico = reader != null && reader.isPlaying() ? ICO_TAPE : ICO_TAPE_DIS; if (labelTapeUsage.getIcon() != tapico) { labelTapeUsage.setIcon(tapico); } final Icon mouseIcon = board.getVideoController().isHoldMouse() ? ICO_MOUSE : ICO_MOUSE_DIS; if (labelMouseUsage.getIcon() != mouseIcon) { labelMouseUsage.setIcon(mouseIcon); } final Icon diskIcon = board.getBetaDiskInterface().isActive() ? ICO_DISK : ICO_DISK_DIS; if (labelDiskUsage.getIcon() != diskIcon) { labelDiskUsage.setIcon(diskIcon); } final Icon zx128Icon = board.isZXPolyMode() ? ICO_ZX128_DIS : ICO_ZX128; if (labelZX128.getIcon() != zx128Icon) { labelZX128.setIcon(zx128Icon); } if (panelIndicators.isVisible()) { indicatorCPU0.updateForState(board.getActivityCPU0()); indicatorCPU1.updateForState(board.getActivityCPU1()); indicatorCPU2.updateForState(board.getActivityCPU2()); indicatorCPU3.updateForState(board.getActivityCPU3()); } updateTracerCheckBoxes(); } }; private static class TRDFileFilter extends FileFilter { @Override public boolean accept(File f) { return f.isDirectory() || f.getName().toLowerCase(Locale.ENGLISH).endsWith(".trd"); } @Override public String getDescription() { return "TR-DOS image (*.trd)"; } } private static class PNGFileFilter extends FileFilter { @Override public boolean accept(File f) { return f.isDirectory() || f.getName().toLowerCase(Locale.ENGLISH).endsWith(".png"); } @Override public String getDescription() { return "PNG image (*.png)"; } } private static class SCLFileFilter extends FileFilter { @Override public boolean accept(File f) { return f.isDirectory() || f.getName().toLowerCase(Locale.ENGLISH).endsWith(".scl"); } @Override public String getDescription() { return "SCL image (*.scl)"; } } private static class TapFileFilter extends FileFilter { @Override public boolean accept(File f) { return f.isDirectory() || f.getName().toLowerCase(Locale.ENGLISH).endsWith(".tap"); } @Override public String getDescription() { return "TAP file (*.tap)"; } } private static class WavFileFilter extends FileFilter { @Override public boolean accept(File f) { return f.isDirectory() || f.getName().toLowerCase(Locale.ENGLISH).endsWith(".wav"); } @Override public String getDescription() { return "WAV file (*.wav)"; } } private static final long serialVersionUID = 7309959798344327441L; public static final Logger log = Logger.getLogger("UI"); private final Motherboard board; private final KeyboardKempstonAndTapeIn keyboardAndTapeModule; private final KempstonMouse kempstonMouse; private final ReentrantLock stepSemaphor = new ReentrantLock(); private static class KeyboardDispatcher implements KeyEventDispatcher { private final KeyboardKempstonAndTapeIn keyboard; public KeyboardDispatcher(final KeyboardKempstonAndTapeIn kbd) { this.keyboard = kbd; } @Override public boolean dispatchKeyEvent(KeyEvent e) { this.keyboard.onKeyEvent(e); return false; } } private RomData loadRom(final String romPath) throws IOException { if (romPath != null) { if (romPath.contains("://")) { try { final String cached = "loaded_" + Integer.toHexString(romPath.hashCode()).toUpperCase(Locale.ENGLISH) + ".rom"; final File cacheFolder = new File(AppOptions.getInstance().getAppConfigFolder(), "cache"); final File cachedRom = new File(cacheFolder, cached); RomData result = null; boolean load = true; if (cachedRom.isFile()) { log.info("Load cached ROM downloaded from '" + romPath + "' : " + cachedRom); result = new RomData(FileUtils.readFileToByteArray(cachedRom)); load = false; } if (load) { log.info("Load ROM from external URL: " + romPath); result = ROMLoader.getROMFrom(romPath); if (cacheFolder.isDirectory() || cacheFolder.mkdirs()) { FileUtils.writeByteArrayToFile(cachedRom, result.getAsArray()); log.info("Loaded ROM saved in cache as file : " + romPath); } } return result; } catch (Exception ex) { log.log(Level.WARNING, "Can't load ROM from '" + romPath + "\'", ex); } } else { log.info("Load ROM from embedded resource '" + romPath + "'"); return RomData.read(Utils.findResourceOrError("com/igormaznitsa/zxpoly/rom/" + romPath)); } } final String testRom = "zxpolytest.rom"; log.info("Load ROM from embedded resource '" + testRom + "'"); return RomData.read(Utils.findResourceOrError("com/igormaznitsa/zxpoly/rom/" + testRom)); } public MainForm(final String title, final String romPath) throws IOException { initComponents(); this.setTitle(title); this.getInputContext().selectInputMethod(Locale.ENGLISH); setIconImage(Utils.loadIcon("appico.png")); final RomData rom = loadRom(romPath); this.board = new Motherboard(rom); this.board.setZXPolyMode(true); this.menuOptionsZX128Mode.setSelected(!this.board.isZXPolyMode()); this.menuOptionsTurbo.setSelected(this.turboMode); log.info("Main form completed"); this.board.reset(); this.scrollPanel.getViewport().add(this.board.getVideoController()); this.keyboardAndTapeModule = this.board.findIODevice(KeyboardKempstonAndTapeIn.class); this.kempstonMouse = this.board.findIODevice(KempstonMouse.class); final KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); manager.addKeyEventDispatcher(new KeyboardDispatcher(this.keyboardAndTapeModule)); final GridBagConstraints cpuIndicatorConstraint = new GridBagConstraints(); cpuIndicatorConstraint.ipadx = 5; this.panelIndicators.add(this.indicatorCPU0, cpuIndicatorConstraint, 0); this.panelIndicators.add(this.indicatorCPU1, cpuIndicatorConstraint, 1); this.panelIndicators.add(this.indicatorCPU2, cpuIndicatorConstraint, 2); this.panelIndicators.add(this.indicatorCPU3, cpuIndicatorConstraint, 3); updateTapeMenu(); final Thread daemon = new Thread(this, "ZXPolyThread"); daemon.setDaemon(true); daemon.start(); updateInfoPanel(); pack(); this.setLocationRelativeTo(null); } private void updateTapeMenu() { final TapeFileReader reader = this.keyboardAndTapeModule.getTap(); if (reader == null) { this.menuTap.setEnabled(false); this.menuTapPlay.setSelected(false); this.menuTapExportAs.setEnabled(false); } else { this.menuTap.setEnabled(true); this.menuTapPlay.setSelected(reader.isPlaying()); this.menuTapExportAs.setEnabled(true); } } @Override public void run() { final int INT_TO_UPDATE_INFOPANEL = 20; long nextSystemInt = System.currentTimeMillis() + TIMER_INT_DELAY_MILLISECONDS; int countdownToPaint = 0; int countToUpdatePanel = INT_TO_UPDATE_INFOPANEL; while (!Thread.currentThread().isInterrupted()) { final long currentMachineCycleCounter = this.board.getCPU0().getMachineCycles(); long currentTime = System.currentTimeMillis(); stepSemaphor.lock(); try { final boolean systemIntSignal; if (nextSystemInt <= currentTime) { systemIntSignal = currentMachineCycleCounter >= VideoController.CYCLES_BETWEEN_INT; nextSystemInt = currentTime + TIMER_INT_DELAY_MILLISECONDS; this.board.getCPU0().resetMCycleCounter(); countdownToPaint--; countToUpdatePanel--; } else { systemIntSignal = false; } this.board.step(systemIntSignal, this.turboMode ? true : systemIntSignal || currentMachineCycleCounter <= VideoController.CYCLES_BETWEEN_INT); if (countdownToPaint <= 0) { countdownToPaint = HOW_MANY_INT_BETWEEN_SCREEN_REFRESH; updateScreen(); } if (countToUpdatePanel <= 0) { countToUpdatePanel = INT_TO_UPDATE_INFOPANEL; updateInfoPanel(); } } finally { stepSemaphor.unlock(); } if (this.activeTracerWindowCounter.get() > 0) { updateTracerWindowsForStep(); } } } private void updateTracerWindowsForStep() { try { SwingUtilities.invokeAndWait(this.traceWindowsUpdater); } catch (InterruptedException ex) { log.log(Level.INFO, "Interrupted trace window updater"); } catch (InvocationTargetException ex) { ex.printStackTrace(); log.log(Level.SEVERE, "Error in trace window updater", ex); } } public void setTurboMode(final boolean value) { this.turboMode = value; } public boolean isTurboMode() { return this.isTurboMode(); } private void updateScreen() { final VideoController vc = board.getVideoController(); vc.updateBuffer(); vc.paintImmediately(0, 0, vc.getWidth(), vc.getHeight()); ; } /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; scrollPanel = new javax.swing.JScrollPane(); jSeparator2 = new javax.swing.JSeparator(); panelIndicators = new javax.swing.JPanel(); filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0)); labelTurbo = new javax.swing.JLabel(); labelMouseUsage = new javax.swing.JLabel(); labelZX128 = new javax.swing.JLabel(); labelTapeUsage = new javax.swing.JLabel(); labelDiskUsage = new javax.swing.JLabel(); menuBar = new javax.swing.JMenuBar(); menuFile = new javax.swing.JMenu(); menuFileLoadSnapshot = new javax.swing.JMenuItem(); menuFileLoadTap = new javax.swing.JMenuItem(); menuLoadDrive = new javax.swing.JMenu(); menuFileSelectDiskA = new javax.swing.JMenuItem(); jMenuItem1 = new javax.swing.JMenuItem(); jMenuItem2 = new javax.swing.JMenuItem(); jMenuItem3 = new javax.swing.JMenuItem(); jSeparator1 = new javax.swing.JPopupMenu.Separator(); menuFileOptions = new javax.swing.JMenuItem(); jSeparator3 = new javax.swing.JPopupMenu.Separator(); menuFileExit = new javax.swing.JMenuItem(); menuTap = new javax.swing.JMenu(); menuTapeRewindToStart = new javax.swing.JMenuItem(); menuTapPrevBlock = new javax.swing.JMenuItem(); menuTapPlay = new javax.swing.JCheckBoxMenuItem(); menuTapNextBlock = new javax.swing.JMenuItem(); menuTapGotoBlock = new javax.swing.JMenuItem(); menuService = new javax.swing.JMenu(); menuFileReset = new javax.swing.JMenuItem(); menuResetKeyboard = new javax.swing.JMenuItem(); menuServiceSaveScreen = new javax.swing.JMenuItem(); menuTapExportAs = new javax.swing.JMenu(); menuTapExportAsWav = new javax.swing.JMenuItem(); menuTracer = new javax.swing.JMenu(); menuTraceCPU0 = new javax.swing.JCheckBoxMenuItem(); menuTraceCPU1 = new javax.swing.JCheckBoxMenuItem(); menuTraceCPU2 = new javax.swing.JCheckBoxMenuItem(); menuTraceCPU3 = new javax.swing.JCheckBoxMenuItem(); menuOptions = new javax.swing.JMenu(); menuOptionsShowIndicators = new javax.swing.JCheckBoxMenuItem(); menuOptionsZX128Mode = new javax.swing.JCheckBoxMenuItem(); menuOptionsTurbo = new javax.swing.JCheckBoxMenuItem(); menuHelp = new javax.swing.JMenu(); menuHelpAbout = new javax.swing.JMenuItem(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); setLocationByPlatform(true); addWindowFocusListener(new java.awt.event.WindowFocusListener() { public void windowGainedFocus(java.awt.event.WindowEvent evt) { formWindowGainedFocus(evt); } public void windowLostFocus(java.awt.event.WindowEvent evt) { formWindowLostFocus(evt); } }); scrollPanel.setViewportView(jSeparator2); getContentPane().add(scrollPanel, java.awt.BorderLayout.CENTER); panelIndicators.setBorder(javax.swing.BorderFactory.createEtchedBorder()); panelIndicators.setLayout(new java.awt.GridBagLayout()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 4; gridBagConstraints.gridy = 0; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1000.0; panelIndicators.add(filler1, gridBagConstraints); labelTurbo.setText(" "); labelTurbo.setToolTipText("Shows turbo mode on"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 5; gridBagConstraints.gridy = 0; panelIndicators.add(labelTurbo, gridBagConstraints); labelMouseUsage.setText(" "); labelMouseUsage.setToolTipText("Indicates kempston mouse activation, ESC - deactivate mouse"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 6; gridBagConstraints.gridy = 0; panelIndicators.add(labelMouseUsage, gridBagConstraints); labelZX128.setText(" "); labelZX128.setToolTipText("Shows that active ZX128 emulation mode"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 7; gridBagConstraints.gridy = 0; panelIndicators.add(labelZX128, gridBagConstraints); labelTapeUsage.setText(" "); labelTapeUsage.setToolTipText("Shows tape activity"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 8; gridBagConstraints.gridy = 0; panelIndicators.add(labelTapeUsage, gridBagConstraints); labelDiskUsage.setText(" "); labelDiskUsage.setToolTipText("Shows disk activity"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 9; gridBagConstraints.gridy = 0; panelIndicators.add(labelDiskUsage, gridBagConstraints); getContentPane().add(panelIndicators, java.awt.BorderLayout.SOUTH); menuFile.setText("File"); menuFileLoadSnapshot.setIcon( new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/zxpoly/icons/snapshot.png"))); // NOI18N menuFileLoadSnapshot.setText("Load Snapshot"); menuFileLoadSnapshot.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { menuFileLoadSnapshotActionPerformed(evt); } }); menuFile.add(menuFileLoadSnapshot); menuFileLoadTap.setIcon( new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/zxpoly/icons/cassette.png"))); // NOI18N menuFileLoadTap.setText("Load TAPE"); menuFileLoadTap.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { menuFileLoadTapActionPerformed(evt); } }); menuFile.add(menuFileLoadTap); menuLoadDrive.setIcon( new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/zxpoly/icons/disk.png"))); // NOI18N menuLoadDrive.setText("Load Disk.."); menuFileSelectDiskA.setText("Drive A"); menuFileSelectDiskA.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { menuFileSelectDiskAActionPerformed(evt); } }); menuLoadDrive.add(menuFileSelectDiskA); jMenuItem1.setText("Drive B"); jMenuItem1.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jMenuItem1ActionPerformed(evt); } }); menuLoadDrive.add(jMenuItem1); jMenuItem2.setText("Drive C"); jMenuItem2.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jMenuItem2ActionPerformed(evt); } }); menuLoadDrive.add(jMenuItem2); jMenuItem3.setText("Drive D"); jMenuItem3.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jMenuItem3ActionPerformed(evt); } }); menuLoadDrive.add(jMenuItem3); menuFile.add(menuLoadDrive); menuFile.add(jSeparator1); menuFileOptions.setIcon( new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/zxpoly/icons/settings.png"))); // NOI18N menuFileOptions.setText("Options"); menuFileOptions.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { menuFileOptionsActionPerformed(evt); } }); menuFile.add(menuFileOptions); menuFile.add(jSeparator3); menuFileExit.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F4, java.awt.event.InputEvent.ALT_MASK)); menuFileExit.setIcon( new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/zxpoly/icons/reset.png"))); // NOI18N menuFileExit.setText("Exit"); menuFileExit.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { menuFileExitActionPerformed(evt); } }); menuFile.add(menuFileExit); menuBar.add(menuFile); menuTap.setText("Tape"); menuTapeRewindToStart.setIcon(new javax.swing.ImageIcon( getClass().getResource("/com/igormaznitsa/zxpoly/icons/tape_previous.png"))); // NOI18N menuTapeRewindToStart.setText("Rewind to start"); menuTapeRewindToStart.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { menuTapeRewindToStartActionPerformed(evt); } }); menuTap.add(menuTapeRewindToStart); menuTapPrevBlock.setIcon(new javax.swing.ImageIcon( getClass().getResource("/com/igormaznitsa/zxpoly/icons/tape_backward.png"))); // NOI18N menuTapPrevBlock.setText("Prev block"); menuTapPrevBlock.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { menuTapPrevBlockActionPerformed(evt); } }); menuTap.add(menuTapPrevBlock); menuTapPlay.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F4, 0)); menuTapPlay.setText("Play"); menuTapPlay.setIcon( new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/zxpoly/icons/tape_play.png"))); // NOI18N menuTapPlay.setInheritsPopupMenu(true); menuTapPlay.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { menuTapPlayActionPerformed(evt); } }); menuTap.add(menuTapPlay); menuTapNextBlock.setIcon(new javax.swing.ImageIcon( getClass().getResource("/com/igormaznitsa/zxpoly/icons/tape_forward.png"))); // NOI18N menuTapNextBlock.setText("Next block"); menuTapNextBlock.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { menuTapNextBlockActionPerformed(evt); } }); menuTap.add(menuTapNextBlock); menuTapGotoBlock.setIcon( new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/zxpoly/icons/tape_pos.png"))); // NOI18N menuTapGotoBlock.setText("Go to block"); menuTapGotoBlock.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { menuTapGotoBlockActionPerformed(evt); } }); menuTap.add(menuTapGotoBlock); menuBar.add(menuTap); menuService.setText("Service"); menuFileReset.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F12, 0)); menuFileReset.setIcon( new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/zxpoly/icons/reset2.png"))); // NOI18N menuFileReset.setText("Reset"); menuFileReset.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { menuFileResetActionPerformed(evt); } }); menuService.add(menuFileReset); menuResetKeyboard.setIcon( new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/zxpoly/icons/keyboard.png"))); // NOI18N menuResetKeyboard.setText("Reset keyboard"); menuResetKeyboard.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { menuResetKeyboardActionPerformed(evt); } }); menuService.add(menuResetKeyboard); menuServiceSaveScreen.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F8, 0)); menuServiceSaveScreen.setIcon( new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/zxpoly/icons/photo.png"))); // NOI18N menuServiceSaveScreen.setText("Make Screenshot"); menuServiceSaveScreen.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { menuServiceSaveScreenActionPerformed(evt); } }); menuService.add(menuServiceSaveScreen); menuTapExportAs.setIcon(new javax.swing.ImageIcon( getClass().getResource("/com/igormaznitsa/zxpoly/icons/tape_record.png"))); // NOI18N menuTapExportAs.setText("Export TAPE as.."); menuTapExportAsWav.setText("WAV file"); menuTapExportAsWav.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { menuTapExportAsWavActionPerformed(evt); } }); menuTapExportAs.add(menuTapExportAsWav); menuService.add(menuTapExportAs); menuTracer.setText("Trace"); menuTraceCPU0.setText("CPU0"); menuTraceCPU0.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { menuTraceCPU0ActionPerformed(evt); } }); menuTracer.add(menuTraceCPU0); menuTraceCPU1.setText("CPU1"); menuTraceCPU1.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { menuTraceCPU1ActionPerformed(evt); } }); menuTracer.add(menuTraceCPU1); menuTraceCPU2.setText("CPU2"); menuTraceCPU2.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { menuTraceCPU2ActionPerformed(evt); } }); menuTracer.add(menuTraceCPU2); menuTraceCPU3.setText("CPU3"); menuTraceCPU3.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { menuTraceCPU3ActionPerformed(evt); } }); menuTracer.add(menuTraceCPU3); menuService.add(menuTracer); menuBar.add(menuService); menuOptions.setText("Options"); menuOptionsShowIndicators.setSelected(true); menuOptionsShowIndicators.setText("Indicator panel"); menuOptionsShowIndicators.setIcon( new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/zxpoly/icons/indicator.png"))); // NOI18N menuOptionsShowIndicators.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { menuOptionsShowIndicatorsActionPerformed(evt); } }); menuOptions.add(menuOptionsShowIndicators); menuOptionsZX128Mode.setSelected(true); menuOptionsZX128Mode.setText("ZX 128 Mode"); menuOptionsZX128Mode.setIcon( new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/zxpoly/icons/zx128.png"))); // NOI18N menuOptionsZX128Mode.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { menuOptionsZX128ModeActionPerformed(evt); } }); menuOptions.add(menuOptionsZX128Mode); menuOptionsTurbo.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F3, 0)); menuOptionsTurbo.setSelected(true); menuOptionsTurbo.setText("Turbo"); menuOptionsTurbo.setIcon( new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/zxpoly/icons/turbo.png"))); // NOI18N menuOptionsTurbo.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { menuOptionsTurboActionPerformed(evt); } }); menuOptions.add(menuOptionsTurbo); menuBar.add(menuOptions); menuHelp.setText("Help"); menuHelpAbout.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F1, 0)); menuHelpAbout.setIcon( new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/zxpoly/icons/info.png"))); // NOI18N menuHelpAbout.setText("About"); menuHelpAbout.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { menuHelpAboutActionPerformed(evt); } }); menuHelp.add(menuHelpAbout); menuBar.add(menuHelp); setJMenuBar(menuBar); pack(); }// </editor-fold>//GEN-END:initComponents private void menuFileResetActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuFileResetActionPerformed this.board.reset(); }//GEN-LAST:event_menuFileResetActionPerformed private void menuOptionsShowIndicatorsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuOptionsShowIndicatorsActionPerformed this.indicatorCPU0.clear(); this.indicatorCPU1.clear(); this.indicatorCPU2.clear(); this.indicatorCPU3.clear(); this.panelIndicators.setVisible(this.menuOptionsShowIndicators.isSelected()); }//GEN-LAST:event_menuOptionsShowIndicatorsActionPerformed private void loadDiskIntoDrive(final int drive) { this.stepSemaphor.lock(); try { final char diskName; switch (drive) { case BetaDiscInterface.DRIVE_A: diskName = 'A'; break; case BetaDiscInterface.DRIVE_B: diskName = 'B'; break; case BetaDiscInterface.DRIVE_C: diskName = 'C'; break; case BetaDiscInterface.DRIVE_D: diskName = 'D'; break; default: throw new Error("Unexpected drive index"); } final AtomicReference<FileFilter> filter = new AtomicReference<>(); final File selectedFile = chooseFileForOpen("Select Disk " + diskName, this.lastFloppyFolder, filter, new SCLFileFilter(), new TRDFileFilter()); if (selectedFile != null) { this.lastFloppyFolder = selectedFile.getParentFile(); try { final TRDOSDisk floppy = new TRDOSDisk( filter.get().getClass() == SCLFileFilter.class ? TRDOSDisk.Source.SCL : TRDOSDisk.Source.TRD, FileUtils.readFileToByteArray(selectedFile), false); this.board.getBetaDiskInterface().insertDiskIntoDrive(drive, floppy); log.info("Loaded drive " + diskName + " by floppy image file " + selectedFile); } catch (IOException ex) { log.log(Level.WARNING, "Can't read Floppy image file [" + selectedFile + ']', ex); JOptionPane.showMessageDialog(this, "Can't read Floppy image file", "Error", JOptionPane.ERROR_MESSAGE); } } } finally { this.stepSemaphor.unlock(); } } private void updateInfoPanel() { if (SwingUtilities.isEventDispatchThread()) { infobarUpdater.run(); } else { SwingUtilities.invokeLater(infobarUpdater); } } private void menuFileSelectDiskAActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuFileSelectDiskAActionPerformed loadDiskIntoDrive(BetaDiscInterface.DRIVE_A); }//GEN-LAST:event_menuFileSelectDiskAActionPerformed private void formWindowLostFocus(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowLostFocus this.stepSemaphor.lock(); try { this.keyboardAndTapeModule.doReset(); } finally { this.stepSemaphor.unlock(); } }//GEN-LAST:event_formWindowLostFocus private void formWindowGainedFocus(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowGainedFocus this.stepSemaphor.lock(); try { this.getInputContext().selectInputMethod(Locale.ENGLISH); this.keyboardAndTapeModule.doReset(); } finally { this.stepSemaphor.unlock(); } }//GEN-LAST:event_formWindowGainedFocus private void menuFileLoadSnapshotActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuFileLoadSnapshotActionPerformed stepSemaphor.lock(); try { this.board.forceResetCPUs(); this.board.resetIODevices(); final AtomicReference<FileFilter> theFilter = new AtomicReference<>(); final File selected = chooseFileForOpen("Select snapshot", this.lastSnapshotFolder, theFilter, new FormatZXP(), new FormatZ80(), new FormatSNA()); if (selected != null) { this.lastSnapshotFolder = selected.getParentFile(); try { final Snapshot selectedFilter = (Snapshot) theFilter.get(); log.info("Loading snapshot " + selectedFilter.getName()); selectedFilter.loadFromArray(this.board, this.board.getVideoController(), FileUtils.readFileToByteArray(selected)); } catch (Exception ex) { log.log(Level.WARNING, "Can't read snapshot file [" + ex.getMessage() + ']', ex); JOptionPane.showMessageDialog(this, "Can't read snapshot file [" + ex.getMessage() + ']', "Error", JOptionPane.ERROR_MESSAGE); } } } finally { stepSemaphor.unlock(); } }//GEN-LAST:event_menuFileLoadSnapshotActionPerformed private void menuOptionsZX128ModeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuOptionsZX128ModeActionPerformed this.stepSemaphor.lock(); try { this.board.setZXPolyMode(!this.menuOptionsZX128Mode.isSelected()); } finally { this.stepSemaphor.unlock(); } }//GEN-LAST:event_menuOptionsZX128ModeActionPerformed private void menuOptionsTurboActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuOptionsTurboActionPerformed this.turboMode = this.menuOptionsTurbo.isSelected(); }//GEN-LAST:event_menuOptionsTurboActionPerformed private void jMenuItem2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem2ActionPerformed loadDiskIntoDrive(BetaDiscInterface.DRIVE_C); }//GEN-LAST:event_jMenuItem2ActionPerformed private void jMenuItem1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem1ActionPerformed loadDiskIntoDrive(BetaDiscInterface.DRIVE_B); }//GEN-LAST:event_jMenuItem1ActionPerformed private void jMenuItem3ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem3ActionPerformed loadDiskIntoDrive(BetaDiscInterface.DRIVE_D); }//GEN-LAST:event_jMenuItem3ActionPerformed private void menuFileExitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuFileExitActionPerformed this.dispose(); }//GEN-LAST:event_menuFileExitActionPerformed private void menuTapGotoBlockActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuTapGotoBlockActionPerformed final TapeFileReader currentReader = this.keyboardAndTapeModule.getTap(); if (currentReader != null) { currentReader.stopPlay(); updateTapeMenu(); final SelectTapPosDialog dialog = new SelectTapPosDialog(this, currentReader); dialog.setVisible(true); final int selected = dialog.getSelectedIndex(); if (selected >= 0) { currentReader.setCurrent(selected); } } }//GEN-LAST:event_menuTapGotoBlockActionPerformed private void menuFileLoadTapActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuFileLoadTapActionPerformed final File selectedTapFile = chooseFileForOpen("Load Tape", this.lastTapFolder, null, new TapFileFilter()); if (selectedTapFile != null) { this.lastTapFolder = selectedTapFile.getParentFile(); InputStream in = null; try { in = new BufferedInputStream(new FileInputStream(selectedTapFile)); if (this.keyboardAndTapeModule.getTap() != null) { this.keyboardAndTapeModule.getTap().removeActionListener(this); } final TapeFileReader tapfile = new TapeFileReader(selectedTapFile.getAbsolutePath(), in); tapfile.addActionListener(this); this.keyboardAndTapeModule.setTap(tapfile); } catch (Exception ex) { log.log(Level.SEVERE, "Can't read " + selectedTapFile, ex); JOptionPane.showMessageDialog(this, "Can't load TAP file", ex.getMessage(), JOptionPane.ERROR_MESSAGE); } finally { IOUtils.closeQuietly(in); updateTapeMenu(); } } }//GEN-LAST:event_menuFileLoadTapActionPerformed private void menuTapExportAsWavActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuTapExportAsWavActionPerformed this.stepSemaphor.lock(); try { final byte[] wav = this.keyboardAndTapeModule.getTap().getAsWAV(); final File fileToSave = chooseFileForSave("Select WAV file", null, new WavFileFilter()); if (fileToSave != null) { FileUtils.writeByteArrayToFile(fileToSave, wav); log.info("Exported current TAP file as WAV file " + fileToSave + " size " + wav.length + " bytes"); } } catch (Exception ex) { ex.printStackTrace(); log.log(Level.WARNING, "Can't export as WAV", ex); JOptionPane.showMessageDialog(this, "Can't export as WAV", ex.getMessage(), JOptionPane.ERROR_MESSAGE); } finally { this.stepSemaphor.unlock(); } }//GEN-LAST:event_menuTapExportAsWavActionPerformed private void menuTapPlayActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuTapPlayActionPerformed if (this.menuTapPlay.isSelected()) { this.keyboardAndTapeModule.getTap().startPlay(); } else { this.keyboardAndTapeModule.getTap().stopPlay(); } updateTapeMenu(); }//GEN-LAST:event_menuTapPlayActionPerformed private void menuTapPrevBlockActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuTapPrevBlockActionPerformed final TapeFileReader tap = this.keyboardAndTapeModule.getTap(); if (tap != null) { tap.rewindToPrevBlock(); } updateTapeMenu(); }//GEN-LAST:event_menuTapPrevBlockActionPerformed private void menuTapNextBlockActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuTapNextBlockActionPerformed final TapeFileReader tap = this.keyboardAndTapeModule.getTap(); if (tap != null) { tap.rewindToNextBlock(); } updateTapeMenu(); }//GEN-LAST:event_menuTapNextBlockActionPerformed private void menuTapeRewindToStartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuTapeRewindToStartActionPerformed final TapeFileReader tap = this.keyboardAndTapeModule.getTap(); if (tap != null) { tap.rewindToStart(); } updateTapeMenu(); }//GEN-LAST:event_menuTapeRewindToStartActionPerformed private void menuServiceSaveScreenActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuServiceSaveScreenActionPerformed final RenderedImage img = this.board.getVideoController().makeCopyOfCurrentPicture(); final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); this.stepSemaphor.lock(); try { ImageIO.write(img, "png", buffer); final File thefile = chooseFileForSave("Save screenshot", lastScreenshotFolder, new PNGFileFilter()); if (thefile != null) { this.lastScreenshotFolder = thefile.getParentFile(); FileUtils.writeByteArrayToFile(thefile, buffer.toByteArray()); } } catch (IOException ex) { JOptionPane.showMessageDialog(this, "Can't save screenshot for error, see the log!", "Error", JOptionPane.ERROR_MESSAGE); log.log(Level.SEVERE, "Can't make screenshot", ex); } finally { this.keyboardAndTapeModule.doReset(); this.stepSemaphor.unlock(); } }//GEN-LAST:event_menuServiceSaveScreenActionPerformed private void menuResetKeyboardActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuResetKeyboardActionPerformed this.keyboardAndTapeModule.doReset(); }//GEN-LAST:event_menuResetKeyboardActionPerformed private void menuFileOptionsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuFileOptionsActionPerformed final OptionsDialog dialog = new OptionsDialog(this); dialog.setVisible(true); }//GEN-LAST:event_menuFileOptionsActionPerformed private void menuHelpAboutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuHelpAboutActionPerformed new AboutDialog(this).setVisible(true); }//GEN-LAST:event_menuHelpAboutActionPerformed private void menuTraceCPU0ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuTraceCPU0ActionPerformed if (this.menuTraceCPU0.isSelected()) { activateTracerForCPUModule(0); } else { deactivateTracerForCPUModule(0); } }//GEN-LAST:event_menuTraceCPU0ActionPerformed private void menuTraceCPU1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuTraceCPU1ActionPerformed if (this.menuTraceCPU1.isSelected()) { activateTracerForCPUModule(1); } else { deactivateTracerForCPUModule(1); } }//GEN-LAST:event_menuTraceCPU1ActionPerformed private void menuTraceCPU2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuTraceCPU2ActionPerformed if (this.menuTraceCPU2.isSelected()) { activateTracerForCPUModule(2); } else { deactivateTracerForCPUModule(2); } }//GEN-LAST:event_menuTraceCPU2ActionPerformed private void menuTraceCPU3ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuTraceCPU3ActionPerformed if (this.menuTraceCPU3.isSelected()) { activateTracerForCPUModule(3); } else { deactivateTracerForCPUModule(3); } }//GEN-LAST:event_menuTraceCPU3ActionPerformed private void activateTracerForCPUModule(final int index) { TraceCPUForm form = this.cpuTracers[index]; if (form == null) { form = new TraceCPUForm(this, this.board, index); form.setVisible(true); } form.toFront(); form.requestFocus(); } private void deactivateTracerForCPUModule(final int index) { TraceCPUForm form = this.cpuTracers[index]; if (form != null) { form.dispose(); } } private void updateTracerCheckBoxes() { this.menuTraceCPU0.setSelected(this.cpuTracers[0] != null); this.menuTraceCPU1.setSelected(this.cpuTracers[1] != null); this.menuTraceCPU2.setSelected(this.cpuTracers[2] != null); this.menuTraceCPU3.setSelected(this.cpuTracers[3] != null); } public void onTracerActivated(final TraceCPUForm tracer) { final int index = tracer.getModuleIndex(); this.cpuTracers[index] = tracer; updateTracerCheckBoxes(); this.activeTracerWindowCounter.incrementAndGet(); } public void onTracerDeactivated(final TraceCPUForm tracer) { final int index = tracer.getModuleIndex(); this.cpuTracers[index] = null; updateTracerCheckBoxes(); this.activeTracerWindowCounter.decrementAndGet(); } private File chooseFileForOpen(final String title, final File initial, final AtomicReference<FileFilter> selectedFilter, final FileFilter... filter) { final JFileChooser chooser = new JFileChooser(initial); for (final FileFilter f : filter) { chooser.addChoosableFileFilter(f); } chooser.setAcceptAllFileFilterUsed(false); chooser.setMultiSelectionEnabled(false); chooser.setDialogTitle(title); chooser.setFileFilter(filter[0]); chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); final File result; if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { result = chooser.getSelectedFile(); if (selectedFilter != null) { selectedFilter.set(chooser.getFileFilter()); } } else { result = null; } return result; } private File chooseFileForSave(final String title, final File initial, final FileFilter filter) { final JFileChooser chooser = new JFileChooser(initial); chooser.addChoosableFileFilter(filter); chooser.setAcceptAllFileFilterUsed(true); chooser.setMultiSelectionEnabled(false); chooser.setDialogTitle(title); chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); final File result; if (chooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) { result = chooser.getSelectedFile(); } else { result = null; } return result; } @Override public void actionPerformed(final ActionEvent e) { if (e.getSource() instanceof TapeFileReader) { updateTapeMenu(); } } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.Box.Filler filler1; private javax.swing.JMenuItem jMenuItem1; private javax.swing.JMenuItem jMenuItem2; private javax.swing.JMenuItem jMenuItem3; private javax.swing.JPopupMenu.Separator jSeparator1; private javax.swing.JSeparator jSeparator2; private javax.swing.JPopupMenu.Separator jSeparator3; private javax.swing.JLabel labelDiskUsage; private javax.swing.JLabel labelMouseUsage; private javax.swing.JLabel labelTapeUsage; private javax.swing.JLabel labelTurbo; private javax.swing.JLabel labelZX128; private javax.swing.JMenuBar menuBar; private javax.swing.JMenu menuFile; private javax.swing.JMenuItem menuFileExit; private javax.swing.JMenuItem menuFileLoadSnapshot; private javax.swing.JMenuItem menuFileLoadTap; private javax.swing.JMenuItem menuFileOptions; private javax.swing.JMenuItem menuFileReset; private javax.swing.JMenuItem menuFileSelectDiskA; private javax.swing.JMenu menuHelp; private javax.swing.JMenuItem menuHelpAbout; private javax.swing.JMenu menuLoadDrive; private javax.swing.JMenu menuOptions; private javax.swing.JCheckBoxMenuItem menuOptionsShowIndicators; private javax.swing.JCheckBoxMenuItem menuOptionsTurbo; private javax.swing.JCheckBoxMenuItem menuOptionsZX128Mode; private javax.swing.JMenuItem menuResetKeyboard; private javax.swing.JMenu menuService; private javax.swing.JMenuItem menuServiceSaveScreen; private javax.swing.JMenu menuTap; private javax.swing.JMenu menuTapExportAs; private javax.swing.JMenuItem menuTapExportAsWav; private javax.swing.JMenuItem menuTapGotoBlock; private javax.swing.JMenuItem menuTapNextBlock; private javax.swing.JCheckBoxMenuItem menuTapPlay; private javax.swing.JMenuItem menuTapPrevBlock; private javax.swing.JMenuItem menuTapeRewindToStart; private javax.swing.JCheckBoxMenuItem menuTraceCPU0; private javax.swing.JCheckBoxMenuItem menuTraceCPU1; private javax.swing.JCheckBoxMenuItem menuTraceCPU2; private javax.swing.JCheckBoxMenuItem menuTraceCPU3; private javax.swing.JMenu menuTracer; private javax.swing.JPanel panelIndicators; private javax.swing.JScrollPane scrollPanel; // End of variables declaration//GEN-END:variables }