mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-11-04 13:26:44 +00:00
improve validation and focus handling in integer spinners
This commit is contained in:
parent
766a8c267f
commit
c51f3d9e66
9 changed files with 128 additions and 22 deletions
|
@ -0,0 +1,83 @@
|
|||
package com.sparrowwallet.sparrow.control;
|
||||
|
||||
import javafx.beans.NamedArg;
|
||||
import javafx.scene.control.Spinner;
|
||||
import javafx.scene.control.SpinnerValueFactory;
|
||||
import javafx.util.converter.IntegerStringConverter;
|
||||
|
||||
public class IntegerSpinner extends Spinner<Integer> {
|
||||
public IntegerSpinner() {
|
||||
super();
|
||||
setupEditor();
|
||||
}
|
||||
|
||||
public IntegerSpinner(@NamedArg("min") int min,
|
||||
@NamedArg("max") int max,
|
||||
@NamedArg("initialValue") int initialValue) {
|
||||
super(min, max, initialValue);
|
||||
setupEditor();
|
||||
}
|
||||
|
||||
public IntegerSpinner(@NamedArg("min") int min,
|
||||
@NamedArg("max") int max,
|
||||
@NamedArg("initialValue") int initialValue,
|
||||
@NamedArg("amountToStepBy") int amountToStepBy) {
|
||||
super(min, max, initialValue, amountToStepBy);
|
||||
setupEditor();
|
||||
}
|
||||
|
||||
private void setupEditor() {
|
||||
getEditor().focusedProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if(newValue != null && !newValue) {
|
||||
commitValue();
|
||||
}
|
||||
});
|
||||
getEditor().textProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if(!newValue.matches("\\d*")) {
|
||||
getEditor().setText(newValue.replaceAll("[^\\d]", ""));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static class ValueFactory extends SpinnerValueFactory.IntegerSpinnerValueFactory {
|
||||
public ValueFactory(@NamedArg("min") int min,
|
||||
@NamedArg("max") int max) {
|
||||
super(min, max);
|
||||
setupConverter(min);
|
||||
}
|
||||
|
||||
public ValueFactory(@NamedArg("min") int min,
|
||||
@NamedArg("max") int max,
|
||||
@NamedArg("initialValue") int initialValue) {
|
||||
super(min, max, initialValue);
|
||||
setupConverter(initialValue);
|
||||
}
|
||||
|
||||
public ValueFactory(@NamedArg("min") int min,
|
||||
@NamedArg("max") int max,
|
||||
@NamedArg("initialValue") int initialValue,
|
||||
@NamedArg("amountToStepBy") int amountToStepBy) {
|
||||
super(min, max, initialValue, amountToStepBy);
|
||||
setupConverter(initialValue);
|
||||
}
|
||||
|
||||
private void setupConverter(Integer defaultValue) {
|
||||
setConverter(new IntegerStringConverter() {
|
||||
@Override
|
||||
public Integer fromString(String value) {
|
||||
if(value == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
value = value.trim();
|
||||
|
||||
if(value.length() < 1) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return Integer.valueOf(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -82,7 +82,7 @@ public class HeadersController extends TransactionFormController implements Init
|
|||
private TransactionDiagram transactionDiagram;
|
||||
|
||||
@FXML
|
||||
private Spinner<Integer> version;
|
||||
private IntegerSpinner version;
|
||||
|
||||
@FXML
|
||||
private CopyableLabel segwit;
|
||||
|
@ -112,10 +112,10 @@ public class HeadersController extends TransactionFormController implements Init
|
|||
private Field locktimeDateField;
|
||||
|
||||
@FXML
|
||||
private Spinner<Integer> locktimeNone;
|
||||
private IntegerSpinner locktimeNone;
|
||||
|
||||
@FXML
|
||||
private Spinner<Integer> locktimeBlock;
|
||||
private IntegerSpinner locktimeBlock;
|
||||
|
||||
@FXML
|
||||
private Hyperlink locktimeCurrentHeight;
|
||||
|
@ -243,8 +243,12 @@ public class HeadersController extends TransactionFormController implements Init
|
|||
|
||||
updateTxId();
|
||||
|
||||
version.setValueFactory(new SpinnerValueFactory.IntegerSpinnerValueFactory(1, 2, (int)tx.getVersion()));
|
||||
version.setValueFactory(new IntegerSpinner.ValueFactory(1, 2, (int)tx.getVersion()));
|
||||
version.valueProperty().addListener((obs, oldValue, newValue) -> {
|
||||
if(newValue == null || newValue < 1 || newValue > 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
tx.setVersion(newValue);
|
||||
if(oldValue != null) {
|
||||
EventManager.get().post(new TransactionChangedEvent(tx));
|
||||
|
@ -305,9 +309,9 @@ public class HeadersController extends TransactionFormController implements Init
|
|||
futureDateWarning.managedProperty().bind(futureDateWarning.visibleProperty());
|
||||
futureDateWarning.setVisible(false);
|
||||
|
||||
locktimeNone.setValueFactory(new SpinnerValueFactory.IntegerSpinnerValueFactory(0, (int)Transaction.MAX_BLOCK_LOCKTIME-1, 0));
|
||||
locktimeNone.setValueFactory(new IntegerSpinner.ValueFactory(0, (int)Transaction.MAX_BLOCK_LOCKTIME-1, 0));
|
||||
if(tx.getLocktime() < Transaction.MAX_BLOCK_LOCKTIME) {
|
||||
locktimeBlock.setValueFactory(new SpinnerValueFactory.IntegerSpinnerValueFactory(0, (int)Transaction.MAX_BLOCK_LOCKTIME-1, (int)tx.getLocktime()));
|
||||
locktimeBlock.setValueFactory(new IntegerSpinner.ValueFactory(0, (int)Transaction.MAX_BLOCK_LOCKTIME-1, (int)tx.getLocktime()));
|
||||
if(tx.getLocktime() == 0) {
|
||||
locktimeToggleGroup.selectToggle(locktimeNoneType);
|
||||
} else {
|
||||
|
@ -316,13 +320,17 @@ public class HeadersController extends TransactionFormController implements Init
|
|||
LocalDateTime date = Instant.now().atZone(ZoneId.systemDefault()).toLocalDateTime();
|
||||
locktimeDate.setDateTimeValue(date);
|
||||
} else {
|
||||
locktimeBlock.setValueFactory(new SpinnerValueFactory.IntegerSpinnerValueFactory(0, (int)Transaction.MAX_BLOCK_LOCKTIME-1));
|
||||
locktimeBlock.setValueFactory(new IntegerSpinner.ValueFactory(0, (int)Transaction.MAX_BLOCK_LOCKTIME-1));
|
||||
LocalDateTime date = Instant.ofEpochSecond(tx.getLocktime()).atZone(ZoneId.systemDefault()).toLocalDateTime();
|
||||
locktimeDate.setDateTimeValue(date);
|
||||
locktimeToggleGroup.selectToggle(locktimeDateType);
|
||||
}
|
||||
|
||||
locktimeBlock.valueProperty().addListener((obs, oldValue, newValue) -> {
|
||||
if(newValue == null || newValue < 0 || newValue >= Transaction.MAX_BLOCK_LOCKTIME) {
|
||||
return;
|
||||
}
|
||||
|
||||
tx.setLocktime(newValue);
|
||||
locktimeCurrentHeight.setVisible(headersForm.isEditable() && AppServices.getCurrentBlockHeight() != null && newValue < AppServices.getCurrentBlockHeight());
|
||||
futureBlockWarning.setVisible(AppServices.getCurrentBlockHeight() != null && newValue > AppServices.getCurrentBlockHeight());
|
||||
|
|
|
@ -104,7 +104,7 @@ public class InputController extends TransactionFormController implements Initia
|
|||
private CopyableLabel locktimeAbsolute;
|
||||
|
||||
@FXML
|
||||
private Spinner<Integer> locktimeRelativeBlocks;
|
||||
private IntegerSpinner locktimeRelativeBlocks;
|
||||
|
||||
@FXML
|
||||
private RelativeTimelockSpinner locktimeRelativeSeconds;
|
||||
|
@ -406,7 +406,7 @@ public class InputController extends TransactionFormController implements Initia
|
|||
}
|
||||
});
|
||||
|
||||
locktimeRelativeBlocks.setValueFactory(new SpinnerValueFactory.IntegerSpinnerValueFactory(0, (int)TransactionInput.RELATIVE_TIMELOCK_VALUE_MASK, 0));
|
||||
locktimeRelativeBlocks.setValueFactory(new IntegerSpinner.ValueFactory(0, (int)TransactionInput.RELATIVE_TIMELOCK_VALUE_MASK, 0));
|
||||
locktimeRelativeBlocks.managedProperty().bind(locktimeRelativeBlocks.visibleProperty());
|
||||
locktimeRelativeSeconds.managedProperty().bind(locktimeRelativeSeconds.visibleProperty());
|
||||
locktimeRelativeCombo.getSelectionModel().selectedItemProperty().addListener((ov, old_toggle, new_toggle) -> {
|
||||
|
@ -433,6 +433,10 @@ public class InputController extends TransactionFormController implements Initia
|
|||
}
|
||||
|
||||
locktimeRelativeBlocks.valueProperty().addListener((obs, oldValue, newValue) -> {
|
||||
if(newValue == null || newValue < 0 || newValue > TransactionInput.RELATIVE_TIMELOCK_VALUE_MASK) {
|
||||
return;
|
||||
}
|
||||
|
||||
setRelativeLocktime(txInput, transaction, oldValue != null);
|
||||
});
|
||||
locktimeRelativeSeconds.valueProperty().addListener((obs, oldValue, newValue) -> {
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.sparrowwallet.sparrow.wallet;
|
|||
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||
import com.sparrowwallet.sparrow.EventManager;
|
||||
import com.sparrowwallet.sparrow.control.DateStringConverter;
|
||||
import com.sparrowwallet.sparrow.control.IntegerSpinner;
|
||||
import com.sparrowwallet.sparrow.event.SettingsChangedEvent;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
|
@ -10,8 +11,6 @@ import javafx.fxml.FXML;
|
|||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.DatePicker;
|
||||
import javafx.scene.control.Spinner;
|
||||
import javafx.scene.control.SpinnerValueFactory;
|
||||
import javafx.util.StringConverter;
|
||||
|
||||
import java.net.URL;
|
||||
|
@ -28,7 +27,7 @@ public class AdvancedController implements Initializable {
|
|||
private DatePicker birthDate;
|
||||
|
||||
@FXML
|
||||
private Spinner<Integer> gapLimit;
|
||||
private IntegerSpinner gapLimit;
|
||||
|
||||
@FXML
|
||||
private ComboBox<Integer> watchLast;
|
||||
|
@ -50,8 +49,12 @@ public class AdvancedController implements Initializable {
|
|||
}
|
||||
});
|
||||
|
||||
gapLimit.setValueFactory(new SpinnerValueFactory.IntegerSpinnerValueFactory(Wallet.DEFAULT_LOOKAHEAD, 9999, wallet.getGapLimit()));
|
||||
gapLimit.setValueFactory(new IntegerSpinner.ValueFactory(Wallet.DEFAULT_LOOKAHEAD, 9999, wallet.getGapLimit()));
|
||||
gapLimit.valueProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if(newValue == null || newValue < Wallet.DEFAULT_LOOKAHEAD || newValue > 9999) {
|
||||
return;
|
||||
}
|
||||
|
||||
wallet.setGapLimit(newValue);
|
||||
if(!watchLast.getItems().equals(getWatchListItems(wallet))) {
|
||||
Integer value = watchLast.getValue();
|
||||
|
|
|
@ -7,6 +7,7 @@ import com.sparrowwallet.drongo.wallet.StandardAccount;
|
|||
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||
import com.sparrowwallet.sparrow.AppServices;
|
||||
import com.sparrowwallet.sparrow.EventManager;
|
||||
import com.sparrowwallet.sparrow.control.IntegerSpinner;
|
||||
import com.sparrowwallet.sparrow.event.MixToConfigChangedEvent;
|
||||
import com.sparrowwallet.sparrow.whirlpool.Whirlpool;
|
||||
import javafx.collections.FXCollections;
|
||||
|
@ -31,7 +32,7 @@ public class MixToController implements Initializable {
|
|||
private ComboBox<Wallet> mixToWallets;
|
||||
|
||||
@FXML
|
||||
private Spinner<Integer> minMixes;
|
||||
private IntegerSpinner minMixes;
|
||||
|
||||
@FXML
|
||||
private ComboBox<IndexRange> indexRange;
|
||||
|
@ -94,8 +95,12 @@ public class MixToController implements Initializable {
|
|||
});
|
||||
|
||||
int initialMinMixes = mixConfig.getMinMixes() == null ? Whirlpool.DEFAULT_MIXTO_MIN_MIXES : mixConfig.getMinMixes();
|
||||
minMixes.setValueFactory(new SpinnerValueFactory.IntegerSpinnerValueFactory(1, 10000, initialMinMixes));
|
||||
minMixes.setValueFactory(new IntegerSpinner.ValueFactory(1, 10000, initialMinMixes));
|
||||
minMixes.valueProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if(newValue == null || newValue < 1 || newValue > 10000) {
|
||||
return;
|
||||
}
|
||||
|
||||
mixConfig.setMinMixes(newValue);
|
||||
EventManager.get().post(new MixToConfigChangedEvent(wallet));
|
||||
});
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
<?import javafx.scene.control.TabPane?>
|
||||
<?import javafx.scene.control.Tab?>
|
||||
<?import com.sparrowwallet.sparrow.control.TransactionDiagram?>
|
||||
<?import com.sparrowwallet.sparrow.control.IntegerSpinner?>
|
||||
|
||||
<GridPane hgap="10.0" vgap="10.0" styleClass="tx-pane" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.sparrowwallet.sparrow.transaction.HeadersController" stylesheets="@headers.css, @transaction.css, @../general.css">
|
||||
<padding>
|
||||
|
@ -71,7 +72,7 @@
|
|||
<Form GridPane.columnIndex="0" GridPane.rowIndex="0">
|
||||
<Fieldset text="Headers" inputGrow="SOMETIMES">
|
||||
<Field text="Version:">
|
||||
<Spinner fx:id="version" prefWidth="60" editable="true" />
|
||||
<IntegerSpinner fx:id="version" prefWidth="60" editable="true" />
|
||||
</Field>
|
||||
<Field text="Type:">
|
||||
<CopyableLabel fx:id="segwit" />
|
||||
|
@ -94,10 +95,10 @@
|
|||
</SegmentedButton>
|
||||
</Field>
|
||||
<Field fx:id="locktimeNoneField" text="Block:">
|
||||
<Spinner fx:id="locktimeNone" disable="true" prefWidth="120"/>
|
||||
<IntegerSpinner fx:id="locktimeNone" disable="true" prefWidth="120"/>
|
||||
</Field>
|
||||
<Field fx:id="locktimeBlockField" text="Block:">
|
||||
<Spinner fx:id="locktimeBlock" editable="true" max="499999999" prefWidth="120"/>
|
||||
<IntegerSpinner fx:id="locktimeBlock" editable="true" max="499999999" prefWidth="120"/>
|
||||
<Hyperlink fx:id="locktimeCurrentHeight" text="Set current height" onAction="#setLocktimeToCurrentHeight" />
|
||||
<Label fx:id="futureBlockWarning">
|
||||
<graphic>
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
<?import com.sparrowwallet.sparrow.control.AddressLabel?>
|
||||
<?import com.sparrowwallet.sparrow.control.UnlabeledToggleSwitch?>
|
||||
<?import com.sparrowwallet.sparrow.control.ScriptArea?>
|
||||
<?import com.sparrowwallet.sparrow.control.IntegerSpinner?>
|
||||
|
||||
<GridPane hgap="10.0" vgap="10.0" styleClass="tx-pane" stylesheets="@input.css, @transaction.css, @../script.css, @../general.css" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.sparrowwallet.sparrow.transaction.InputController">
|
||||
<padding>
|
||||
|
@ -122,7 +123,7 @@
|
|||
<CopyableLabel fx:id="locktimeAbsolute" />
|
||||
</Field>
|
||||
<Field fx:id="locktimeRelativeField" text="Value:">
|
||||
<Spinner fx:id="locktimeRelativeBlocks" editable="true" prefWidth="110"/>
|
||||
<IntegerSpinner fx:id="locktimeRelativeBlocks" editable="true" prefWidth="110"/>
|
||||
<RelativeTimelockSpinner fx:id="locktimeRelativeSeconds" editable="true" prefWidth="110"/>
|
||||
<ComboBox fx:id="locktimeRelativeCombo">
|
||||
<items>
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
<?import tornadofx.control.Field?>
|
||||
<?import com.sparrowwallet.sparrow.control.HelpLabel?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import com.sparrowwallet.sparrow.control.IntegerSpinner?>
|
||||
|
||||
<BorderPane stylesheets="@../general.css" styleClass="line-border" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="com.sparrowwallet.sparrow.wallet.AdvancedController">
|
||||
<center>
|
||||
|
@ -31,7 +32,7 @@
|
|||
<HelpLabel helpText="The date of the earliest transaction (used to avoid scanning the entire blockchain)."/>
|
||||
</Field>
|
||||
<Field text="Gap limit:">
|
||||
<Spinner fx:id="gapLimit" editable="true" prefWidth="90" />
|
||||
<IntegerSpinner fx:id="gapLimit" editable="true" prefWidth="90" />
|
||||
<HelpLabel helpText="Change how far ahead to look for additional transactions beyond the highest derivation with previous transaction outputs."/>
|
||||
</Field>
|
||||
<Field text="Watch addresses:">
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.collections.FXCollections?>
|
||||
<?import javafx.scene.control.ComboBox?>
|
||||
<?import javafx.scene.control.Spinner?>
|
||||
<?import com.samourai.whirlpool.client.wallet.beans.IndexRange?>
|
||||
<?import com.sparrowwallet.sparrow.control.IntegerSpinner?>
|
||||
|
||||
<BorderPane stylesheets="@../general.css" styleClass="line-border" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="com.sparrowwallet.sparrow.wallet.MixToController">
|
||||
<center>
|
||||
|
@ -34,7 +34,7 @@
|
|||
<HelpLabel helpText="Select an open wallet to mix to."/>
|
||||
</Field>
|
||||
<Field text="Minimum mixes:">
|
||||
<Spinner fx:id="minMixes" editable="true" prefWidth="90" />
|
||||
<IntegerSpinner fx:id="minMixes" editable="true" prefWidth="90" />
|
||||
<HelpLabel helpText="The minimum number of mixes required before mixing to the selected wallet.\nTo ensure privacy, each mix beyond this number will have a 75% probability to mix to the selected wallet."/>
|
||||
</Field>
|
||||
</Fieldset>
|
||||
|
|
Loading…
Reference in a new issue