//============================================================================== // HexDumpGui.java //============================================================================== package tribble.gui; // System imports import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.AdjustmentEvent; import java.awt.event.AdjustmentListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.lang.Class; import java.lang.Integer; import java.lang.Runnable; import java.lang.String; import java.lang.System; import java.lang.Thread; import java.lang.Throwable; import java.util.Date; import java.util.TimeZone; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollBar; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.SwingConstants; import javax.swing.event.TableModelEvent; import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.JTableHeader; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; // Local imports // (None) /******************************************************************************* * Hexadecimal file displayer. * Displays the contents of a file in hexadecimal form in a GUI window. * * *
* Bugs * *
*
* This is the crux of the entire GUI application. It operates by * maintaining a 64 KB buffer of the contents of the data file being * displayed by the GUI. The 64 KB buffer is composed of two 32 KB * ({@link #BUF_SIZE}) buffers, which together comprise a contiguous window * into the data file at any given moment. * *
* The display window (the table pane) represents the contents of a portion
* of the 64 KB file buffer. As the table pane is scrolled up or down, the
* file buffer is adjusted accordingly. Smooth scrolling (one line at a
* time) causes the two 32 KB halves of the buffer to be shifted and one of
* them to be re-filled with data read from the data file. More coarse
* scrolling causes both buffer halves to be re-filled appropriately.
*
*
* @param addr
* Starting address (offset) of the date within the file.
* Sixteen (16, 0x0010) bytes or less will be read into the buffer.
*
* @param offsets
* A two-element array whose elements are modified: the first element is set
* to the offset within the returned array of the first data byte for address
* addr, and the second element is set to the last (maximum) offset
* contained within the returned array.
*
* @return
* A byte array (buffer) containing the requested data contents.
* The contents of offsets are also modified.
*
* @throws IOException
* Throw if an I/O (read) error occurs while reading the contents of the data
* file.
*
* @since 1.1, 2005-04-30
*/
protected byte[] locateData(long addr, int[] offsets)
throws IOException
{
// Check if a buffer refresh (read) is necessary
if (addr < m_lowAddr)
{
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
if (addr < m_lowAddr - BUF_SIZE)
{
// Refill both lower and upper buffers
m_lowAddr = (addr/BUF_SIZE)*BUF_SIZE;
// Fill the lower and (possibly) the upper buffer
m_in.seek(m_lowAddr);
if (m_in.read(m_data[0]) >= m_data.length)
m_in.read(m_data[1]);
}
else
{
byte[] tmp;
// Shift the buffers down and fill the lower buffer
tmp = m_data[1];
m_data[1] = m_data[0];
m_data[0] = tmp;
// Fill the lower buffer
m_lowAddr -= BUF_SIZE;
m_in.seek(m_lowAddr);
m_in.read(m_data[0]);
}
this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
else if (addr >= m_lowAddr + 2*BUF_SIZE)
{
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
if (addr >= m_lowAddr + 3*BUF_SIZE)
{
///+Also recheck the file size if the very last row is selected
// Refill both lower and upper buffers
m_lowAddr = (addr/BUF_SIZE - 1)*BUF_SIZE;
// Fill the lower and (possibly) the upper buffer
m_in.seek(m_lowAddr);
if (m_in.read(m_data[0]) >= m_data.length)
m_in.read(m_data[1]);
}
else
{
byte[] tmp;
long fsize;
///+Also recheck the file size if the very last row is selected
// Shift the buffers up and fill the upper buffer
tmp = m_data[0];
m_data[0] = m_data[1];
m_data[1] = tmp;
// Check the data file length again, in case it has changed
fsize = m_fname.length();
if (fsize != m_fileSize)
{
System.out.println("$ locateData: file size changed to: " + fsize);
///+++INCOMPLETE
// The data file size has changed,
// so the display must be redrawn
///...
m_fileSize = fsize;
}
// Fill the upper buffer
m_lowAddr += BUF_SIZE;
m_in.seek(m_lowAddr + BUF_SIZE);
m_in.read(m_data[1]);
}
this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
// Locate the address within the current buffer
addr -= m_lowAddr;
offsets[0] = (int) addr;
offsets[1] = BUF_SIZE;
///+TEMPORARY, FOR TESTING ONLY
///if (addr == 0x00002000)
///throw new IOException("Invalid TEST offset: " + Long.toHexString(addr));
if (addr < BUF_SIZE)
{
// Use the lower buffer
if (m_fileSize < m_lowAddr + BUF_SIZE)
offsets[1] = (int) (m_fileSize - m_lowAddr);
return (m_data[0]);
}
else
{
// Use the upper buffer
offsets[0] -= BUF_SIZE;
if (m_fileSize < m_lowAddr + 2*BUF_SIZE)
offsets[1] = (int) (m_fileSize - (m_lowAddr+BUF_SIZE));
return (m_data[1]);
}
}
/***************************************************************************
* Display a warning dialog for an I/O error that has occurred.
*
* @param ex
* The I/O exception that occurred.
*
* @param addr
* The file address/offset where the exception occurred, in the form
* "XX XXXX XXXX".
*
* @since 1.7, 2005-04-30
*/
protected void showIOException(IOException ex, long addr)
{
String[] msg;
System.out.println("% showIOException: " + ex.getMessage());
// Create a warning dialog panel
msg = new String[5];
msg[0] = "I/O Error";
msg[1] = "\n";
msg[2] = "File: " + m_fname.getName();
msg[3] = "Address: " + addressAsHex(addr) + 'H';
msg[4] = ex.getMessage();
JOptionPane.showMessageDialog(this, msg,
PROG, JOptionPane.ERROR_MESSAGE);
///+INCOMPLETE
///...reset display window offsets, etc.,
///...to prevent an infinite Warning loop
}
/***************************************************************************
* Convert a file address/offset into its hexadecimal form.
*
* @param addr
* A file address/offset.
*
* @return
* A string of the form "HHHH HHHH".
*
* @since 1.8, 2005-06-01
*/
protected String addressAsHex(long addr)
{
int i, j;
// Convert an address/offset into its hex form "HH HHHH HHHH"
for (i = 8, j = 8; i > 0; i--)
{
int d;
if (i == 4)
m_charBuf[j--] = ' ';
d = (int) (addr & 0x0F);
addr >>>= 4;
d = (d < 0xA ? d+'0' : d-0xA+'A');
m_charBuf[j--] = (char) d;
}
return (new String(m_charBuf, 0, 8+1));
}
/***************************************************************************
* Convert a file address/offset into its decimal form.
*
* @param addr
* A file address/offset.
*
* @param fill
* If true, right-justify the returned string by padding it with leading
* spaces, otherwise return the string unpadded.
*
* @return
* A string of the form "D,DDD,DDD,DDD" (leading zeros are
* replaced with spaces).
*
* @since 1.10, 2005-06-07
*/
protected String addressAsDec(long addr, boolean fill)
{
int i, j;
// Convert an address/offset into its decimal form "DDD,DDD,DDD,DDD"
for (i = 10, j = 10+2; i > 0; i--)
{
int d;
if (i == 1 || i == 4 || i == 7)
m_charBuf[j--] = ',';
d = (int) (addr % 10);
addr /= 10;
m_charBuf[j--] = (char) (d + '0');
if (addr == 0)
break;
}
if (fill)
{
while (j >= 0)
m_charBuf[j--] = ' ';
}
return (new String(m_charBuf, j+1, 10+2-j));
}
/***************************************************************************
* Convert a file address/offset into its octal form.
*
* @param addr
* A file address/offset.
*
* @return
* A string of the form "QQQ QQQQ QQQQ".
*
* @since 1.10, 2005-06-07
*/
protected String addressAsOct(long addr)
{
int i, j;
// Convert an address/offset into its octal form "QQQ QQQQ QQQQ"
for (i = 11, j = 11+1; i > 0; i--)
{
int d;
if (i == 3 || i == 7)
m_charBuf[j--] = ' ';
d = (int) (addr & 0x07);
addr >>>= 3;
m_charBuf[j--] = (char) (d + '0');
}
return (new String(m_charBuf, 0, 11+2));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Inner classes
/***************************************************************************
* Hexadecimal file displayer helper class.
* Displays the contents of a file in hexadecimal form in a GUI window.
*
*
* @version $Revision: 1.11 $ $Date: 2005/06/27 03:42:14 $
* @since {@link HexDumpGui} 1.1, 2005-04-15
* @author David R. Tribble
* (david@tribble.com).
*
*
* Copyright ©2005 by David R. Tribble, all rights reserved.
*
* Permission is granted to freely use and distribute this source
* code provided that the original copyright and authorship notices
* remain intact.
*/
static class MyTableModel
extends javax.swing.table.AbstractTableModel
{
// Identification
/** Revision information. */
static final String REV =
"@(#)tribble/gui/HexDumpGui.java $Revision: 1.11 $ $Date: 2005/06/27 03:42:14 $\n";
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Private constants
// Special display characters
private static final char CHAR_BUL = (char) 0x2022;
private static final char CHAR_DOT = (char) 0x2022;
private static final char CHAR_BOX = (char) 0x2423;
// or 2022,20DE,2610,2423,25AF
// Address radix types
private static final short ADDR_RADIX_HEX =
HexDumpGui.ADDR_RADIX_HEX;
private static final short ADDR_RADIX_DEC =
HexDumpGui.ADDR_RADIX_DEC;
private static final short ADDR_RADIX_OCT =
HexDumpGui.ADDR_RADIX_OCT;
// Data radix types
private static final short DATA_RADIX_HEX = 0;
private static final short DATA_RADIX_DEC = 1;
private static final short DATA_RADIX_OCT = 2;
// ASCII/EBCDIC character conversion table
// Based on ISO 8859-1 (Latin-1, ASCII) and IBM CP 1047
private static final String EBCDIC_CP_01047s =
/* 0x00 */ "\u0100\u0101\u0102\u0103\u0080\u0109\u0081\u007F"
/* 0x08 */ + "\u0082\u0083\u0084\u010B\u010C\u010D\u010E\u010F"
/* 0x10 */ + "\u0110\u0111\u0112\u0113\u0085\u010A\u0108\u0086"
/* 0x18 */ + "\u0118\u0119\u0087\u0088\u011C\u011D\u011E\u011F"
/* 0x20 */ + "\u0089\u008A\u008B\u008C\u008D\u008E\u0117\u011B"
/* 0x28 */ + "\u008F\u0090\u0091\u0092\u0093\u0105\u0106\u0107"
/* 0x30 */ + "\u0094\u0095\u0116\u0096\u0097\u0098\u0099\u0104"
/* 0x38 */ + "\u009A\u009B\u009C\u009D\u0114\u0115\u009E\u011A"
/* 0x40 */ + "\u0020\u00A0\u00E2\u00E4\u00E0\u00E1\u00E3\u00E5"
/* 0x48 */ + "\u00E7\u00F1\u00A2\u002E\u003C\u0028\u002B\u007C"
/* 0x50 */ + "\u0026\u00E9\u00EA\u00EB\u00E8\u00ED\u00EE\u00EF"
/* 0x58 */ + "\u00EC\u00DF\u0021\u0024\u002A\u0029\u003B\u005E"
/* 0x60 */ + "\u002D\u002F\u00C2\u00C4\u00C0\u00C1\u00C3\u00C5"
/* 0x68 */ + "\u00C7\u00D1\u00A6\u002C\u0025\u005F\u003E\u003F"
/* 0x70 */ + "\u00F8\u00C9\u00CA\u00CB\u00C8\u00CD\u00CE\u00CF"
/* 0x78 */ + "\u00CC\u0060\u003A\u0023\u0040\u0027\u003D\u0122"
/* 0x80 */ + "\u00D8\u0061\u0062\u0063\u0064\u0065\u0066\u0067"
/* 0x88 */ + "\u0068\u0069\u00AB\u00BB\u00F0\u00FD\u00FE\u00B1"
/* 0x90 */ + "\u00B0\u006A\u006B\u006C\u006D\u006E\u006F\u0070"
/* 0x98 */ + "\u0071\u0072\u00AA\u00BA\u00E6\u00B8\u00C6\u00A4"
/* 0xA0 */ + "\u00B5\u007E\u0073\u0074\u0075\u0076\u0077\u0078"
/* 0xA8 */ + "\u0079\u007A\u00A1\u00BF\u00D0\u005B\u00DE\u00AE"
/* 0xB0 */ + "\u00AC\u00A3\u00A5\u00B7\u00A9\u00A7\u00B6\u00BC"
/* 0xB8 */ + "\u00BD\u00BE\u00DD\u00A8\u00AF\u005D\u00B4\u00D7"
/* 0xC0 */ + "\u007B\u0041\u0042\u0043\u0044\u0045\u0046\u0047"
/* 0xC8 */ + "\u0048\u0049\u00AD\u00F4\u00F6\u00F2\u00F3\u00F5"
/* 0xD0 */ + "\u007D\u004A\u004B\u004C\u004D\u004E\u004F\u0050"
/* 0xD8 */ + "\u0051\u0052\u00B9\u00FB\u00FC\u00F9\u00FA\u00FF"
/* 0xE0 */ + "\u015C\u00F7\u0053\u0054\u0055\u0056\u0057\u0058"
/* 0xE8 */ + "\u0059\u005A\u00B2\u00D4\u00D6\u00D2\u00D3\u00D5"
/* 0xF0 */ + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037"
/* 0xF8 */ + "\u0038\u0039\u00B3\u00DB\u00DC\u00D9\u00DA\u009F";
private static final byte[] EBCDIC_CP =
new byte[0x100];
{
for (int i = 0x00; i < 0x100; i++)
EBCDIC_CP[i] = (byte) EBCDIC_CP_01047s.charAt(i);
}
private static final byte[] ASCII_CP =
new byte[0x100];
{
for (int i = 0x00; i < 0x100; i++)
ASCII_CP[i] = (byte) i;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Private variables
/** Parent hexadecimal file displayer object. */
private HexDumpGui m_mom;
/** Hex character buffer. */
private char[] m_charBuf =
new char[80];
/** Data buffer offsets. */
private int[] m_offs =
new int[2];
/** Current address display radix setting. */
private short m_addrRadix =
ADDR_RADIX_HEX;
/** Current data display radix setting. */
private short m_dataRadix =
DATA_RADIX_HEX;
/** Current character display type setting. */
private byte[] m_charTable =
ASCII_CP;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Constructors
/***********************************************************************
* Constructor.
*
* @param parent
* Parent hexadecimal file displayer object for this table model.
*
* @since 1.1, 2005-04-15
*/
MyTableModel(HexDumpGui parent)
{
// Initialize
m_mom = parent;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Public methods
/**********************************************************************/
public int getColumnCount()
//overrides javax.swing.table.AbstractTableModel
{
System.out.println("> getColumnCount: " + m_mom.COL__MAX);
return (m_mom.COL__MAX);
}
/**********************************************************************/
int rowCount_; ///+TEMPORARY
public int getRowCount()
//overrides javax.swing.table.AbstractTableModel
{
long m;
int n;
///+FIX THIS to limit the return value to Integer.MAX
// Determine the total number of rows in the hex display table
m = (m_mom.m_fileSize+0x10-1) / 0x10;
if (m > 0x7FFFFFFFL)
m = 0x7FFFFFFFL;
n = (int) m;
if (n != rowCount_)
System.out.println("> getRowCount: " + n);
rowCount_ = n;
return (n);
}
/**********************************************************************/
public String getColumnName(int col)
//overrides javax.swing.table.AbstractTableModel
{
System.out.println("> getColumnName(" + col + ")");
return ("");
}
/**********************************************************************/
public Object getValueAt(int row, int col)
//overrides javax.swing.table.AbstractTableModel
{
long addr;
// Determine the file offset for the displayed data block
addr = row*0x10L + m_mom.m_startAddr;
if (addr >= m_mom.m_fileSize)
return ("?");
// Build the displayable text for the column
try
{
int off;
int max;
byte[] data;
String s;
int pb;
int i, j;
// Build the displayable text for the column
switch (col)
{
case COL_ADDRESS:
///+Optimize by prebuilding a string "0000.0000|0000.0010|..." for the current
///+data buffer, then just doling out substrings of it
// Location/address column
switch (m_addrRadix)
{
case ADDR_RADIX_HEX:
default:
return (m_mom.addressAsHex(addr));
case ADDR_RADIX_DEC:
return (m_mom.addressAsDec(addr, true));
case ADDR_RADIX_OCT:
return (m_mom.addressAsOct(addr));
}
//--------------------------------
case COL_DATA:
// Hexadecimal byte data column
data = m_mom.locateData(addr, m_offs);
off = m_offs[0];
max = m_offs[1];
pb = -1;
// hex "HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH"
// word "HHHH HHHH HHHH HHHH HHHH HHHH HHHH HHHH"
// dec "DDD DDD DDD DDD DDD DDD DDD DDD DDD DDD DDD DDD DDD DDD DDD DDD"
// oct "QQQ QQQ QQQ QQQ QQQ QQQ QQQ QQQ QQQ QQQ QQQ QQQ QQQ QQQ QQQ QQQ"
for (i = 0, j = 0; i < 0x10 && off+i < max; i++)
{
int b;
int b2;
int d;
// Format the next data byte
b = data[off+i] & 0xFF;
b2 = m_charTable[data[off+i] & 0xFF];
//if (i > 0)
// m_charBuf[j++] = ' ';
if (i > 0)
{
if ((b2 < 0x0A || b2 > 0x0D) &&
(pb >= 0x0A && pb <= 0x0D))
m_charBuf[j++] = CHAR_BUL;
else
m_charBuf[j++] = ' ';
}
pb = b2;
if (i%4 == 0)
m_charBuf[j++] = ' ';
d = b >>> 4;
d = (d < 0xA ? d+'0' : d-0xA+'A');
m_charBuf[j++] = (char) d;
d = b & 0x0F;
d = (d < 0xA ? d+'0' : d-0xA+'A');
m_charBuf[j++] = (char) d;
if (i == 0x10-1 || off+i == max-1)
{
if (b2 >= 0x0A && b2 <= 0x0D)
m_charBuf[j++] = CHAR_BUL;
else
m_charBuf[j++] = ' ';
}
}
while (j < 0x10*3 + 4)
m_charBuf[j++] = ' ';
return (new String(m_charBuf, 0, j));
//--------------------------------
case COL_CHARACTERS:
// Character byte data column
data = m_mom.locateData(addr, m_offs);
off = m_offs[0];
max = m_offs[1];
for (i = 0; i < 0x10 && off+i < max; i++)
{
int b;
b = m_charTable[data[off+i] & 0xFF];
if (b >= 0x0A && b <= 0x0D)
b = CHAR_DOT;
else if (b < 0x20)
b = CHAR_BOX;
else if (b >= 0x7F && b < 0xA0)
b = CHAR_BOX;
m_charBuf[i] = (char) b;
}
return (new String(m_charBuf, 0, i));
//--------------------------------
default:
throw new RuntimeException();
}
}
catch (IOException ex)
{
TableModelEvent evt;
System.out.println("$ IOException (" + Long.toHexString(addr) + "): "
+ ex.getMessage());
// Display a pop-up warning
m_mom.showIOException(ex, addr);
///+++INCOMPLETE
// I/O error occurred,
// remove the offending row from the displayed table
row = (row > 0 ? row-1 : 0);
m_mom.m_fileSize = (row*0x10L + m_mom.m_startAddr);
// Trigger a table change event
hasChanged(row);
return ("????????");
}
}
/***********************************************************************
* Determines the default renderer/editor for each table column.
*
* @since 1.1, 2005-04-15
*/
public Class getColumnClass(int col)
//overrides javax.swing.table.AbstractTableModel
{
return (String.class);
}
/*+++NOT NEEDED
/***********************************************************************
* Don't need to implement this method unless the table is editable.
*
* @since 1.1, 2005-04-15
*\/
public boolean isCellEditable(int row, int col)
//overrides javax.swing.table.AbstractTableModel
{
// Note that the data/cell address is constant,
// no matter where the cell appears onscreen
return (false);
}
+++*/
/*+++NOT NEEDED
/***********************************************************************
* Don't need to implement this method unless the table's data can
* change.
*
* @since 1.1, 2005-04-15
*\/
public void setValueAt(Object value, int row, int col)
//overrides javax.swing.table.AbstractTableModel
{
// Do nothing
///data[row][col] = value;
///fireTableCellUpdated(row, col);
}
+++*/
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Package private methods
/***********************************************************************
* Rotate the setting type of a table column.
*
* @since 1.10, 2005-06-07
*/
void bump(int col)
{
///System.out.println("% model.bump(" + col + ")");
// Rotate the current setting for a column
switch (col)
{
case COL_ADDRESS:
m_addrRadix++;
if (m_addrRadix > ADDR_RADIX_OCT)
m_addrRadix = ADDR_RADIX_HEX;
m_mom.m_addrRadix = m_addrRadix;
break;
case COL_DATA:
m_dataRadix++;
if (m_dataRadix > DATA_RADIX_OCT)
m_dataRadix = DATA_RADIX_HEX;
break;
case COL_CHARACTERS:
m_charTable = (m_charTable == ASCII_CP ? EBCDIC_CP : ASCII_CP);
break;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Private methods
/***********************************************************************
* Fire a table change event.
*
* @param row
* Last table row index known to be valid (displayable).
*
* @since 1.7, 2005-05-10
*/
private void hasChanged(int row)
{
TableModelEvent evt;
System.out.println("$ hasChanged");
// Trigger a table change event
evt = new TableModelEvent(this, row, row,
TableModelEvent.ALL_COLUMNS, TableModelEvent.DELETE);
fireTableChanged(evt);
}
}
/***************************************************************************
* Hexadecimal file displayer helper class.
* Renders the column headings of the displayable table window of the GUI.
*
*
* @version $Revision: 1.11 $ $Date: 2005/06/27 03:42:14 $
* @since {@link HexDumpGui} 1.10, 2005-06-07
* @author David R. Tribble
* (david@tribble.com).
*
*
* Copyright ©2005 by David R. Tribble, all rights reserved.
*
* Permission is granted to freely use and distribute this source
* code provided that the original copyright and authorship notices
* remain intact.
*/
static class MyHeaderRenderer
extends javax.swing.table.DefaultTableCellRenderer
implements javax.swing.table.TableCellRenderer,
///+++NEW, NECESSARY?
java.awt.event.ActionListener
{
// Identification
/** Revision information. */
static final String REV =
"@(#)tribble/gui/HexDumpGui.java $Revision: 1.11 $ $Date: 2005/06/27 03:42:14 $\n";
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Private constants
// "Address" column header labels
private static final String COL_ADDR_HEX = "Address";
private static final String COL_ADDR_DEC = "Address";
private static final String COL_ADDR_OCT = "Address";
// "Data" column header labels
private static final String COL_DATA_HEX = "Data - Hexadecimal";
private static final String COL_DATA_DEC = "Data - Decimal";
private static final String COL_DATA_OCT = "Data - Octal";
// "Character" column header labels
private static final String COL_CHAR_ASC = "Character";
private static final String COL_CHAR_EBC = "EBCDIC";
// Table column header button accelerator mnemonics
private static final char COL_ACC_ADDR = 'A';
private static final char COL_ACC_DATA = 'D';
private static final char COL_ACC_CHAR = 'C';
// Table column accelerator mnemonics
private static final char[] MNEMONICS =
{
COL_ACC_ADDR,
COL_ACC_DATA,
COL_ACC_CHAR,
};
// Table column header labels
private static final String[][] HEADINGS =
{
///+TEMPORARY, REMOVE WHEN IMPLEMENTED
{ COL_ADDR_HEX, COL_ADDR_DEC, COL_ADDR_OCT },
{ COL_DATA_HEX },
{ COL_CHAR_ASC, COL_CHAR_EBC },
///+RESTORE WHEN IMPLEMENTED
{ COL_ADDR_HEX, COL_ADDR_DEC, COL_ADDR_OCT },
{ COL_DATA_HEX, COL_DATA_DEC, COL_DATA_OCT },
{ COL_CHAR_ASC, COL_CHAR_EBC },
};
// Table column action commands
private static final String[] COMMANDS =
{
HexDumpGui.CMD_BUT_ADDR,
HexDumpGui.CMD_BUT_DATA,
HexDumpGui.CMD_BUT_CHAR,
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Private variables
/** Parent hexadecimal file displayer object. */
private HexDumpGui m_mom;
/** Column header label button. */
private JButton m_button =
new JButton();
/** Column header index. */
private short m_col;
/** Current column header setting. */
private short m_setting;
/** Maximum column header setting. */
private short m_max;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Constructors
/***********************************************************************
* Constructor.
*
* @param parent
* Parent hexadecimal file displayer object for this table model.
*
* @param col
* Header column index.
*
* @since 1.10, 2005-06-07
*/
MyHeaderRenderer(HexDumpGui parent, int col)
{
// Initialize
m_mom = parent;
m_col = (short) col;
m_max = (short) HEADINGS[col].length;
/*+++INCOMPLETE,EXPERIMENTAL
m_button.setMnemonic(MNEMONICS[col]);
m_button.setActionCommand(COMMANDS[col]);
m_button.addActionListener(this);
+++*/
System.out.println("% MyHeaderRenderer.ctor: col=" + m_col + " max=" + m_max);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Public methods
/**********************************************************************
* Handles table column header button events for the GUI.
*
* @param ev
* The button event, which will contain a command string equal to one of
* the CMD_XXX_YYY constants.
*
* @since 1.11, 2005-06-12
*/
///+++NEW, NECESSARY?
public void actionPerformed(ActionEvent ev)
//implements java.awt.event.ActionListener
{
String cmd;
String val;
// Retrieve the action's command
cmd = ev.getActionCommand();
System.out.println("% actionPerformed: '" + cmd + "'");
/*+++INCOMPLETE
if (cmd == CMD_FILE_EXIT)
{
...;
}
...;
///System.out.println("&& mouse.click (" + loc.x + "," + loc.y
///+ ") col:" + col);
// Rotate the column setting
m_rends[col].bump();
m_model.bump(col);
+++*/
}
/***********************************************************************
* Renders a column heading of the hexadecimal file dump table.
*
* @param tbl
* The table containing the cell to be rendered.
*
* @param val
* The cell value to render.
*
* @param isSelected
* True if the cell (row) is currently selected.
*
* @param hasFocus
* True if the cell (row) has focus, i.e., was the last one selected.
*
* @param row
* Cell's row index (Y coordinate).
*
* @param col
* Cell's column index (X coordinate).
* Note: this is the actual index for the column as it is
* currently displayed, which might not be the same as the logical
* column index (i.e., one of the
* {@link #HexDumpGui.COL_ADDRESS HexDumpGui.COL_XXX}) constants.
*
* @since 1.10, 2005-06-07
*/
public Component getTableCellRendererComponent(JTable tbl, Object val,
boolean isSelected, boolean hasFocus, int row, int col)
//implements javax.swing.table.TableCellRenderer
{
///System.out.println("&& hdr.render(" + row + "," + col + ":" + m_col
///+ (col == m_col ? "" : "!") + "): " + m_setting + " "
///+ (isSelected ? "S" : " ") + (hasFocus ? "F" : ""));
// Set the column header text
// Note: Ignore 'col' and use 'm_col' instead
m_button.setText(HEADINGS[m_col][m_setting]);
return (m_button);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Package private methods
/***********************************************************************
* Retrieve the button for this table column header.
*
* @since 1.11, 2005-06-11
*/
///+++NEW, NECESSARY?
JButton getButton()
{
// Retrieve the button for the column header
return (m_button);
}
/***********************************************************************
* Rotate the setting of the table column header.
*
* @since 1.10, 2005-06-07
*/
void bump()
{
// Rotate the current setting for the column header
m_setting++;
if (m_setting >= m_max)
m_setting = 0;
///System.out.println("% rend.bump(" + m_col + "): " + m_setting);
}
}
/***************************************************************************
* Hexadecimal file displayer helper class.
* Renders the displayable contents of a file in hexadecimal form in a GUI
* table window.
*
*
* @version $Revision: 1.11 $ $Date: 2005/06/27 03:42:14 $
* @since {@link HexDumpGui} 1.9, 2005-06-01
* @author David R. Tribble
* (david@tribble.com).
*
*
* Copyright ©2005 by David R. Tribble, all rights reserved.
*
* Permission is granted to freely use and distribute this source
* code provided that the original copyright and authorship notices
* remain intact.
*/
static class MyCellRenderer
extends javax.swing.table.DefaultTableCellRenderer
implements javax.swing.table.TableCellRenderer
{
// Identification
/** Revision information. */
static final String REV =
"@(#)tribble/gui/HexDumpGui.java $Revision: 1.11 $ $Date: 2005/06/27 03:42:14 $\n";
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Private variables
/** Parent hexadecimal file displayer object. */
private HexDumpGui m_mom;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Constructors
/***********************************************************************
* Constructor.
*
* @param parent
* Parent hexadecimal file displayer object for this table model.
*
* @since 1.9, 2005-06-01
*/
MyCellRenderer(HexDumpGui parent)
{
// Initialize
m_mom = parent;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Public methods
/***********************************************************************
* Renders a cell within the hexadecimal file dump table.
*
* @param tbl
* The table containing the cell to be rendered.
*
* @param val
* The cell value to render.
*
* @param isSelected
* True if the cell (row) is currently selected.
*
* @param hasFocus
* True if the cell (row) has focus, i.e., was the last one selected.
*
* @param row
* Cell's row number (Y coordinate).
*
* @param
* Cell's column number (X coordinate).
*
* @since 1.9, 2005-06-01
*/
public Component getTableCellRendererComponent(JTable tbl, Object val,
boolean isSelected, boolean hasFocus, int row, int col)
//implements javax.swing.table.TableCellRenderer
{
JLabel comp;
long addr;
///System.out.println("&& render[" + col + "," + row + "] "
///+ (isSelected ? "S" : " ") + (hasFocus ? "F" : ""));
// Format and retrieve the component text
if (hasFocus)
isSelected = true;
comp = (JLabel) super.getTableCellRendererComponent(tbl, val,
isSelected, false, row, col);
comp.setHorizontalAlignment((col == COL_ADDRESS)
? SwingConstants.CENTER : SwingConstants.LEFT);
// Reset the current address/offset display field
if (isSelected && col == COL_ADDRESS)
{
// Determine the file offset for the displayed data block
addr = row*0x10L + m_mom.m_startAddr;
m_mom.setFileAddress(addr);
}
return (comp);
}
}
/***************************************************************************
* Hexadecimal file displayer helper class.
* Handles mouse events for the column headings of the displayable table
* window of the GUI.
*
*
* @version $Revision: 1.11 $ $Date: 2005/06/27 03:42:14 $
* @since {@link HexDumpGui} 1.10, 2005-06-07
* @author David R. Tribble
* (david@tribble.com).
*
*
* Copyright ©2005 by David R. Tribble, all rights reserved.
*
* Permission is granted to freely use and distribute this source
* code provided that the original copyright and authorship notices
* remain intact.
*/
static class MyMouseListener
extends java.awt.event.MouseAdapter
implements java.awt.event.MouseListener
{
// Identification
/** Revision information. */
static final String REV =
"@(#)tribble/gui/HexDumpGui.java $Revision: 1.11 $ $Date: 2005/06/27 03:42:14 $\n";
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Private variables
/** Parent hexadecimal file displayer object. */
private HexDumpGui m_mom;
/** Table column header renderers. */
private MyHeaderRenderer[] m_rends;
/** Table display model. */
private MyTableModel m_model;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Constructors
/***********************************************************************
* Constructor.
*
* @param parent
* Parent hexadecimal file displayer object for this table model.
*
* @param rends
* Renderers for the column headings.
*
* @param model
* Table display model.
*
* @since 1.10, 2005-06-07
*/
MyMouseListener(HexDumpGui parent, MyHeaderRenderer[] rends,
MyTableModel model)
{
// Initialize
m_mom = parent;
m_rends = rends;
m_model = model;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Public methods
/***********************************************************************
* Handles a mouse click event for a column heading of the hexadecimal
* file dump table.
*
* @param ev
* A mouse click event.
*
* @since 1.10, 2005-06-07
*/
public void mouseClicked(MouseEvent ev)
//implements java.awt.MouseListener
{
Point loc;
int col;
// Determine the table column heading that was clicked
loc = ev.getPoint();
col = m_mom.m_table.columnAtPoint(loc);
col = m_mom.m_table.convertColumnIndexToModel(col);
///System.out.println("&& mouse.click (" + loc.x + "," + loc.y
///+ ") col:" + col);
// Rotate the column setting
m_rends[col].bump();
m_model.bump(col);
}
}
}
// End HexDumpGui.java