Merge remote-tracking branch 'origin/patch'

Conflicts:
	Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/DebuggerRegistersProvider.java
This commit is contained in:
Ryan Kurtz 2023-11-02 12:18:46 -04:00
commit 0e48d6e055
8 changed files with 225 additions and 140 deletions

View File

@ -51,7 +51,7 @@ import ghidra.base.widgets.table.DataTypeTableCellEditor;
import ghidra.dbg.error.DebuggerModelAccessException; import ghidra.dbg.error.DebuggerModelAccessException;
import ghidra.debug.api.target.Target; import ghidra.debug.api.target.Target;
import ghidra.debug.api.tracemgr.DebuggerCoordinates; import ghidra.debug.api.tracemgr.DebuggerCoordinates;
import ghidra.docking.settings.Settings; import ghidra.docking.settings.*;
import ghidra.framework.model.DomainObject; import ghidra.framework.model.DomainObject;
import ghidra.framework.model.DomainObjectChangeRecord; import ghidra.framework.model.DomainObjectChangeRecord;
import ghidra.framework.options.AutoOptions; import ghidra.framework.options.AutoOptions;
@ -80,6 +80,7 @@ import ghidra.util.data.DataTypeParser.AllowedDataTypes;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.table.GhidraTable; import ghidra.util.table.GhidraTable;
import ghidra.util.table.GhidraTableFilterPanel; import ghidra.util.table.GhidraTableFilterPanel;
import ghidra.util.table.column.GColumnRenderer;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
public class DebuggerRegistersProvider extends ComponentProviderAdapter public class DebuggerRegistersProvider extends ComponentProviderAdapter
@ -143,33 +144,53 @@ public class DebuggerRegistersProvider extends ComponentProviderAdapter
protected enum RegisterTableColumns protected enum RegisterTableColumns
implements EnumeratedTableColumn<RegisterTableColumns, RegisterRow> { implements EnumeratedTableColumn<RegisterTableColumns, RegisterRow> {
FAV("Fav", Boolean.class, RegisterRow::isFavorite, RegisterRow::setFavorite, // FAV("Fav", 1, Boolean.class, RegisterRow::isFavorite, RegisterRow::setFavorite, //
r -> true, SortDirection.DESCENDING), r -> true, SortDirection.DESCENDING),
NUMBER("#", Integer.class, RegisterRow::getNumber), NUMBER("#", 1, Integer.class, RegisterRow::getNumber),
NAME("Name", String.class, RegisterRow::getName), NAME("Name", 40, String.class, RegisterRow::getName),
VALUE("Value", BigInteger.class, RegisterRow::getValue, RegisterRow::setValue, // VALUE("Value", 100, BigInteger.class, RegisterRow::getValue, RegisterRow::setValue, //
RegisterRow::isValueEditable, SortDirection.ASCENDING), RegisterRow::isValueEditable, SortDirection.ASCENDING) {
TYPE("Type", DataType.class, RegisterRow::getDataType, RegisterRow::setDataType, // private static final RegisterValueCellRenderer RENDERER =
new RegisterValueCellRenderer();
private static final SettingsDefinition[] DEFS = new SettingsDefinition[] {
FormatSettingsDefinition.DEF_HEX,
};
@Override
public GColumnRenderer<BigInteger> getRenderer() {
return RENDERER;
}
@Override
public SettingsDefinition[] getSettingsDefinitions() {
return DEFS;
}
},
TYPE("Type", 40, DataType.class, RegisterRow::getDataType, RegisterRow::setDataType, //
r -> true, SortDirection.ASCENDING), r -> true, SortDirection.ASCENDING),
REPR("Repr", String.class, RegisterRow::getRepresentation, RegisterRow::setRepresentation, // REPR("Repr", 100, String.class, RegisterRow::getRepresentation, RegisterRow::setRepresentation, //
RegisterRow::isRepresentationEditable, SortDirection.ASCENDING); RegisterRow::isRepresentationEditable, SortDirection.ASCENDING);
private final String header; private final String header;
private final int width;
private final Function<RegisterRow, ?> getter; private final Function<RegisterRow, ?> getter;
private final BiConsumer<RegisterRow, Object> setter; private final BiConsumer<RegisterRow, Object> setter;
private final Predicate<RegisterRow> editable; private final Predicate<RegisterRow> editable;
private final Class<?> cls; private final Class<?> cls;
private final SortDirection direction; private final SortDirection direction;
<T> RegisterTableColumns(String header, Class<T> cls, Function<RegisterRow, T> getter) { <T> RegisterTableColumns(String header, int width, Class<T> cls,
this(header, cls, getter, null, null, SortDirection.ASCENDING); Function<RegisterRow, T> getter) {
this(header, width, cls, getter, null, null, SortDirection.ASCENDING);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
<T> RegisterTableColumns(String header, Class<T> cls, Function<RegisterRow, T> getter, <T> RegisterTableColumns(String header, int width, Class<T> cls,
Function<RegisterRow, T> getter,
BiConsumer<RegisterRow, T> setter, Predicate<RegisterRow> editable, BiConsumer<RegisterRow, T> setter, Predicate<RegisterRow> editable,
SortDirection direction) { SortDirection direction) {
this.header = header; this.header = header;
this.width = width;
this.cls = cls; this.cls = cls;
this.getter = getter; this.getter = getter;
this.setter = (BiConsumer<RegisterRow, Object>) setter; this.setter = (BiConsumer<RegisterRow, Object>) setter;
@ -206,6 +227,11 @@ public class DebuggerRegistersProvider extends ComponentProviderAdapter
public SortDirection defaultSortDirection() { public SortDirection defaultSortDirection() {
return direction; return direction;
} }
@Override
public int getPreferredWidth() {
return width;
}
} }
protected static class RegistersTableModel protected static class RegistersTableModel
@ -387,7 +413,7 @@ public class DebuggerRegistersProvider extends ComponentProviderAdapter
} }
} }
class RegisterValueCellRenderer extends HexBigIntegerTableCellRenderer { static class RegisterValueCellRenderer extends HexDefaultGColumnRenderer<BigInteger> {
@Override @Override
public final Component getTableCellRendererComponent(GTableCellRenderingData data) { public final Component getTableCellRendererComponent(GTableCellRenderingData data) {
super.getTableCellRendererComponent(data); super.getTableCellRendererComponent(data);
@ -574,21 +600,10 @@ public class DebuggerRegistersProvider extends ComponentProviderAdapter
}); });
TableColumnModel columnModel = regsTable.getColumnModel(); TableColumnModel columnModel = regsTable.getColumnModel();
TableColumn favCol = columnModel.getColumn(RegisterTableColumns.FAV.ordinal());
favCol.setPreferredWidth(1);
TableColumn numCol = columnModel.getColumn(RegisterTableColumns.NUMBER.ordinal());
numCol.setPreferredWidth(1);
TableColumn nameCol = columnModel.getColumn(RegisterTableColumns.NAME.ordinal());
nameCol.setPreferredWidth(40);
TableColumn valCol = columnModel.getColumn(RegisterTableColumns.VALUE.ordinal()); TableColumn valCol = columnModel.getColumn(RegisterTableColumns.VALUE.ordinal());
valCol.setCellRenderer(new RegisterValueCellRenderer());
valCol.setCellEditor(new HexBigIntegerTableCellEditor()); valCol.setCellEditor(new HexBigIntegerTableCellEditor());
valCol.setPreferredWidth(100);
TableColumn typeCol = columnModel.getColumn(RegisterTableColumns.TYPE.ordinal()); TableColumn typeCol = columnModel.getColumn(RegisterTableColumns.TYPE.ordinal());
typeCol.setCellEditor(new RegisterDataTypeEditor()); typeCol.setCellEditor(new RegisterDataTypeEditor());
typeCol.setPreferredWidth(50);
TableColumn reprCol = columnModel.getColumn(RegisterTableColumns.REPR.ordinal());
reprCol.setPreferredWidth(100);
} }
@Override @Override

View File

@ -21,8 +21,10 @@ import java.util.function.Predicate;
import docking.widgets.table.ColumnSortState.SortDirection; import docking.widgets.table.ColumnSortState.SortDirection;
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn; import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
import ghidra.docking.settings.Settings; import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsDefinition;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.ServiceProvider; import ghidra.framework.plugintool.ServiceProvider;
import ghidra.util.table.column.GColumnRenderer;
/** /**
* A table model whose columns are described using an {@link Enum}. * A table model whose columns are described using an {@link Enum}.
@ -106,6 +108,26 @@ public class DefaultEnumeratedColumnTableModel<C extends Enum<C> & EnumeratedTab
default public SortDirection defaultSortDirection() { default public SortDirection defaultSortDirection() {
return SortDirection.ASCENDING; return SortDirection.ASCENDING;
} }
default public int getPreferredWidth() {
return -1;
}
/**
* Because of limitations with Java generics and Enumerations, type checking cannot be
* guaranteed here. The user must ensure that any returned by {@link #getValueOf(Object)}
* can be accepted by the renderer returned here. The framework will perform an unchecked
* cast of the renderer.
*
* @return the renderer
*/
default public GColumnRenderer<?> getRenderer() {
return null;
}
default public SettingsDefinition[] getSettingsDefinitions() {
return null;
}
} }
private final List<R> modelData = new ArrayList<>(); private final List<R> modelData = new ArrayList<>();
@ -167,6 +189,26 @@ public class DefaultEnumeratedColumnTableModel<C extends Enum<C> & EnumeratedTab
ServiceProvider serviceProvider) { ServiceProvider serviceProvider) {
col.setValueOf(row, value); col.setValueOf(row, value);
} }
@Override
@SuppressWarnings("unchecked")
public GColumnRenderer<Object> getColumnRenderer() {
return (GColumnRenderer<Object>) col.getRenderer();
}
@Override
public int getColumnPreferredWidth() {
return col.getPreferredWidth();
}
@Override
public SettingsDefinition[] getSettingsDefinitions() {
SettingsDefinition[] defs = col.getSettingsDefinitions();
if (defs != null) {
return defs;
}
return super.getSettingsDefinitions();
}
} }
@Override @Override

View File

@ -52,6 +52,7 @@ public class HexBigIntegerTableCellEditor extends AbstractCellEditor implements
input.setHexMode(); input.setHexMode();
input.setAllowsHexPrefix(false); input.setAllowsHexPrefix(false);
input.setShowNumberMode(true); input.setShowNumberMode(true);
input.setHorizontalAlignment(JTextField.RIGHT);
if (value != null) { if (value != null) {
input.setValue((BigInteger) value); input.setValue((BigInteger) value);

View File

@ -1,49 +0,0 @@
/* ###
* IP: GHIDRA
*
* 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 docking.widgets.table;
import java.awt.Component;
import java.math.BigInteger;
import javax.swing.JTable;
import javax.swing.table.TableModel;
import ghidra.docking.settings.Settings;
import ghidra.util.table.column.AbstractGColumnRenderer;
public class HexBigIntegerTableCellRenderer extends AbstractGColumnRenderer<BigInteger> {
@Override
protected void configureFont(JTable table, TableModel model, int column) {
setFont(fixedWidthFont);
}
protected String formatBigInteger(BigInteger value) {
return value == null ? "??" : value.toString(16);
}
@Override
public Component getTableCellRendererComponent(GTableCellRenderingData data) {
super.getTableCellRendererComponent(data);
setText(formatBigInteger((BigInteger) data.getValue()));
return this;
}
// TODO: Seems the filter model does not heed this....
@Override
public String getFilterString(BigInteger t, Settings settings) {
return formatBigInteger(t);
}
}

View File

@ -0,0 +1,35 @@
/* ###
* IP: GHIDRA
*
* 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 docking.widgets.table;
import ghidra.docking.settings.FormatSettingsDefinition;
import ghidra.docking.settings.Settings;
import ghidra.util.table.column.AbstractGColumnRenderer;
public class HexDefaultGColumnRenderer<T extends Number> extends AbstractGColumnRenderer<T> {
private final static FormatSettingsDefinition INTEGER_RADIX_SETTING =
FormatSettingsDefinition.DEF_HEX;
@Override
protected int getRadix(Settings settings) {
return INTEGER_RADIX_SETTING.getRadix(settings);
}
@Override
public String getFilterString(Number t, Settings settings) {
return formatNumber(t, settings);
}
}

View File

@ -50,10 +50,10 @@ public abstract class AbstractDynamicTableColumn<ROW_TYPE, COLUMN_TYPE, DATA_SOU
protected static final FloatingPointPrecisionSettingsDefinition FLOATING_POINT_PRECISION_SETTING = protected static final FloatingPointPrecisionSettingsDefinition FLOATING_POINT_PRECISION_SETTING =
FloatingPointPrecisionSettingsDefinition.DEF; FloatingPointPrecisionSettingsDefinition.DEF;
protected static SettingsDefinition[] INTEGER_SETTINGS_DEFINITIONS = protected static final SettingsDefinition[] INTEGER_SETTINGS_DEFINITIONS =
new SettingsDefinition[] { INTEGER_RADIX_SETTING, INTEGER_SIGNEDNESS_MODE_SETTING }; new SettingsDefinition[] { INTEGER_RADIX_SETTING, INTEGER_SIGNEDNESS_MODE_SETTING };
protected static SettingsDefinition[] FLOATING_POINT_SETTINGS_DEFINITIONS = protected static final SettingsDefinition[] FLOATING_POINT_SETTINGS_DEFINITIONS =
new SettingsDefinition[] { FLOATING_POINT_PRECISION_SETTING }; new SettingsDefinition[] { FLOATING_POINT_PRECISION_SETTING };
private boolean hasConfiguredDefaultSettings = false; private boolean hasConfiguredDefaultSettings = false;

View File

@ -34,8 +34,8 @@ import ghidra.util.*;
import ghidra.util.exception.AssertException; import ghidra.util.exception.AssertException;
/** /**
* A default table cell renderer that relies on the <code>toString()</code> method * A default table cell renderer that relies on the <code>toString()</code> method when rendering
* when rendering the cells of the table. * the cells of the table.
*/ */
public class GTableCellRenderer extends AbstractGCellRenderer implements TableCellRenderer { public class GTableCellRenderer extends AbstractGCellRenderer implements TableCellRenderer {
@ -84,6 +84,7 @@ public class GTableCellRenderer extends AbstractGCellRenderer implements TableCe
/** /**
* Constructs a new GTableCellRenderer using the specified font. * Constructs a new GTableCellRenderer using the specified font.
*
* @param f the font to use when rendering text in the table cells * @param f the font to use when rendering text in the table cells
*/ */
public GTableCellRenderer(Font f) { public GTableCellRenderer(Font f) {
@ -93,6 +94,7 @@ public class GTableCellRenderer extends AbstractGCellRenderer implements TableCe
/** /**
* Return the cell renderer text * Return the cell renderer text
*
* @param value Cell object value * @param value Cell object value
* @return A string interpretation of value; generated by calling value.toString() * @return A string interpretation of value; generated by calling value.toString()
*/ */
@ -101,8 +103,8 @@ public class GTableCellRenderer extends AbstractGCellRenderer implements TableCe
} }
/** /**
* Satisfies the Java {@link javax.swing.table.TableCellRenderer} interface; retrieves * Satisfies the Java {@link javax.swing.table.TableCellRenderer} interface; retrieves column
* column data via a GTableCellRenderingData object, and defers painting to * data via a GTableCellRenderingData object, and defers painting to
* {@link #getTableCellRendererComponent(GTableCellRenderingData)}. * {@link #getTableCellRendererComponent(GTableCellRenderingData)}.
* <p> * <p>
* This is marked <code>final</code> to redirect subclasses to the enhanced method, * This is marked <code>final</code> to redirect subclasses to the enhanced method,
@ -111,7 +113,8 @@ public class GTableCellRenderer extends AbstractGCellRenderer implements TableCe
* Throws an AssertException if the table this renderer is used with is not a * Throws an AssertException if the table this renderer is used with is not a
* {@link docking.widgets.table.GTable} instance. * {@link docking.widgets.table.GTable} instance.
* *
* @see javax.swing.table.TableCellRenderer#getTableCellRendererComponent(javax.swing.JTable, java.lang.Object, boolean, boolean, int, int) * @see javax.swing.table.TableCellRenderer#getTableCellRendererComponent(javax.swing.JTable,
* java.lang.Object, boolean, boolean, int, int)
* @see #getTableCellRendererComponent(GTableCellRenderingData) * @see #getTableCellRendererComponent(GTableCellRenderingData)
*/ */
@Override @Override
@ -144,8 +147,9 @@ public class GTableCellRenderer extends AbstractGCellRenderer implements TableCe
/** /**
* Provide basic cell rendering -- setting foreground and background colors, font, text, * Provide basic cell rendering -- setting foreground and background colors, font, text,
* alignment, drop color, and border. Additional data that may be of use to the renderer * alignment, drop color, and border. Additional data that may be of use to the renderer is
* is passed through the {@link docking.widgets.table.GTableCellRenderingData} object. * passed through the {@link docking.widgets.table.GTableCellRenderingData} object.
*
* @param data Context data used in the rendering of a data cell. * @param data Context data used in the rendering of a data cell.
* @return The component used for drawing the table cell. * @return The component used for drawing the table cell.
*/ */
@ -199,8 +203,21 @@ public class GTableCellRenderer extends AbstractGCellRenderer implements TableCe
setFont(defaultFont); setFont(defaultFont);
} }
protected int getRadix(Settings settings) {
return INTEGER_RADIX_SETTING.getRadix(settings);
}
protected SignednessFormatMode getSignMode(Settings settings) {
return INTEGER_SIGNEDNESS_MODE_SETTING.getFormatMode(settings);
}
protected int getPrecision(Settings settings) {
return FLOATING_POINT_PRECISION_SETTING.getPrecision(settings);
}
/** /**
* Format a Number per the Settings parameters. * Format a Number per the Settings parameters.
*
* @param value the number to format * @param value the number to format
* @param settings settings controlling the display of the Number parameter * @param settings settings controlling the display of the Number parameter
* @return a formatted representation of the Number value * @return a formatted representation of the Number value
@ -208,8 +225,8 @@ public class GTableCellRenderer extends AbstractGCellRenderer implements TableCe
protected String formatNumber(Number value, Settings settings) { protected String formatNumber(Number value, Settings settings) {
if (NumericUtilities.isIntegerType(value)) { if (NumericUtilities.isIntegerType(value)) {
int radix = INTEGER_RADIX_SETTING.getRadix(settings); int radix = getRadix(settings);
SignednessFormatMode signMode = INTEGER_SIGNEDNESS_MODE_SETTING.getFormatMode(settings); SignednessFormatMode signMode = getSignMode(settings);
long number = value.longValue(); long number = value.longValue();
return NumericUtilities.formatNumber(number, radix, signMode); return NumericUtilities.formatNumber(number, radix, signMode);
} }
@ -219,18 +236,18 @@ public class GTableCellRenderer extends AbstractGCellRenderer implements TableCe
if (number.isNaN() || number.isInfinite()) { if (number.isNaN() || number.isInfinite()) {
return Character.toString('\u221e'); // infinity symbol return Character.toString('\u221e'); // infinity symbol
} }
int precision = FLOATING_POINT_PRECISION_SETTING.getPrecision(settings); int precision = getPrecision(settings);
return getFormatter(precision).format(number); return getFormatter(precision).format(number);
} }
if (value instanceof BigInteger) { if (value instanceof BigInteger) {
int radix = INTEGER_RADIX_SETTING.getRadix(settings); int radix = getRadix(settings);
return ((BigInteger) value).toString(radix); return ((BigInteger) value).toString(radix);
} }
if (value instanceof BigDecimal) { if (value instanceof BigDecimal) {
int precision = FLOATING_POINT_PRECISION_SETTING.getPrecision(settings); int precision = getPrecision(settings);
DecimalFormat formatter = getFormatter(precision); DecimalFormat formatter = getFormatter(precision);
formatter.format(value); formatter.format(value);

View File

@ -34,26 +34,28 @@ import ghidra.util.SystemUtilities;
/** /**
* TextField for entering integer numbers, either in decimal or hex. * TextField for entering integer numbers, either in decimal or hex.
* *
* <P> This field does continuous checking, so * <P>
* you can't enter a bad value. * This field does continuous checking, so you can't enter a bad value.
* *
* <P> Internally, values are maintained using BigIntegers so this field can * <P>
* contain numbers as large as desired. There are convenience methods for getting the value as * Internally, values are maintained using BigIntegers so this field can contain numbers as large as
* either an int or long. If using these convenience methods, you should also set the max allowed * desired. There are convenience methods for getting the value as either an int or long. If using
* value so that users can't enter a value larger than can be represented by the {@link #getIntValue()} * these convenience methods, you should also set the max allowed value so that users can't enter a
* or {@link #getLongValue()} methods as appropriate. * value larger than can be represented by the {@link #getIntValue()} or {@link #getLongValue()}
* methods as appropriate.
* *
* <P> There are several configuration options as follows: * <P>
* There are several configuration options as follows:
* <UL> * <UL>
* <LI> Allows negative numbers - either support all integer numbers or just non-negative * <LI>Allows negative numbers - either support all integer numbers or just non-negative numbers.
* numbers. See {@link #setAllowNegativeValues(boolean)} </LI> * See {@link #setAllowNegativeValues(boolean)}</LI>
* <LI>Allows hex prefix - If this mode is on, then hex mode is turned on and off automatically * <LI>Allows hex prefix - If this mode is on, then hex mode is turned on and off automatically
* depending whether or not the text starts with 0x. Otherwise, the hex/decimal mode is set externally * depending whether or not the text starts with 0x. Otherwise, the hex/decimal mode is set
* (either programmatically or pressing &lt;CTRL&gt; M) and the user is restricted to the numbers/letters * externally (either programmatically or pressing &lt;CTRL&gt; M) and the user is restricted to the
* appropriate for that mode. See {@link #setAllowsHexPrefix(boolean)}</LI> * numbers/letters appropriate for that mode. See {@link #setAllowsHexPrefix(boolean)}</LI>
* <LI> Have a max value - a max value can be set (must be positive) such that the user can not type a * <LI>Have a max value - a max value can be set (must be positive) such that the user can not type
* number whose absolute value is greater than the max. Otherwise, the value is unlimited if max is * a number whose absolute value is greater than the max. Otherwise, the value is unlimited if max
* null/unspecified. See {@link #setMaxValue(BigInteger)}</LI> * is null/unspecified. See {@link #setMaxValue(BigInteger)}</LI>
* <LI>Show the number mode as hint text - If on either "Hex" or "Dec" is displayed lightly in the * <LI>Show the number mode as hint text - If on either "Hex" or "Dec" is displayed lightly in the
* bottom right portion of the text field. See {@link #setShowNumberMode(boolean)}</LI> * bottom right portion of the text field. See {@link #setShowNumberMode(boolean)}</LI>
* </UL> * </UL>
@ -93,8 +95,8 @@ public class IntegerTextField {
* *
* @param columns the number of columns to display in the JTextField. * @param columns the number of columns to display in the JTextField.
* @param initialValue the initial value. This constructor takes an initialValue as a long. If * @param initialValue the initial value. This constructor takes an initialValue as a long. If
* you need a value that is bigger (or smaller) than can be specified as a long, then use * you need a value that is bigger (or smaller) than can be specified as a long, then
* the constructor that takes a BigInteger as an initial value. * use the constructor that takes a BigInteger as an initial value.
*/ */
public IntegerTextField(int columns, long initialValue) { public IntegerTextField(int columns, long initialValue) {
this(columns, BigInteger.valueOf(initialValue)); this(columns, BigInteger.valueOf(initialValue));
@ -159,11 +161,13 @@ public class IntegerTextField {
/** /**
* Returns the current value as an int. * Returns the current value as an int.
* *
* <P> If the field has no current value, 0 will be returned. If * <P>
* the value is bigger (or smaller) than an int, it will be cast to an int. * If the field has no current value, 0 will be returned. If the value is bigger (or smaller)
* than an int, it will be cast to an int.
* *
* <P> If using this method, it is highly recommended that you set the max value to {@link Integer#MAX_VALUE} * <P>
* or lower. * If using this method, it is highly recommended that you set the max value to
* {@link Integer#MAX_VALUE} or lower.
* *
* @return the current value as an int. Or 0 if there is no value * @return the current value as an int. Or 0 if there is no value
* @throws ArithmeticException if the value in this field will not fit into an int * @throws ArithmeticException if the value in this field will not fit into an int
@ -179,11 +183,13 @@ public class IntegerTextField {
/** /**
* Returns the current value as a long. * Returns the current value as a long.
* *
* <P> If the field has no current value, 0 will be returned. If * <P>
* the value is bigger (or smaller) than an long, it will be cast to a long. * If the field has no current value, 0 will be returned. If the value is bigger (or smaller)
* than an long, it will be cast to a long.
* *
* <P> If using this method, it is highly recommended that you set the max value to {@link Long#MAX_VALUE} * <P>
* or lower. * If using this method, it is highly recommended that you set the max value to
* {@link Long#MAX_VALUE} or lower.
* *
* @return the current value as a long. Or 0 if there is no value * @return the current value as a long. Or 0 if there is no value
* @throws ArithmeticException if the value in this field will not fit into a long * @throws ArithmeticException if the value in this field will not fit into a long
@ -215,13 +221,13 @@ public class IntegerTextField {
} }
/** /**
* Sets the field to the given text. The text must be a properly formated string that is * Sets the field to the given text. The text must be a properly formated string that is a value
* a value that is valid for this field. If the field is set to not allow "0x" prefixes, then * that is valid for this field. If the field is set to not allow "0x" prefixes, then the input
* the input string cannot start with 0x and furthermore, if the field is in decimal mode, then * string cannot start with 0x and furthermore, if the field is in decimal mode, then input
* input string cannot take in hex digits a-f. On the other hand, if "0x" prefixes are allowed, * string cannot take in hex digits a-f. On the other hand, if "0x" prefixes are allowed, then
* then the input string can be either a decimal number or a hex number depending on if the * the input string can be either a decimal number or a hex number depending on if the input
* input string starts with "0x". In this case, the field's hex mode will be set to match * string starts with "0x". In this case, the field's hex mode will be set to match the input
* the input text. If the text is not valid, the field will not change. * text. If the text is not valid, the field will not change.
* *
* @param text the value as text to set on this field * @param text the value as text to set on this field
* @return true if the set was successful * @return true if the set was successful
@ -259,8 +265,9 @@ public class IntegerTextField {
/** /**
* Sets the radix mode to Hex. * Sets the radix mode to Hex.
* *
* <P> If the field is currently in decimal mode, the current text will be * <P>
* change from displaying the current value from decimal to hex. * If the field is currently in decimal mode, the current text will be change from displaying
* the current value from decimal to hex.
*/ */
public void setHexMode() { public void setHexMode() {
BigInteger currentValue = getValue(); BigInteger currentValue = getValue();
@ -271,8 +278,9 @@ public class IntegerTextField {
/** /**
* Sets the mode to Decimal. * Sets the mode to Decimal.
* *
* <P> If the field is currently in hex mode, the current text will be * <P>
* change from displaying the current value from hex to decimal. * If the field is currently in hex mode, the current text will be change from displaying the
* current value from hex to decimal.
*/ */
public void setDecimalMode() { public void setDecimalMode() {
BigInteger currentValue = getValue(); BigInteger currentValue = getValue();
@ -283,12 +291,12 @@ public class IntegerTextField {
/** /**
* Sets whether on not the field supports the 0x prefix. * Sets whether on not the field supports the 0x prefix.
* *
* <P> If 0x is supported, hex numbers * <P>
* will be displayed with the 0x prefix. Also, when typing, you must type 0x first to enter * If 0x is supported, hex numbers will be displayed with the 0x prefix. Also, when typing, you
* a hex number, otherwise it will only allow digits 0-9. If the 0x prefix option is turned * must type 0x first to enter a hex number, otherwise it will only allow digits 0-9. If the 0x
* off, then hex numbers are displayed without the 0x prefix and you can't change the decimal/hex * prefix option is turned off, then hex numbers are displayed without the 0x prefix and you
* mode by typing 0x. The field will either be in decimal or hex mode and the typed text * can't change the decimal/hex mode by typing 0x. The field will either be in decimal or hex
* will be interpreted appropriately for the mode. * mode and the typed text will be interpreted appropriately for the mode.
* *
* @param allowsHexPrefix true to use the 0x convention for hex. * @param allowsHexPrefix true to use the 0x convention for hex.
*/ */
@ -333,9 +341,10 @@ public class IntegerTextField {
} }
/** /**
* Returns the current maximum allowed value. Null indicates that there is no maximum value. * Returns the current maximum allowed value. Null indicates that there is no maximum value. If
* If negative values are permitted (see {@link #setAllowNegativeValues(boolean)}) this value * negative values are permitted (see {@link #setAllowNegativeValues(boolean)}) this value will
* will establish the upper and lower limit of the absolute value. * establish the upper and lower limit of the absolute value.
*
* @return the current maximum value allowed. * @return the current maximum value allowed.
*/ */
public BigInteger getMaxValue() { public BigInteger getMaxValue() {
@ -451,6 +460,15 @@ public class IntegerTextField {
textField.selectAll(); textField.selectAll();
} }
/**
* Sets the horizontal alignment of the JTextField
*
* @param alignment the alignment as in {@link JTextField#setHorizontalAlignment(int)}
*/
public void setHorizontalAlignment(int alignment) {
textField.setHorizontalAlignment(alignment);
}
private String computeTextForValue(BigInteger value) { private String computeTextForValue(BigInteger value) {
if (value == null) { if (value == null) {
return ""; return "";
@ -724,7 +742,13 @@ public class IntegerTextField {
Dimension size = getSize(); Dimension size = getSize();
Insets insets = getInsets(); Insets insets = getInsets();
int x = size.width - insets.right - hintWidth; int x;
if (getHorizontalAlignment() == RIGHT) {
x = insets.left;
}
else {
x = size.width - insets.right - hintWidth;
}
int y = size.height - insets.bottom - 1; int y = size.height - insets.bottom - 1;
String mode = isHexMode ? "Hex" : "Dec"; String mode = isHexMode ? "Hex" : "Dec";
GraphicsUtils.drawString(this, g, mode, x, y); GraphicsUtils.drawString(this, g, mode, x, y);