0da1c5dcca
First commit of the 4.5 version (latest version available)
558 lines
25 KiB
Java
558 lines
25 KiB
Java
package mars.venus;
|
|
|
|
import mars.*;
|
|
import mars.util.*;
|
|
import mars.assembler.*;
|
|
import mars.mips.hardware.*;
|
|
import java.io.*;
|
|
import java.util.*;
|
|
import java.awt.*;
|
|
import java.awt.event.*;
|
|
import javax.swing.*;
|
|
import javax.swing.table.*;
|
|
import javax.swing.border.*;
|
|
|
|
/*
|
|
Copyright (c) 2003-2009, Pete Sanderson and Kenneth Vollmar
|
|
|
|
Developed by Pete Sanderson (psanderson@otterbein.edu)
|
|
and Kenneth Vollmar (kenvollmar@missouristate.edu)
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
a copy of this software and associated documentation files (the
|
|
"Software"), to deal in the Software without restriction, including
|
|
without limitation the rights to use, copy, modify, merge, publish,
|
|
distribute, sublicense, and/or sell copies of the Software, and to
|
|
permit persons to whom the Software is furnished to do so, subject
|
|
to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be
|
|
included in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
|
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
(MIT license, http://www.opensource.org/licenses/mit-license.html)
|
|
*/
|
|
|
|
/**
|
|
* Represents the Labels window, which is a type of JInternalFrame. Venus user
|
|
* can view MIPS program labels.
|
|
* @author Sanderson and Team JSpim
|
|
**/
|
|
|
|
public class LabelsWindow extends JInternalFrame{
|
|
private Container contentPane;
|
|
private JPanel labelPanel; // holds J
|
|
private JCheckBox dataLabels, textLabels;
|
|
private ArrayList listOfLabelsForSymbolTable;
|
|
private LabelsWindow labelsWindow;
|
|
private static final int MAX_DISPLAYED_CHARS = 24;
|
|
private static final int PREFERRED_NAME_COLUMN_WIDTH = 60;
|
|
private static final int PREFERRED_ADDRESS_COLUMN_WIDTH = 60;
|
|
private static final int LABEL_COLUMN = 0;
|
|
private static final int ADDRESS_COLUMN = 1;
|
|
private static final String[] columnToolTips = {
|
|
/* LABEL_COLUMN */ "Programmer-defined label (identifier).",
|
|
/* ADDRESS_COLUMN */ "Text or data segment address at which label is defined."
|
|
};
|
|
private static String [] columnNames;
|
|
private Comparator tableSortComparator;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// Use 8-state machine to track sort status for displaying tables
|
|
// State Sort Column Name sort order Address sort order Click Name Click Addr
|
|
// 0 Addr ascend ascend 4 1
|
|
// 1 Addr ascend descend 5 0
|
|
// 2 Addr descend ascend 6 3
|
|
// 3 Addr descend descend 7 2
|
|
// 4 Name ascend ascend 6 0
|
|
// 5 Name ascend descend 7 1
|
|
// 6 Name descend ascend 4 2
|
|
// 7 Name descend descend 5 3
|
|
// "Click Name" column shows which state to go to when Name column is clicked.
|
|
// "Click Addr" column shows which state to go to when Addr column is clicked.
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
// The array of comparators; index corresponds to state in table above.
|
|
private final Comparator[] tableSortingComparators = {
|
|
/* 0 */ new LabelAddressAscendingComparator(),
|
|
/* 1 */ new DescendingComparator(new LabelAddressAscendingComparator()),
|
|
/* 2 */ new LabelAddressAscendingComparator(),
|
|
/* 3 */ new DescendingComparator(new LabelAddressAscendingComparator()),
|
|
/* 4 */ new LabelNameAscendingComparator(),
|
|
/* 5 */ new LabelNameAscendingComparator(),
|
|
/* 6 */ new DescendingComparator(new LabelNameAscendingComparator()),
|
|
/* 7 */ new DescendingComparator(new LabelNameAscendingComparator())
|
|
};
|
|
// The array of state transitions; primary index corresponds to state in table above,
|
|
// secondary index corresponds to table columns (0==label name, 1==address).
|
|
private static final int[][] sortStateTransitions = {
|
|
/* 0 */ { 4, 1 },
|
|
/* 1 */ { 5, 0 },
|
|
/* 2 */ { 6, 3 },
|
|
/* 3 */ { 7, 2 },
|
|
/* 4 */ { 6, 0 },
|
|
/* 5 */ { 7, 1 },
|
|
/* 6 */ { 4, 2 },
|
|
/* 7 */ { 5, 3 }
|
|
};
|
|
// The array of column headings; index corresponds to state in table above.
|
|
private static final char ASCENDING_SYMBOL = '\u25b2'; //triangle with base at bottom ("points" up, to indicate ascending sort)
|
|
private static final char DESCENDING_SYMBOL = '\u25bc';//triangle with base at top ("points" down, to indicate descending sort)
|
|
private static final String[][] sortColumnHeadings = {
|
|
/* 0 */ {"Label", "Address "+ASCENDING_SYMBOL},
|
|
/* 1 */ {"Label", "Address "+DESCENDING_SYMBOL},
|
|
/* 2 */ {"Label", "Address "+ASCENDING_SYMBOL},
|
|
/* 3 */ {"Label", "Address "+DESCENDING_SYMBOL},
|
|
/* 4 */ {"Label "+ASCENDING_SYMBOL, "Address"},
|
|
/* 5 */ {"Label "+ASCENDING_SYMBOL, "Address"},
|
|
/* 6 */ {"Label "+DESCENDING_SYMBOL, "Address"},
|
|
/* 7 */ {"Label "+DESCENDING_SYMBOL, "Address"}
|
|
};
|
|
|
|
// Current sort state (0-7, see table above). Will be set from saved Settings in construtor.
|
|
private int sortState = 0;
|
|
|
|
/**
|
|
* Constructor for the Labels (symbol table) window.
|
|
**/
|
|
|
|
public LabelsWindow (){
|
|
super("Labels", true, false, true, true);
|
|
try {
|
|
sortState = Integer.parseInt(Globals.getSettings().getLabelSortState());
|
|
}
|
|
catch (NumberFormatException nfe) {
|
|
sortState = 0;
|
|
}
|
|
columnNames = sortColumnHeadings[sortState];
|
|
tableSortComparator = tableSortingComparators[sortState];
|
|
labelsWindow = this;
|
|
contentPane = this.getContentPane();
|
|
labelPanel = new JPanel(new GridLayout(1,2,10,0));
|
|
JPanel features = new JPanel();
|
|
dataLabels = new JCheckBox("Data", true);
|
|
textLabels = new JCheckBox("Text", true);
|
|
dataLabels.addItemListener(new LabelItemListener());
|
|
textLabels.addItemListener(new LabelItemListener());
|
|
dataLabels.setToolTipText("If checked, will display labels defined in data segment");
|
|
textLabels.setToolTipText("If checked, will display labels defined in text segment");
|
|
features.add(dataLabels);
|
|
features.add(textLabels);
|
|
contentPane.add(features, BorderLayout.SOUTH);
|
|
contentPane.add(labelPanel);
|
|
}
|
|
|
|
/**
|
|
* Initialize table of labels (symbol table)
|
|
*/
|
|
public void setupTable(){
|
|
labelPanel.removeAll();
|
|
labelPanel.add(generateLabelScrollPane());
|
|
}
|
|
|
|
/**
|
|
* Clear the window
|
|
*/
|
|
public void clearWindow() {
|
|
labelPanel.removeAll();
|
|
}
|
|
|
|
//
|
|
private JScrollPane generateLabelScrollPane() {
|
|
listOfLabelsForSymbolTable = new ArrayList();
|
|
listOfLabelsForSymbolTable.add(new LabelsForSymbolTable(null));// global symtab
|
|
ArrayList MIPSprogramsAssembled = RunAssembleAction.getMIPSprogramsToAssemble();
|
|
Box allSymtabTables = Box.createVerticalBox();
|
|
for (int i=0; i<MIPSprogramsAssembled.size(); i++) {
|
|
listOfLabelsForSymbolTable.add(new LabelsForSymbolTable(
|
|
(MIPSprogram) MIPSprogramsAssembled.get(i)));
|
|
}
|
|
ArrayList tableNames = new ArrayList();
|
|
JTableHeader tableHeader = null;
|
|
for (int i=0; i<listOfLabelsForSymbolTable.size(); i++) {
|
|
LabelsForSymbolTable symtab = (LabelsForSymbolTable)listOfLabelsForSymbolTable.get(i);
|
|
if (symtab.hasSymbols()) {
|
|
String name = symtab.getSymbolTableName();
|
|
if (name.length() > MAX_DISPLAYED_CHARS) {
|
|
name = name.substring(0,MAX_DISPLAYED_CHARS-3)+"...";
|
|
}
|
|
// To get left-justified, put file name into first slot of horizontal Box, then glue.
|
|
JLabel nameLab = new JLabel(name,JLabel.LEFT);
|
|
Box nameLabel = Box.createHorizontalBox();
|
|
nameLabel.add(nameLab);
|
|
nameLabel.add(Box.createHorizontalGlue());
|
|
nameLabel.add(Box.createHorizontalStrut(1));
|
|
tableNames.add(nameLabel);
|
|
allSymtabTables.add(nameLabel);
|
|
JTable table = symtab.generateLabelTable();
|
|
tableHeader = table.getTableHeader();
|
|
// The following is selfish on my part. Column re-ordering doesn't work correctly when
|
|
// displaying multiple symbol tables; the headers re-order but the columns do not.
|
|
// Given the low perceived benefit of reordering displayed symbol table information
|
|
// versus the perceived effort to make reordering work for multiple symbol tables,
|
|
// I am taking the easy way out here. PS 19 July 2007.
|
|
tableHeader.setReorderingAllowed(false);
|
|
table.setSelectionBackground(table.getBackground());
|
|
// Sense click on label/address and scroll Text/Data segment display to it.
|
|
table.addMouseListener(new LabelDisplayMouseListener());
|
|
allSymtabTables.add(table);
|
|
}
|
|
}
|
|
JScrollPane labelScrollPane = new JScrollPane(allSymtabTables,
|
|
ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
|
|
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
|
// Set file name label's max width to scrollpane's viewport width, max height to small.
|
|
// Does it do any good? Addressing problem that occurs when label (filename) is wider than
|
|
// the table beneath it -- the table column widths are stretched to attain the same width and
|
|
// the address information requires scrolling to see. All because of a long file name.
|
|
for (int i=0;i<tableNames.size(); i++) {
|
|
JComponent nameLabel = (JComponent)tableNames.get(i);
|
|
nameLabel.setMaximumSize(new Dimension(
|
|
labelScrollPane.getViewport().getViewSize().width,
|
|
(int) (1.5*nameLabel.getFontMetrics(nameLabel.getFont()).getHeight())));
|
|
}
|
|
labelScrollPane.setColumnHeaderView(tableHeader);
|
|
return labelScrollPane;
|
|
}
|
|
|
|
/**
|
|
* Method to update display of label addresses. Since label information doesn't change,
|
|
* this should only be done when address base is changed.
|
|
* (e.g. between base 16 hex and base 10 dec).
|
|
*/
|
|
public void updateLabelAddresses() {
|
|
if (listOfLabelsForSymbolTable != null) {
|
|
for (int i=0; i<listOfLabelsForSymbolTable.size(); i++) {
|
|
((LabelsForSymbolTable)listOfLabelsForSymbolTable.get(i)).updateLabelAddresses();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Listener class to respond to "Text" or "Data" checkbox click
|
|
private class LabelItemListener implements ItemListener {
|
|
public void itemStateChanged(ItemEvent ie) {
|
|
for (int i=0; i<listOfLabelsForSymbolTable.size(); i++) {
|
|
((LabelsForSymbolTable)listOfLabelsForSymbolTable.get(i)).generateLabelTable();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// Private listener class to sense clicks on a table entry's
|
|
// Label or Address. This will trigger action by Text or Data
|
|
// segment to scroll to the corresponding label/address.
|
|
// Suggested by Ken Vollmar, implemented by Pete Sanderson
|
|
// July 2007.
|
|
|
|
private class LabelDisplayMouseListener extends MouseAdapter {
|
|
public void mouseClicked(MouseEvent e) {
|
|
JTable table = (JTable) e.getSource();
|
|
int row = table.rowAtPoint(e.getPoint());
|
|
int column = table.columnAtPoint(e.getPoint());
|
|
Object data = table.getValueAt(row,column);
|
|
if ( table.getColumnName(column).equals(columnNames[LABEL_COLUMN])) {
|
|
// Selected a Label name, so get its address.
|
|
data = table.getModel().getValueAt(row, ADDRESS_COLUMN);
|
|
}
|
|
int address = 0;
|
|
try {
|
|
address = Binary.stringToInt((String) data);
|
|
}
|
|
catch (NumberFormatException nfe) {
|
|
// Cannot happen because address is generated internally.
|
|
}
|
|
catch (ClassCastException cce) {
|
|
// Cannot happen because table contains only strings.
|
|
}
|
|
// Scroll to this address, either in Text Segment display or Data Segment display
|
|
if (Memory.inTextSegment(address) || Memory.inKernelTextSegment(address)) {
|
|
Globals.getGui().getMainPane().getExecutePane().getTextSegmentWindow().selectStepAtAddress(address);
|
|
}
|
|
else {
|
|
Globals.getGui().getMainPane().getExecutePane().getDataSegmentWindow().selectCellForAddress(address);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
// Represents one symbol table for the display.
|
|
private class LabelsForSymbolTable {
|
|
private MIPSprogram myMIPSprogram;
|
|
private Object[][] labelData;
|
|
private JTable labelTable;
|
|
private ArrayList symbols;
|
|
private SymbolTable symbolTable;
|
|
private String tableName;
|
|
|
|
// Associated MIPSprogram object. If null, this represents global symbol table.
|
|
public LabelsForSymbolTable(MIPSprogram myMIPSprogram) {
|
|
this.myMIPSprogram = myMIPSprogram;
|
|
symbolTable = (myMIPSprogram == null)
|
|
? Globals.symbolTable
|
|
: myMIPSprogram.getLocalSymbolTable();
|
|
tableName = (myMIPSprogram == null)
|
|
? "(global)"
|
|
: new File(myMIPSprogram.getFilename()).getName();
|
|
}
|
|
|
|
// Returns file name of associated file for local symbol table or "(global)"
|
|
public String getSymbolTableName() {
|
|
return tableName;
|
|
}
|
|
|
|
public boolean hasSymbols() {
|
|
return symbolTable.getSize()!=0;
|
|
}
|
|
|
|
|
|
// builds the Table containing labels and addresses for this symbol table.
|
|
private JTable generateLabelTable() {
|
|
SymbolTable symbolTable = (myMIPSprogram == null)
|
|
? Globals.symbolTable
|
|
: myMIPSprogram.getLocalSymbolTable();
|
|
int addressBase = Globals.getGui().getMainPane().getExecutePane().getAddressDisplayBase();
|
|
if (textLabels.isSelected() && dataLabels.isSelected()) {
|
|
symbols = symbolTable.getAllSymbols();
|
|
}
|
|
else if (textLabels.isSelected() && !dataLabels.isSelected()) {
|
|
symbols = symbolTable.getTextSymbols();
|
|
}
|
|
else if (!textLabels.isSelected() && dataLabels.isSelected()) {
|
|
symbols = symbolTable.getDataSymbols();
|
|
}
|
|
else {
|
|
symbols = new ArrayList();
|
|
}
|
|
Collections.sort(symbols, tableSortComparator); // DPS 25 Dec 2008
|
|
labelData = new Object[symbols.size()][2];
|
|
|
|
for(int i=0; i< symbols.size(); i++){//sets up the label table
|
|
Symbol s = (Symbol)(symbols.get(i));
|
|
labelData[i][LABEL_COLUMN] = s.getName();
|
|
labelData[i][ADDRESS_COLUMN] = NumberDisplayBaseChooser.formatNumber(s.getAddress(), addressBase);
|
|
}
|
|
LabelTableModel m = new LabelTableModel(labelData, LabelsWindow.columnNames);
|
|
if (labelTable == null) {
|
|
labelTable = new MyTippedJTable(m);
|
|
}
|
|
else {
|
|
labelTable.setModel(m);
|
|
}
|
|
labelTable.getColumnModel().getColumn(ADDRESS_COLUMN).setCellRenderer(new MonoRightCellRenderer());
|
|
return labelTable;
|
|
}
|
|
|
|
|
|
public void updateLabelAddresses() {
|
|
if (labelPanel.getComponentCount() == 0)
|
|
return; // ignore if no content to change
|
|
int addressBase = Globals.getGui().getMainPane().getExecutePane().getAddressDisplayBase();
|
|
int address;
|
|
String formattedAddress;
|
|
int numSymbols = (labelData==null) ? 0 : labelData.length;
|
|
for(int i=0; i< numSymbols; i++) {
|
|
address = ((Symbol)symbols.get(i)).getAddress();
|
|
formattedAddress = NumberDisplayBaseChooser.formatNumber(address, addressBase);
|
|
labelTable.getModel().setValueAt(formattedAddress, i, ADDRESS_COLUMN);
|
|
}
|
|
}
|
|
}
|
|
////////////////////// end of LabelsForOneSymbolTable class //////////////////
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Class representing label table data
|
|
class LabelTableModel extends AbstractTableModel {
|
|
String[] columns;
|
|
Object[][] data;
|
|
|
|
public LabelTableModel(Object[][] d, String [] n){
|
|
data=d;
|
|
columns= n;
|
|
}
|
|
|
|
public int getColumnCount() {
|
|
return columns.length;
|
|
}
|
|
|
|
public int getRowCount() {
|
|
return data.length;
|
|
}
|
|
|
|
public String getColumnName(int col) {
|
|
return columns[col];
|
|
}
|
|
|
|
public Object getValueAt(int row, int col) {
|
|
return data[row][col];
|
|
}
|
|
|
|
/*
|
|
* JTable uses this method to determine the default renderer/
|
|
* editor for each cell.
|
|
*/
|
|
public Class getColumnClass(int c) {
|
|
return getValueAt(0, c).getClass();
|
|
}
|
|
|
|
/*
|
|
* Don't need to implement this method unless your table's
|
|
* data can change.
|
|
*/
|
|
public void setValueAt(Object value, int row, int col) {
|
|
data[row][col] = value;
|
|
fireTableCellUpdated(row, col);
|
|
}
|
|
|
|
private void printDebugData() {
|
|
int numRows = getRowCount();
|
|
int numCols = getColumnCount();
|
|
|
|
for (int i=0; i < numRows; i++) {
|
|
System.out.print(" row " + i + ":");
|
|
for (int j=0; j < numCols; j++) {
|
|
System.out.print(" " + data[i][j]);
|
|
}
|
|
System.out.println();
|
|
}
|
|
System.out.println("--------------------------");
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// JTable subclass to provide custom tool tips for each of the
|
|
// label table column headers. From Sun's JTable tutorial.
|
|
// http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
|
|
//
|
|
private class MyTippedJTable extends JTable {
|
|
MyTippedJTable(LabelTableModel m) {
|
|
super(m);
|
|
}
|
|
|
|
|
|
|
|
//Implement table header tool tips.
|
|
protected JTableHeader createDefaultTableHeader() {
|
|
return new SymbolTableHeader(columnModel);
|
|
}
|
|
|
|
// Implement cell tool tips. All of them are the same (although they could be customized).
|
|
public Component prepareRenderer(TableCellRenderer renderer, int rowIndex, int vColIndex) {
|
|
Component c = super.prepareRenderer(renderer, rowIndex, vColIndex);
|
|
if (c instanceof JComponent) {
|
|
JComponent jc = (JComponent)c;
|
|
jc.setToolTipText("Click on label or address to view it in Text/Data Segment");
|
|
}
|
|
return c;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
//
|
|
// Customized table header that will both display tool tip when
|
|
// mouse hovers over each column, and also sort the table when
|
|
// mouse is clicked on each column. The tool tip and sort are
|
|
// customized based on the column under the mouse.
|
|
|
|
private class SymbolTableHeader extends JTableHeader {
|
|
|
|
public SymbolTableHeader(TableColumnModel cm) {
|
|
super(cm);
|
|
this.addMouseListener(new SymbolTableHeaderMouseListener());
|
|
}
|
|
|
|
public String getToolTipText(MouseEvent e) {
|
|
Point p = e.getPoint();
|
|
int index = columnModel.getColumnIndexAtX(p.x);
|
|
int realIndex = columnModel.getColumn(index).getModelIndex();
|
|
return columnToolTips[realIndex];
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
// When user clicks on table column header, system will sort the
|
|
// table based on that column then redraw it.
|
|
private class SymbolTableHeaderMouseListener implements MouseListener {
|
|
public void mouseClicked(MouseEvent e) {
|
|
Point p = e.getPoint();
|
|
int index = columnModel.getColumnIndexAtX(p.x);
|
|
int realIndex = columnModel.getColumn(index).getModelIndex();
|
|
sortState = sortStateTransitions[sortState][realIndex];
|
|
tableSortComparator = tableSortingComparators[sortState];
|
|
columnNames = sortColumnHeadings[sortState];
|
|
Globals.getSettings().setLabelSortState(new Integer(sortState).toString());
|
|
setupTable();
|
|
Globals.getGui().getMainPane().getExecutePane().setLabelWindowVisibility(false);
|
|
Globals.getGui().getMainPane().getExecutePane().setLabelWindowVisibility(true);
|
|
}
|
|
public void mouseEntered(MouseEvent e) {}
|
|
public void mouseExited(MouseEvent e) {}
|
|
public void mousePressed(MouseEvent e) {}
|
|
public void mouseReleased(MouseEvent e) {}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Comparator class used to sort in ascending order a List of symbols alphabetically by name
|
|
private class LabelNameAscendingComparator implements java.util.Comparator {
|
|
public int compare(Object a, Object b) {
|
|
return ((Symbol)a).getName().toLowerCase().compareTo(((Symbol)b).getName().toLowerCase());
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Comparator class used to sort in ascending order a List of symbols numerically
|
|
// by address. The kernel address space is all negative integers, so we need some
|
|
// special processing to treat int address as unsigned 32 bit value.
|
|
// Note: Integer.signum() is Java 1.5 and MARS is 1.4 so I can't use it.
|
|
// Remember, if not equal then any value with correct sign will work.
|
|
// If both have same sign, a-b will yield correct result.
|
|
// If signs differ, b will yield correct result (think about it).
|
|
private class LabelAddressAscendingComparator implements java.util.Comparator {
|
|
public int compare(Object a, Object b) {
|
|
int addrA = ((Symbol)a).getAddress();
|
|
int addrB = ((Symbol)b).getAddress();
|
|
return (addrA >= 0 && addrB >= 0 || addrA < 0 && addrB < 0) ? addrA-addrB : addrB ;
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Comparator class used to sort in descending order a List of symbols. It will
|
|
// sort either alphabetically by name or numerically by address, depending on the
|
|
// Comparator object provided as the argument constructor. This works because it
|
|
// is implemented by returning the result of the Ascending comparator when
|
|
// arguments are reversed.
|
|
private class DescendingComparator implements java.util.Comparator {
|
|
private Comparator opposite;
|
|
private DescendingComparator(Comparator opposite) {
|
|
this.opposite = opposite;
|
|
}
|
|
public int compare(Object a, Object b) {
|
|
return opposite.compare(b,a);
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|