/** * Copyright 2012 Tobias Gierke <tobias.gierke@code-sourcery.de> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.codesourcery.jasm16.ide.ui.views; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.SwingUtilities; import org.apache.commons.lang.StringUtils; import de.codesourcery.jasm16.Address; import de.codesourcery.jasm16.Size; import de.codesourcery.jasm16.emulator.EmulationListener; import de.codesourcery.jasm16.emulator.IEmulationListener; import de.codesourcery.jasm16.emulator.IEmulator; import de.codesourcery.jasm16.emulator.memory.MemUtils; import de.codesourcery.jasm16.ide.ui.utils.PagingKeyAdapter; import de.codesourcery.jasm16.utils.Misc; public class HexDumpView extends AbstractView { public static final String VIEW_ID = "hexdump-view"; private JPanel panel; private final JTextArea textArea = new JTextArea(); private IEmulator emulator; private Address dumpStartAddress = Address.wordAddress( 0x0 ); private int numberOfWordsPerLine = 8; private boolean printASCII = true; private final IEmulationListener listener = new EmulationListener() { @Override public void afterCommandExecution(IEmulator emulator, int commandDuration) { if ( ! isFullSpeedMode() ) { refreshDisplay(); } } @Override public void afterReset(IEmulator emulator) { if ( ! isFullSpeedMode() ) { refreshDisplay(); } } @Override public void afterMemoryLoad(IEmulator emulator, Address startAddress, int lengthInBytes) { if ( ! isFullSpeedMode() ) { refreshDisplay(); } } @Override public void onStopHook(IEmulator emulator, Address previousPC, Throwable emulationError) { refreshDisplay(); } }; public HexDumpView(IEmulator emulator) { setEmulator( emulator ); } public HexDumpView() { } @Override public void refreshDisplay() { if ( emulator == null ) { return; } SwingUtilities.invokeLater( new Runnable() { @Override public void run() { final byte[] data = MemUtils.getBytes( emulator.getMemory() , dumpStartAddress , calcSizeOfVisibleMemory(), true ); textArea.setText( Misc.toHexDumpWithAddresses(dumpStartAddress, data, data.length , numberOfWordsPerLine , printASCII, true) ); } }); } protected Size calcSizeOfVisibleMemory() { int rows = calculateVisibleTextRowCount( textArea ); if ( rows < 1 ) { rows = 1; } return Size.words( rows * numberOfWordsPerLine ); } public void setEmulator(IEmulator emulator) { if (emulator == null) { throw new IllegalArgumentException("emulator must not be NULL."); } if ( this.emulator == emulator ) { return; } if ( this.emulator != null ) { this.emulator.removeEmulationListener( listener ); } this.emulator = emulator; emulator.addEmulationListener( listener ); } @Override public void disposeHook() { if ( this.emulator != null ) { this.emulator.removeEmulationListener( listener ); this.emulator = null; } } protected JPanel createPanel() { textArea.setEditable( false ); setColors( textArea ); textArea.setFont( getMonospacedFont() ); textArea.setEditable( false ); // dump panel final JPanel dumpPanel = new JPanel(); setColors( dumpPanel ); dumpPanel.setLayout( new GridBagLayout() ); GridBagConstraints cnstrs = constraints( 0 , 0 , true , true , GridBagConstraints.BOTH ); dumpPanel.add( textArea , cnstrs ); // toolbar panel final JPanel toolbarPanel = new JPanel(); setColors( toolbarPanel ); toolbarPanel.setLayout( new GridBagLayout() ); cnstrs = constraints( 0 , 0 , false , false , GridBagConstraints.NONE); toolbarPanel.add( new JLabel("Goto") , cnstrs ); final JTextField gotoTextfield = new JTextField(); gotoTextfield.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { final String val = gotoTextfield.getText(); Address adr; if ( StringUtils.isBlank( val ) ) { gotoTextfield.setText("0000"); adr = Address.wordAddress( 0 ); } else { try { adr = Address.wordAddress( Misc.parseHexString( val ) ); } catch (NumberFormatException e1) { gotoTextfield.setText("0000"); adr = Address.wordAddress( 0 ); } } dumpStartAddress = adr; refreshDisplay(); } }); cnstrs = constraints( 0 , 1 , true , true , GridBagConstraints.HORIZONTAL ); toolbarPanel.add( gotoTextfield , cnstrs ); // create result panel final JPanel result = new JPanel(); setColors( result ); result.setLayout( new GridBagLayout() ); cnstrs = constraints( 0 , 0 , false , true , GridBagConstraints.BOTH ); result.add( dumpPanel , cnstrs ); cnstrs = constraints( 1 , 0 , true , true , GridBagConstraints.VERTICAL ); result.add( toolbarPanel , cnstrs ); textArea.addKeyListener( new PagingKeyAdapter() { @Override protected void onePageUp() { HexDumpView.this.onePageUp(); } @Override protected void onePageDown() { HexDumpView.this.onePageDown(); } @Override protected void oneLineUp() { HexDumpView.this.oneLineUp(); } @Override protected void oneLineDown() { HexDumpView.this.oneLineDown(); } }); result.addComponentListener( new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { refreshDisplay(); } }); return result; } private void onePageDown() { dumpStartAddress = dumpStartAddress.plus( calcSizeOfVisibleMemory() , true ); refreshDisplay(); } private void oneLineDown() { dumpStartAddress = dumpStartAddress.plus( Size.words( numberOfWordsPerLine ) , true ); refreshDisplay(); } private void onePageUp() { dumpStartAddress = dumpStartAddress.minus( calcSizeOfVisibleMemory() ); refreshDisplay(); } private void oneLineUp() { dumpStartAddress = dumpStartAddress.minus( Size.words( numberOfWordsPerLine ) ); refreshDisplay(); } @Override public JPanel getPanel() { if ( panel == null ) { panel = createPanel(); } return panel; } @Override public String getTitle() { return "memory view"; } @Override public String getID() { return VIEW_ID; } }