mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-08-17 20:49:08 +08:00
Merge remote-tracking branch 'origin/GP-5253-dragonmacher-structure-editor-jump-to-offset--SQUASHED'
This commit is contained in:
+1
-1
@@ -51,7 +51,7 @@ public class HexBigIntegerTableCellEditor extends AbstractCellEditor implements
|
||||
input.getComponent().setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
|
||||
input.setMinValue(null); // allow negative numbers
|
||||
input.setFormat(IntegerFormat.HEX);
|
||||
input.setUseNumberPrefix(false);
|
||||
input.setAutoSwitchMode(false);
|
||||
input.setShowNumberMode(true);
|
||||
input.setHorizontalAlignment(SwingConstants.RIGHT);
|
||||
|
||||
|
||||
+23
-13
@@ -17,16 +17,18 @@ package ghidra.features.bsim.gui.search.dialog;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import docking.DialogComponentProvider;
|
||||
import docking.DockingWindowManager;
|
||||
import docking.widgets.EmptyBorderButton;
|
||||
import docking.widgets.textfield.IntegerTextField;
|
||||
import docking.widgets.numberformat.IntegerFormatter;
|
||||
import docking.widgets.numberformat.IntegerFormatterFactory;
|
||||
import docking.widgets.textfield.GFormattedTextField;
|
||||
import generic.theme.GIcon;
|
||||
import ghidra.app.services.GoToService;
|
||||
import ghidra.features.bsim.gui.BSimSearchPlugin;
|
||||
@@ -49,7 +51,7 @@ public class BSimSearchDialog extends AbstractBSimSearchDialog {
|
||||
private BSimFilterPanel filterPanel;
|
||||
|
||||
// Query Settings
|
||||
private IntegerTextField maxResultsField;
|
||||
private GFormattedTextField maxResultsField;
|
||||
|
||||
public BSimSearchDialog(PluginTool tool, BSimSearchService service,
|
||||
BSimServerManager serverManager, Set<FunctionSymbol> functions) {
|
||||
@@ -124,26 +126,34 @@ public class BSimSearchDialog extends AbstractBSimSearchDialog {
|
||||
protected JPanel buildOptionsPanel() {
|
||||
JPanel panel = super.buildOptionsPanel();
|
||||
|
||||
maxResultsField = new IntegerTextField(10);
|
||||
maxResultsField.setValue(100);
|
||||
maxResultsField.setMinValue(BigInteger.ONE);
|
||||
maxResultsField.setUseNumberPrefix(false);
|
||||
maxResultsField.setShowNumberMode(false);
|
||||
|
||||
JComponent maxResultsComponent = maxResultsField.getComponent();
|
||||
IntegerFormatter formatter = new OneOrMoreIntegerFormatter();
|
||||
IntegerFormatterFactory factory = new IntegerFormatterFactory(formatter, false);
|
||||
maxResultsField = new GFormattedTextField(factory, 100);
|
||||
|
||||
JLabel maxLabel = new JLabel("Max Matches Per Function:");
|
||||
maxLabel.setLabelFor(maxResultsComponent);
|
||||
maxLabel.setLabelFor(maxResultsField);
|
||||
|
||||
panel.add(maxLabel);
|
||||
panel.add(maxResultsComponent);
|
||||
panel.add(maxResultsField);
|
||||
return panel;
|
||||
}
|
||||
|
||||
private class OneOrMoreIntegerFormatter extends IntegerFormatter {
|
||||
|
||||
@Override
|
||||
protected Predicate<Number> createIsValidNumberPredicate() {
|
||||
return n -> {
|
||||
int i = n.intValue();
|
||||
return i > 0;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected BSimSearchSettings getSearchSettings() {
|
||||
double similarity = similarityField.getValue();
|
||||
double confidence = confidenceField.getValue();
|
||||
int maxResults = maxResultsField.getIntValue();
|
||||
int maxResults = (Integer) maxResultsField.getValue();
|
||||
BSimFilterSet set = filterPanel.getFilterSet();
|
||||
return new BSimSearchSettings(similarity, confidence, maxResults, set);
|
||||
}
|
||||
|
||||
@@ -1215,6 +1215,16 @@
|
||||
start the search from there.
|
||||
</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
|
||||
<H2><A name="Structure_Editor_Go_To_Offset"></A> Go To Offset</H2>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>
|
||||
<B>Go to Offset</B> is available from the popup menu. It allows you to jump to the row with
|
||||
the given offset.
|
||||
</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
|
||||
<H2><A name="Structure_Editor_Show_Component_Path"></A> Showing a Component's Data Type
|
||||
|
||||
+1
-9
@@ -141,7 +141,7 @@ abstract public class CompositeEditorModel<T extends Composite> extends Composit
|
||||
}
|
||||
|
||||
if (dataType.isDeleted()) {
|
||||
// This can occur when mayny events get lumped together and a change event triggers
|
||||
// This can occur when many events get lumped together and a change event triggers
|
||||
// a delayed reload prior to datatype removal and its event
|
||||
if (dataType == originalComposite) {
|
||||
// Re-route to dataTypeRemoved callback after restoring listener.
|
||||
@@ -1480,12 +1480,4 @@ abstract public class CompositeEditorModel<T extends Composite> extends Composit
|
||||
return (viewComposite instanceof Structure) || (viewComposite instanceof Union);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the composite edtor's datatype manager
|
||||
* @return composite edtor's datatype manager
|
||||
*/
|
||||
public CompositeViewerDataTypeManager<T> getViewDataTypeManager() {
|
||||
return viewDTM;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-55
@@ -952,61 +952,7 @@ public abstract class CompositeEditorPanel<T extends Composite, M extends Compos
|
||||
}
|
||||
}
|
||||
|
||||
void goToNextDefinedRow(boolean forward) {
|
||||
|
||||
Integer nextRow = findNextDefinedRow(forward);
|
||||
if (nextRow == null) {
|
||||
getToolkit().beep();
|
||||
}
|
||||
else {
|
||||
goToRow(nextRow);
|
||||
}
|
||||
}
|
||||
|
||||
private Integer findNextDefinedRow(boolean forward) {
|
||||
|
||||
int currentRow = Math.max(0, model.getRow());
|
||||
DtcMatcher isUndefined = dtc -> isUndefined(dtc);
|
||||
int undefinedRow = findNextMatchingDtc(currentRow, forward, isUndefined);
|
||||
int startRow = undefinedRow + (forward ? 1 : -1);
|
||||
int n = model.getRowCount();
|
||||
if (startRow >= n) {
|
||||
return null;
|
||||
}
|
||||
|
||||
DtcMatcher isDefined = dtc -> !isUndefined(dtc);
|
||||
return findNextMatchingDtc(startRow, forward, isDefined);
|
||||
}
|
||||
|
||||
private int findNextMatchingDtc(int row, boolean forward, DtcMatcher matcher) {
|
||||
|
||||
int start = row;
|
||||
int end = forward ? model.getRowCount() : -1;
|
||||
int direction = forward ? 1 : -1;
|
||||
for (int i = start; i != end; i += direction) {
|
||||
DataTypeComponent dtc = model.getComponent(i);
|
||||
if (matcher.matches(dtc)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// just a nicer predicate
|
||||
private interface DtcMatcher {
|
||||
public boolean matches(DataTypeComponent dtc);
|
||||
}
|
||||
|
||||
private boolean isUndefined(DataTypeComponent dtc) {
|
||||
if (dtc == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
DataType dt = dtc.getDataType();
|
||||
return Undefined.isUndefined(dt);
|
||||
}
|
||||
|
||||
private void goToRow(int row) {
|
||||
protected void goToRow(int row) {
|
||||
table.getSelectionModel().setSelectionInterval(row, row);
|
||||
Rectangle cellRect = table.getCellRect(row, 0, true);
|
||||
table.scrollRectToVisible(cellRect);
|
||||
@@ -1601,4 +1547,5 @@ public abstract class CompositeEditorPanel<T extends Composite, M extends Compos
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+1
-4
@@ -225,10 +225,6 @@ public abstract class CompositeEditorProvider<T extends Composite, M extends Com
|
||||
}
|
||||
}
|
||||
|
||||
public void goToNextDefinedRow(boolean forward) {
|
||||
editorPanel.goToNextDefinedRow(forward);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HelpLocation getHelpLocation() {
|
||||
return new HelpLocation(getHelpTopic(), getHelpName());
|
||||
@@ -393,4 +389,5 @@ public abstract class CompositeEditorProvider<T extends Composite, M extends Com
|
||||
protected void closeDependentEditors() {
|
||||
// do nothing by default
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
@@ -1240,4 +1240,11 @@ abstract class CompositeViewerModel<T extends Composite> extends AbstractTableMo
|
||||
return viewComposite.isPackingEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the composite edtor's datatype manager
|
||||
* @return composite edtor's datatype manager
|
||||
*/
|
||||
public CompositeViewerDataTypeManager<T> getViewDataTypeManager() {
|
||||
return viewDTM;
|
||||
}
|
||||
}
|
||||
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/* ###
|
||||
* 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 ghidra.app.plugin.core.compositeeditor;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.MenuData;
|
||||
import docking.widgets.dialogs.NumberInputDialog;
|
||||
import docking.widgets.textfield.integer.IntegerFormat;
|
||||
import ghidra.util.HelpLocation;
|
||||
|
||||
public class JumpToOffsetAction extends CompositeEditorTableAction {
|
||||
|
||||
protected JumpToOffsetAction(StructureEditorProvider provider) {
|
||||
super(provider, "Jump to Offset");
|
||||
|
||||
MenuData data = new MenuData(new String[] { "Jump to Offset" });
|
||||
data.setMenuGroup(BASIC_ACTION_GROUP + "_Jump");
|
||||
data.setMenuSubGroup("3");
|
||||
setPopupMenuData(data);
|
||||
|
||||
setHelpLocation(
|
||||
new HelpLocation(provider.getHelpTopic(), "Structure_Editor_Go_To_Offset"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
NumberInputDialog dialog = new NumberInputDialog("Offset", 0, 0, Integer.MAX_VALUE);
|
||||
dialog.setHelpLocation(getHelpLocation());
|
||||
dialog.setTitle("Enter Offset");
|
||||
dialog.setPrompt("Enter offset:");
|
||||
|
||||
// make the 0x optional; users will have to manually change modes
|
||||
dialog.setAutoSwitchMode(false);
|
||||
boolean isHex = model.isShowingNumbersInHex();
|
||||
if (isHex) {
|
||||
dialog.setMode(IntegerFormat.HEX);
|
||||
dialog.setInputAsText(""); // have no initial value
|
||||
dialog.setDefaultMessage("");
|
||||
}
|
||||
|
||||
if (!dialog.show()) {
|
||||
return; // cancelled
|
||||
}
|
||||
|
||||
int offset = dialog.getValue();
|
||||
((StructureEditorProvider) provider).goToOffset(offset);
|
||||
}
|
||||
|
||||
}
|
||||
+4
-3
@@ -27,13 +27,14 @@ public class NextPrevDefinedComponentAction extends CompositeEditorTableAction {
|
||||
|
||||
private boolean forward;
|
||||
|
||||
public NextPrevDefinedComponentAction(CompositeEditorProvider<?, ?> provider, boolean forward) {
|
||||
public NextPrevDefinedComponentAction(StructureEditorProvider provider, boolean forward) {
|
||||
super(provider, getName(forward));
|
||||
|
||||
this.forward = forward;
|
||||
|
||||
MenuData data = new MenuData(new String[] { getName(forward) });
|
||||
data.setMenuGroup(BASIC_ACTION_GROUP + "_2"); // put below the basic action group
|
||||
data.setMenuGroup(BASIC_ACTION_GROUP + "_Jump"); // put below the basic action group
|
||||
data.setMenuSubGroup("1");
|
||||
setPopupMenuData(data);
|
||||
|
||||
setKeyBindingData(new KeyBindingData(forward ? "Control Down" : "Control Up"));
|
||||
@@ -44,7 +45,7 @@ public class NextPrevDefinedComponentAction extends CompositeEditorTableAction {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
provider.goToNextDefinedRow(forward);
|
||||
((StructureEditorProvider) provider).goToNextDefinedRow(forward);
|
||||
}
|
||||
|
||||
private static String getName(boolean forward) {
|
||||
|
||||
+11
-1
@@ -31,7 +31,8 @@ import docking.widgets.table.GTableHeaderRenderer;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.InsufficientBytesException;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.UsrException;
|
||||
import ghidra.util.task.TaskLauncher;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
@@ -201,6 +202,15 @@ class StructureEditorModel extends CompEditorModel<Structure> {
|
||||
return viewComposite == null ? 0 : viewComposite.getNumComponents();
|
||||
}
|
||||
|
||||
public int getRowForOffset(int offset) {
|
||||
DataTypeComponent dtc = viewComposite.getComponentContaining(offset);
|
||||
if (dtc != null) {
|
||||
return dtc.getOrdinal();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isSizeEditable() {
|
||||
return !isPackingEnabled();
|
||||
|
||||
+63
-2
@@ -18,8 +18,7 @@ package ghidra.app.plugin.core.compositeeditor;
|
||||
import java.awt.Component;
|
||||
|
||||
import docking.DockingWindowManager;
|
||||
import ghidra.program.model.data.DataTypeComponent;
|
||||
import ghidra.program.model.data.Structure;
|
||||
import ghidra.program.model.data.*;
|
||||
|
||||
/**
|
||||
* Editor panel for Union datatype
|
||||
@@ -53,4 +52,66 @@ public class StructureEditorPanel extends CompEditorPanel<Structure, StructureEd
|
||||
editorModel.notifyCompositeChanged();
|
||||
editorModel.setSelection(new int[] { ordinal, ordinal });
|
||||
}
|
||||
|
||||
void goToOffset(int offset) {
|
||||
|
||||
int row = model.getRowForOffset(offset);
|
||||
if (row >= 0) {
|
||||
goToRow(row);
|
||||
}
|
||||
}
|
||||
|
||||
void goToNextDefinedRow(boolean forward) {
|
||||
|
||||
Integer nextRow = findNextDefinedRow(forward);
|
||||
if (nextRow == null) {
|
||||
getToolkit().beep();
|
||||
}
|
||||
else {
|
||||
goToRow(nextRow);
|
||||
}
|
||||
}
|
||||
|
||||
private Integer findNextDefinedRow(boolean forward) {
|
||||
|
||||
int currentRow = Math.max(0, model.getRow());
|
||||
DtcMatcher isUndefined = dtc -> isUndefined(dtc);
|
||||
int undefinedRow = findNextMatchingDtc(currentRow, forward, isUndefined);
|
||||
int startRow = undefinedRow + (forward ? 1 : -1);
|
||||
int n = model.getRowCount();
|
||||
if (startRow >= n) {
|
||||
return null;
|
||||
}
|
||||
|
||||
DtcMatcher isDefined = dtc -> !isUndefined(dtc);
|
||||
return findNextMatchingDtc(startRow, forward, isDefined);
|
||||
}
|
||||
|
||||
private int findNextMatchingDtc(int row, boolean forward, DtcMatcher matcher) {
|
||||
|
||||
int start = row;
|
||||
int end = forward ? model.getRowCount() : -1;
|
||||
int direction = forward ? 1 : -1;
|
||||
for (int i = start; i != end; i += direction) {
|
||||
DataTypeComponent dtc = model.getComponent(i);
|
||||
if (matcher.matches(dtc)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// just a nicer predicate
|
||||
private interface DtcMatcher {
|
||||
public boolean matches(DataTypeComponent dtc);
|
||||
}
|
||||
|
||||
private boolean isUndefined(DataTypeComponent dtc) {
|
||||
if (dtc == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
DataType dt = dtc.getDataType();
|
||||
return Undefined.isUndefined(dt);
|
||||
}
|
||||
}
|
||||
|
||||
+11
@@ -87,6 +87,7 @@ public class StructureEditorProvider
|
||||
new ShowDataTypeInTreeAction(this),
|
||||
new NextPrevDefinedComponentAction(this, true),
|
||||
new NextPrevDefinedComponentAction(this, false),
|
||||
new JumpToOffsetAction(this),
|
||||
|
||||
// new ViewBitFieldAction(this)
|
||||
};
|
||||
@@ -165,4 +166,14 @@ public class StructureEditorProvider
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void goToNextDefinedRow(boolean forward) {
|
||||
((StructureEditorPanel) editorPanel).goToNextDefinedRow(forward);
|
||||
}
|
||||
|
||||
public void goToOffset(int offset) {
|
||||
((StructureEditorPanel) editorPanel).goToOffset(offset);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -477,14 +477,14 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
|
||||
|
||||
schemeDestByteCountField = new IntegerTextField(4, 1);
|
||||
schemeDestByteCountField.setMinValue(BigInteger.ZERO);
|
||||
schemeDestByteCountField.setUseNumberPrefix(false);
|
||||
schemeDestByteCountField.setAutoSwitchMode(false);
|
||||
schemeDestByteCountField.setFormat(IntegerFormat.DEC);
|
||||
schemeDestByteCountField.addChangeListener(ev -> schemeDestByteCountChanged());
|
||||
schemeDestByteCountField.setAccessibleName("Mapping Ratio: Destination Size");
|
||||
|
||||
schemeSrcByteCountField = new IntegerTextField(4, 1);
|
||||
schemeSrcByteCountField.setMinValue(BigInteger.ZERO);
|
||||
schemeSrcByteCountField.setUseNumberPrefix(false);
|
||||
schemeSrcByteCountField.setAutoSwitchMode(false);
|
||||
schemeSrcByteCountField.setFormat(IntegerFormat.DEC);
|
||||
schemeSrcByteCountField.addChangeListener(ev -> schemeSrcByteCountChanged());
|
||||
schemeSrcByteCountField.setAccessibleName("Mapping Ratio: Source Size");
|
||||
|
||||
+42
-6
@@ -24,6 +24,7 @@ import docking.DialogComponentProvider;
|
||||
import docking.DockingWindowManager;
|
||||
import docking.widgets.label.GDLabel;
|
||||
import docking.widgets.textfield.IntegerTextField;
|
||||
import docking.widgets.textfield.integer.AbstractIntegerTextField;
|
||||
import docking.widgets.textfield.integer.IntegerFormat;
|
||||
import ghidra.util.Swing;
|
||||
|
||||
@@ -64,9 +65,7 @@ public abstract class AbstractNumberInputDialog extends DialogComponentProvider
|
||||
* @param showAsHex if true, the initial value will be displayed as hex
|
||||
*/
|
||||
public AbstractNumberInputDialog(String title, String prompt, BigInteger initialValue,
|
||||
BigInteger min,
|
||||
BigInteger max,
|
||||
boolean showAsHex) {
|
||||
BigInteger min, BigInteger max, boolean showAsHex) {
|
||||
super(title, true, true, true, false);
|
||||
|
||||
this.min = min;
|
||||
@@ -204,10 +203,12 @@ public abstract class AbstractNumberInputDialog extends DialogComponentProvider
|
||||
|
||||
private void selectAndFocusText() {
|
||||
Swing.runLater(() -> {
|
||||
numberInputField.requestFocus();
|
||||
numberInputField.selectAll();
|
||||
});
|
||||
|
||||
if (numberInputField.isSelectTextOnFocusGainedEnabled()) {
|
||||
numberInputField.requestFocus();
|
||||
numberInputField.selectAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,6 +229,41 @@ public abstract class AbstractNumberInputDialog extends DialogComponentProvider
|
||||
numberInputField.setValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the fields value as text.
|
||||
* @param text the text
|
||||
*/
|
||||
public void setInputAsText(String text) {
|
||||
numberInputField.setText(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the input mode for the field in this dialog.
|
||||
* @param mode the mode
|
||||
* @see AbstractIntegerTextField#setFormat(IntegerFormat)
|
||||
*/
|
||||
public void setMode(IntegerFormat mode) {
|
||||
numberInputField.setFormat(mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this text field will switch the input mode format when typing a matching prefix.
|
||||
*
|
||||
* @param autoSwitch true to auto-switch; false requires user to change modes manually
|
||||
* @see AbstractIntegerTextField#setAutoSwitchMode(boolean)
|
||||
*/
|
||||
public void setAutoSwitchMode(boolean autoSwitch) {
|
||||
numberInputField.setAutoSwitchMode(autoSwitch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the label text of this dialog. The default value is "Enter number of items".
|
||||
* @param text the text
|
||||
*/
|
||||
public void setPrompt(String text) {
|
||||
label.setText(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default message to be displayed when valid values are in the text fields.
|
||||
* @param defaultMessage the message to be displayed when valid values are in the text fields.
|
||||
|
||||
@@ -96,5 +96,4 @@ public class NumberInputDialog extends AbstractNumberInputDialog {
|
||||
public int getValue() {
|
||||
return getIntValue();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+17
-2
@@ -17,6 +17,7 @@ package docking.widgets.numberformat;
|
||||
|
||||
import java.awt.Toolkit;
|
||||
import java.text.*;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import javax.swing.text.*;
|
||||
|
||||
@@ -36,18 +37,21 @@ public class IntegerFormatter extends NumberFormatter {
|
||||
setAllowsInvalid(true);
|
||||
}
|
||||
|
||||
protected Predicate<Number> createIsValidNumberPredicate() {
|
||||
return n -> true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DocumentFilter getDocumentFilter() {
|
||||
if (myDocumentFilter == null) {
|
||||
myDocumentFilter = createDocumentFilter();
|
||||
}
|
||||
|
||||
return myDocumentFilter;
|
||||
}
|
||||
|
||||
protected DocumentFilter createDocumentFilter() {
|
||||
return new PosiviteValueIntegerDocumentFilterWrapper(getFormat(),
|
||||
getOriginalDocumentFilter());
|
||||
getOriginalDocumentFilter(), createIsValidNumberPredicate());
|
||||
}
|
||||
|
||||
protected DocumentFilter getOriginalDocumentFilter() {
|
||||
@@ -58,10 +62,17 @@ public class IntegerFormatter extends NumberFormatter {
|
||||
|
||||
protected final DocumentFilter wrappedFilter;
|
||||
protected final Format format;
|
||||
protected final Predicate<Number> isValidNumber;
|
||||
|
||||
PosiviteValueIntegerDocumentFilterWrapper(Format format, DocumentFilter wrappedFilter) {
|
||||
this(format, wrappedFilter, n -> true);
|
||||
}
|
||||
|
||||
PosiviteValueIntegerDocumentFilterWrapper(Format format, DocumentFilter wrappedFilter,
|
||||
Predicate<Number> isValidNumber) {
|
||||
this.format = format;
|
||||
this.wrappedFilter = wrappedFilter;
|
||||
this.isValidNumber = isValidNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -132,6 +143,10 @@ public class IntegerFormatter extends NumberFormatter {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isValidNumber.test(number)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Long longValue = number.longValue();
|
||||
if (longValue.compareTo(0L) < 0) {
|
||||
return false; // no negatives
|
||||
|
||||
+3
-6
@@ -44,17 +44,14 @@ import docking.widgets.textfield.integer.IntegerFormat;
|
||||
* equal to this value.</LI>
|
||||
* <LI>Min value - This value must be generally be negative and will restrict the input to values
|
||||
* greater than or equal to this value. As a special case, the min value can be set to 1.</LI>
|
||||
* <LI>Use number prefix - If this mode is on, then non-decimal values must be typed with its
|
||||
* prefix(i.e., 0x for hex). When requiring non-decimal prefix, the field is permitted to auto
|
||||
* <LI>Auto-switch mode - When requiring non-decimal prefix, the field is permitted to auto
|
||||
* switch formats based on the prefix (or lack thereof). When the use prefix is off, the only way
|
||||
* to switch formats is to use the ctrl-M action.</LI>
|
||||
* <LI>Show the number mode as hint text - If showing number mode is on, the format short name
|
||||
* is displayed lightly in the bottom right portion of the text field.
|
||||
* See {@link #setShowNumberMode(boolean)}</LI>
|
||||
* </UL>
|
||||
*
|
||||
*/
|
||||
|
||||
public class IntegerTextField extends AbstractIntegerTextField {
|
||||
private IntegerFormat hex;
|
||||
private IntegerFormat decimal;
|
||||
@@ -137,11 +134,11 @@ public class IntegerTextField extends AbstractIntegerTextField {
|
||||
* mode and the typed text will be interpreted appropriately for the mode.
|
||||
*
|
||||
* @param usePrefix true to use the 0x convention for hex.
|
||||
* @deprecated use {@link #setUseNumberPrefix(boolean)} instead
|
||||
* @deprecated use {@link #setAutoSwitchMode(boolean)} instead
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "12.2")
|
||||
public void setAllowsHexPrefix(boolean usePrefix) {
|
||||
setUseNumberPrefix(usePrefix);
|
||||
setAutoSwitchMode(usePrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+148
-38
@@ -25,6 +25,9 @@ import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import javax.swing.text.*;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Strings;
|
||||
|
||||
/**
|
||||
* Base class for IntegerTextFields that allow entering integer values based on some
|
||||
* integer format (i.e., hex, decimal, unsigned hex, binary, etc.). This field does input
|
||||
@@ -38,7 +41,7 @@ public class AbstractIntegerTextField {
|
||||
protected IntegerFormat currentFormat;
|
||||
private BigInteger minValue;
|
||||
private BigInteger maxValue;
|
||||
private boolean usePrefix = true;
|
||||
private boolean autoSwitch = true;
|
||||
|
||||
/**
|
||||
* Creates a new IntegerTextField with the specified number of columns and initial value
|
||||
@@ -53,7 +56,7 @@ public class AbstractIntegerTextField {
|
||||
allFormats = Arrays.asList(formats);
|
||||
currentFormat = allFormats.get(0);
|
||||
|
||||
textField = new MultiFormatTextField(columns, allFormats, m -> setFormat(m));
|
||||
textField = new CustomHintMultiFormatTextField(columns);
|
||||
|
||||
AbstractDocument document = (AbstractDocument) textField.getDocument();
|
||||
document.setDocumentFilter(new HexDecimalDocumentFilter());
|
||||
@@ -61,6 +64,14 @@ public class AbstractIntegerTextField {
|
||||
textField.addTextChangedCallback(this::valueChanged);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the accessible name for the component of this input field.
|
||||
* @param name the accessible name for this field
|
||||
*/
|
||||
public void setAccessibleName(String name) {
|
||||
textField.getAccessibleContext().setAccessibleName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a change listener that will be notified whenever the value changes.
|
||||
*
|
||||
@@ -70,14 +81,6 @@ public class AbstractIntegerTextField {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the accessible name for the component of this input field.
|
||||
* @param name the accessible name for this field
|
||||
*/
|
||||
public void setAccessibleName(String name) {
|
||||
textField.getAccessibleContext().setAccessibleName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the changes listener.
|
||||
*
|
||||
@@ -87,6 +90,17 @@ public class AbstractIntegerTextField {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return true if the text field will select the text when it initially gains focus.}
|
||||
*/
|
||||
public boolean isSelectTextOnFocusGainedEnabled() {
|
||||
Object value = textField.getClientProperty("JTextField.selectAllOnFocusPolicy");
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
return Strings.CI.containsAny(value.toString(), "once", "always");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current value of the field or null if the field has no current value.
|
||||
*
|
||||
@@ -94,7 +108,11 @@ public class AbstractIntegerTextField {
|
||||
*/
|
||||
public BigInteger getValue() {
|
||||
String text = textField.getText();
|
||||
return parse(text, currentFormat);
|
||||
BigInteger value = parse(text, currentFormat);
|
||||
if (isInBounds(value)) {
|
||||
return value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,9 +216,14 @@ public class AbstractIntegerTextField {
|
||||
}
|
||||
|
||||
private String addPrefix(String text) {
|
||||
|
||||
// 'autoSwitch' requires a prefix. When not using auto-switch, do not add a prefix if the
|
||||
// user has not added one.
|
||||
boolean usePrefix = autoSwitch;
|
||||
if (!usePrefix) {
|
||||
return text;
|
||||
}
|
||||
|
||||
String prefix = currentFormat.getPrefix();
|
||||
if (prefix.isBlank()) {
|
||||
return text;
|
||||
@@ -328,6 +351,18 @@ public class AbstractIntegerTextField {
|
||||
textField.selectAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the current selection and places the caret at the end of the text.
|
||||
*/
|
||||
public void clearSelection() {
|
||||
String text = textField.getText();
|
||||
int end = 0;
|
||||
if (!StringUtils.isBlank(text)) {
|
||||
end = text.length();
|
||||
}
|
||||
textField.setCaretPosition(end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the horizontal alignment of the JTextField
|
||||
*
|
||||
@@ -338,16 +373,17 @@ public class AbstractIntegerTextField {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not that non-decimal formats require using a prefix (i.e., "0x" for hex).
|
||||
* Generally, using a prefix is preferred as it allows the mode to auto-switch as the user
|
||||
* types (or not types) a prefix. If the prefix is not used, the only way to change input
|
||||
* formats is to use the built-in cntr-M action.
|
||||
* @param usePrefix true to require a prefix, false to not require a prefix
|
||||
* Sets whether this text field will switch the input mode format when typing a matching prefix.
|
||||
* For example, assuming DEC and HEX modes are available, while in DEC mode, typing {@code 0x}
|
||||
* will switch the mode format to HEX.
|
||||
* <P>
|
||||
* Auto-switching is on by default.
|
||||
*
|
||||
* @param newAutoSwitch true to auto-switch; false requires user to change modes manually
|
||||
*/
|
||||
public void setUseNumberPrefix(boolean usePrefix) {
|
||||
BigInteger value = getValue();
|
||||
this.usePrefix = usePrefix;
|
||||
setValue(value);
|
||||
public void setAutoSwitchMode(boolean newAutoSwitch) {
|
||||
this.autoSwitch = newAutoSwitch;
|
||||
textField.repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -358,13 +394,35 @@ public class AbstractIntegerTextField {
|
||||
return new ArrayList<>(allFormats);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum value. The given value must be less than or equal to 0.
|
||||
* @param minValue the value
|
||||
*/
|
||||
protected void setMinValue(BigInteger minValue) {
|
||||
|
||||
if (minValue != null) {
|
||||
if (minValue.compareTo(BigInteger.ZERO) > 0) {
|
||||
throw new IllegalArgumentException("Min value must be <= 0");
|
||||
}
|
||||
}
|
||||
|
||||
BigInteger value = getValue();
|
||||
this.minValue = minValue;
|
||||
setValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum value. The given value must be greater than 0.
|
||||
* @param maxValue the value
|
||||
*/
|
||||
protected void setMaxValue(BigInteger maxValue) {
|
||||
|
||||
if (maxValue != null) {
|
||||
if (maxValue.compareTo(BigInteger.ZERO) <= 0) {
|
||||
throw new IllegalArgumentException("Max value must be > 0");
|
||||
}
|
||||
}
|
||||
|
||||
BigInteger value = getValue();
|
||||
this.maxValue = maxValue;
|
||||
setValue(value);
|
||||
@@ -381,6 +439,9 @@ public class AbstractIntegerTextField {
|
||||
}
|
||||
|
||||
protected boolean isInBounds(BigInteger value) {
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
if (minValue != null && minValue.compareTo(value) > 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -391,21 +452,41 @@ public class AbstractIntegerTextField {
|
||||
if (text.equals("0") || text.equals("-0")) {
|
||||
return BigInteger.ZERO;
|
||||
}
|
||||
|
||||
String prefix = format.getPrefix();
|
||||
if (usePrefix && !prefix.isBlank()) {
|
||||
if (text.startsWith(prefix)) {
|
||||
text = text.substring(prefix.length());
|
||||
}
|
||||
else if (text.startsWith("-" + prefix)) {
|
||||
text = "-" + text.substring(prefix.length() + 1);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
if (prefix.isBlank()) {
|
||||
return format.parse(text);
|
||||
}
|
||||
|
||||
// auto-switching requires a prefix so we know when we should switch formats
|
||||
boolean requiresPrefix = autoSwitch;
|
||||
boolean hasPrefix = hasPrefix(text, prefix);
|
||||
if (requiresPrefix && !hasPrefix) {
|
||||
return null;
|
||||
}
|
||||
|
||||
text = text.replaceFirst(prefix, "");
|
||||
return format.parse(text);
|
||||
}
|
||||
|
||||
private boolean hasPrefix(String text, String prefix) {
|
||||
return text.startsWith(prefix) || text.startsWith("-" + prefix);
|
||||
}
|
||||
|
||||
private boolean hasFormatPrefix(String text, IntegerFormat format) {
|
||||
if (text.startsWith("-")) {
|
||||
if (!allowsNegative()) {
|
||||
return false;
|
||||
}
|
||||
if (text.length() == 1) {
|
||||
return true;
|
||||
}
|
||||
text = text.substring(1);
|
||||
}
|
||||
|
||||
return format.getPrefix().startsWith(text);
|
||||
}
|
||||
|
||||
private boolean isValidPrefix(String text, IntegerFormat format) {
|
||||
if (text.startsWith("-")) {
|
||||
if (!allowsNegative()) {
|
||||
@@ -416,12 +497,13 @@ public class AbstractIntegerTextField {
|
||||
}
|
||||
text = text.substring(1);
|
||||
}
|
||||
if (!usePrefix) {
|
||||
return false;
|
||||
}
|
||||
return usePrefix && format.getPrefix().startsWith(text);
|
||||
return format.getPrefix().startsWith(text);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
// Inner Classes
|
||||
//=================================================================================================
|
||||
|
||||
/**
|
||||
* DocumentFilter that prevents users from entering invalid data into the field.
|
||||
*/
|
||||
@@ -473,8 +555,9 @@ public class AbstractIntegerTextField {
|
||||
if (text.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isValidPrefix(text, currentFormat)) {
|
||||
return true;
|
||||
return true; // just a prefix and is valid
|
||||
}
|
||||
|
||||
BigInteger value = parse(text, currentFormat);
|
||||
@@ -482,8 +565,8 @@ public class AbstractIntegerTextField {
|
||||
return isInBounds(value);
|
||||
}
|
||||
|
||||
if (usePrefix) {
|
||||
// only allow auto switching if using number prefix
|
||||
// only allow auto switching if using number prefix
|
||||
if (autoSwitch) {
|
||||
return autoSwitchFormat(text);
|
||||
}
|
||||
return false;
|
||||
@@ -491,11 +574,12 @@ public class AbstractIntegerTextField {
|
||||
|
||||
private boolean autoSwitchFormat(String text) {
|
||||
for (IntegerFormat format : allFormats) {
|
||||
if (isValidPrefix(text, format)) {
|
||||
if (hasFormatPrefix(text, format)) {
|
||||
currentFormat = format;
|
||||
textField.setFormat(format);
|
||||
return true;
|
||||
}
|
||||
|
||||
BigInteger value = parse(text, format);
|
||||
if (value != null && isInBounds(value)) {
|
||||
currentFormat = format;
|
||||
@@ -515,4 +599,30 @@ public class AbstractIntegerTextField {
|
||||
}
|
||||
}
|
||||
|
||||
private class CustomHintMultiFormatTextField extends MultiFormatTextField {
|
||||
|
||||
public CustomHintMultiFormatTextField(int columns) {
|
||||
super(columns, allFormats, m -> AbstractIntegerTextField.this.setFormat(m));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getHintToolTipText() {
|
||||
String superText = super.getHintToolTipText();
|
||||
if (autoSwitch) {
|
||||
return superText;
|
||||
}
|
||||
|
||||
return superText + "<br><br><i>*Auto-switch mode disabled</i>";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getHint() {
|
||||
String superHint = super.getHint();
|
||||
if (autoSwitch) {
|
||||
return superHint;
|
||||
}
|
||||
|
||||
return superHint + "*";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+30
-17
@@ -39,17 +39,18 @@ import utility.function.Callback;
|
||||
public class MultiFormatTextField extends JTextField {
|
||||
|
||||
private static final String FONT_ID = "font.input.hint";
|
||||
private int hintWidth;
|
||||
|
||||
private boolean showFormatHint = true;
|
||||
private List<IntegerFormat> formats;
|
||||
private int currentFormatIndex;
|
||||
|
||||
private String toolTipAppendix;
|
||||
|
||||
public MultiFormatTextField(int columns, List<IntegerFormat> formats,
|
||||
Consumer<IntegerFormat> formatChangeConsumer) {
|
||||
super(columns);
|
||||
|
||||
this.formats = formats;
|
||||
updateFormatNameWidth();
|
||||
|
||||
addKeyListener(new KeyAdapter() {
|
||||
@Override
|
||||
@@ -58,7 +59,7 @@ public class MultiFormatTextField extends JTextField {
|
||||
if (++currentFormatIndex >= formats.size()) {
|
||||
currentFormatIndex = 0;
|
||||
}
|
||||
updateFormatNameWidth();
|
||||
|
||||
formatChangeConsumer.accept(formats.get(currentFormatIndex));
|
||||
repaint();
|
||||
}
|
||||
@@ -67,7 +68,6 @@ public class MultiFormatTextField extends JTextField {
|
||||
|
||||
// make sure tooltips will be activated
|
||||
ToolTipManager.sharedInstance().registerComponent(this);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,30 +96,41 @@ public class MultiFormatTextField extends JTextField {
|
||||
});
|
||||
}
|
||||
|
||||
private void updateFormatNameWidth() {
|
||||
FontMetrics fontMetrics = getFontMetrics(Gui.getFont(FONT_ID));
|
||||
hintWidth = fontMetrics.stringWidth(formats.get(currentFormatIndex).getName());
|
||||
protected String getHint() {
|
||||
return formats.get(currentFormatIndex).getName();
|
||||
}
|
||||
|
||||
public void setToolTipAppendix(String appendix) {
|
||||
this.toolTipAppendix = appendix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToolTipText(MouseEvent event) {
|
||||
|
||||
int hintStart = getBounds().width - hintWidth;
|
||||
String hint = getHint();
|
||||
FontMetrics fontMetrics = getFontMetrics(Gui.getFont(FONT_ID));
|
||||
int hintWidth = fontMetrics.stringWidth(hint);
|
||||
|
||||
int hintStart = getBounds().width - hintWidth;
|
||||
if (event.getX() > hintStart && formats.size() > 1) {
|
||||
String key = DockingUtils.CONTROL_KEY_NAME;
|
||||
IntegerFormat format = formats.get(currentFormatIndex);
|
||||
return "Enter value in %s format. Press %s-M to cycle input formats."
|
||||
.formatted(format.getDescription(), key);
|
||||
return getHintToolTipText();
|
||||
}
|
||||
|
||||
return super.getToolTipText(event);
|
||||
}
|
||||
|
||||
protected String getHintToolTipText() {
|
||||
String key = DockingUtils.CONTROL_KEY_NAME;
|
||||
IntegerFormat format = formats.get(currentFormatIndex);
|
||||
String appendix = toolTipAppendix == null ? "" : toolTipAppendix;
|
||||
return """
|
||||
<html>Enter value in %s format.<br>
|
||||
<i>Press %s-M to cycle input formats.</i>%s
|
||||
""".formatted(format.getDescription(), key, appendix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link IntegerFormat} that will be used to format and parse the text in this
|
||||
* field.
|
||||
* Sets the {@link IntegerFormat} that will be used to format and parse the text in this field.
|
||||
* @param format the number format that will be used to format and parse the text in this field
|
||||
*/
|
||||
public void setFormat(IntegerFormat format) {
|
||||
@@ -127,7 +138,6 @@ public class MultiFormatTextField extends JTextField {
|
||||
if (indexOf >= 0) {
|
||||
currentFormatIndex = indexOf;
|
||||
}
|
||||
updateFormatNameWidth();
|
||||
repaint();
|
||||
}
|
||||
|
||||
@@ -153,6 +163,10 @@ public class MultiFormatTextField extends JTextField {
|
||||
g.setFont(Gui.getFont(FONT_ID));
|
||||
g.setColor(Messages.HINT);
|
||||
|
||||
String hint = getHint();
|
||||
FontMetrics fontMetrics = getFontMetrics(Gui.getFont(FONT_ID));
|
||||
int hintWidth = fontMetrics.stringWidth(hint);
|
||||
|
||||
Dimension size = getSize();
|
||||
Insets insets = getInsets();
|
||||
int x;
|
||||
@@ -163,8 +177,7 @@ public class MultiFormatTextField extends JTextField {
|
||||
x = size.width - insets.right - hintWidth;
|
||||
}
|
||||
int y = size.height - insets.bottom - 1;
|
||||
IntegerFormat format = formats.get(currentFormatIndex);
|
||||
GraphicsUtils.drawString(this, g, format.getName(), x, y);
|
||||
GraphicsUtils.drawString(this, g, hint, x, y);
|
||||
g.setFont(savedFont);
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ public class IntValue extends AbstractValue<Integer> {
|
||||
public JComponent getComponent() {
|
||||
if (field == null) {
|
||||
field = new IntegerTextField(20);
|
||||
field.setUseNumberPrefix(false);
|
||||
field.setAutoSwitchMode(false);
|
||||
field.setShowNumberMode(false);
|
||||
if (displayAsHex) {
|
||||
field.setFormat(IntegerFormat.HEX);
|
||||
|
||||
@@ -58,7 +58,7 @@ public class LongValue extends AbstractValue<Long> {
|
||||
public JComponent getComponent() {
|
||||
if (field == null) {
|
||||
field = new IntegerTextField(20);
|
||||
field.setUseNumberPrefix(false);
|
||||
field.setAutoSwitchMode(false);
|
||||
field.setShowNumberMode(false);
|
||||
if (displayAsHex) {
|
||||
field.setFormat(IntegerFormat.HEX);
|
||||
|
||||
+2
-2
@@ -98,8 +98,8 @@ public abstract class AbstractIntegerTextFieldTest<T extends AbstractIntegerText
|
||||
triggerText(textField, text);
|
||||
}
|
||||
|
||||
protected void setUsePrefix(boolean b) {
|
||||
runSwing(() -> field.setUseNumberPrefix(b));
|
||||
protected void setAutoSwitchMode(boolean b) {
|
||||
runSwing(() -> field.setAutoSwitchMode(b));
|
||||
}
|
||||
|
||||
class TestChangeListener implements ChangeListener {
|
||||
|
||||
+15
-20
@@ -80,7 +80,7 @@ public class IntegerTextFieldTest extends AbstractIntegerTextFieldTest<IntegerTe
|
||||
typeText("a");
|
||||
assertEquals(null, getBigIntegerValue());
|
||||
|
||||
setUsePrefix(false);
|
||||
setAutoSwitchMode(false);
|
||||
typeText("abc");
|
||||
assertEquals(0xabc, getValue());
|
||||
}
|
||||
@@ -134,12 +134,9 @@ public class IntegerTextFieldTest extends AbstractIntegerTextFieldTest<IntegerTe
|
||||
assertNull(field.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testMinSetTo1() {
|
||||
field.setMinValue(BigInteger.ONE);
|
||||
setValue(0);
|
||||
assertEquals(1, getValue());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -219,15 +216,15 @@ public class IntegerTextFieldTest extends AbstractIntegerTextFieldTest<IntegerTe
|
||||
|
||||
@Test
|
||||
public void testHexValueInDontRequireHexPrefixMode() {
|
||||
field.setUseNumberPrefix(false);
|
||||
field.setAutoSwitchMode(false);
|
||||
field.setFormat(HEX);
|
||||
setValue(255);
|
||||
assertEquals("ff", field.getText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAutoModeSwitchingIsOffWhenPrefixNotUsed() {
|
||||
field.setUseNumberPrefix(false);
|
||||
public void testAutoSwitchingMode() {
|
||||
field.setAutoSwitchMode(false);
|
||||
field.setFormat(HEX);
|
||||
typeText("15");
|
||||
assertEquals(HEX, getFormat());
|
||||
@@ -265,12 +262,12 @@ public class IntegerTextFieldTest extends AbstractIntegerTextFieldTest<IntegerTe
|
||||
|
||||
@Test
|
||||
public void testUseHexPrefixUpdatesTextField() {
|
||||
field.setUseNumberPrefix(false);
|
||||
field.setAutoSwitchMode(false);
|
||||
setFormat(HEX);
|
||||
setValue(255);
|
||||
assertEquals("ff", field.getText());
|
||||
field.setUseNumberPrefix(true);
|
||||
assertEquals("0xff", field.getText());
|
||||
field.setAutoSwitchMode(true);
|
||||
assertEquals("ff", field.getText());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -311,21 +308,19 @@ public class IntegerTextFieldTest extends AbstractIntegerTextFieldTest<IntegerTe
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMinValueOfOneDecimalFormat() {
|
||||
public void testDecimalFormat_ValueOfZero() {
|
||||
setFormat(DEC);
|
||||
field.setMinValue(BigInteger.ONE);
|
||||
typeText("0");
|
||||
assertEquals("", field.getText());
|
||||
typeText("1");
|
||||
assertEquals("1", field.getText());
|
||||
assertEquals("0", field.getText());
|
||||
assertEquals(BigInteger.ZERO, field.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMinValueOfOneHexFormat() {
|
||||
public void testHexFormat_ValueOfZero() {
|
||||
setFormat(HEX);
|
||||
field.setMinValue(BigInteger.ONE);
|
||||
typeText("0x1");
|
||||
assertEquals("0x1", field.getText());
|
||||
typeText("0");
|
||||
assertEquals("0", field.getText());
|
||||
assertEquals(BigInteger.ZERO, field.getValue());
|
||||
}
|
||||
|
||||
protected void setMinValue(BigInteger minValue) {
|
||||
|
||||
Reference in New Issue
Block a user