Customize prefix text entry
To only allow digits and to respect the digitsPerGroup spacing
This commit is contained in:
		@@ -0,0 +1,145 @@
 | 
			
		||||
    package name.nathanmcrae.numbersstation;
 | 
			
		||||
 | 
			
		||||
    import java.lang.StringBuilder;
 | 
			
		||||
    import javafx.application.Platform;
 | 
			
		||||
    import javafx.fxml.FXML;
 | 
			
		||||
    import javafx.scene.control.Button;
 | 
			
		||||
    import javafx.scene.control.TextField;
 | 
			
		||||
    import javafx.stage.Stage;
 | 
			
		||||
    import javafx.scene.input.KeyCode;
 | 
			
		||||
    import javafx.scene.input.KeyEvent;
 | 
			
		||||
 | 
			
		||||
    public class AddPrefixController {
 | 
			
		||||
        @FXML
 | 
			
		||||
        private TextField prefixField;
 | 
			
		||||
 | 
			
		||||
        @FXML
 | 
			
		||||
        private Button okButton;
 | 
			
		||||
 | 
			
		||||
        @FXML
 | 
			
		||||
        private Button cancelButton;
 | 
			
		||||
 | 
			
		||||
        private int digitsPerGroup;
 | 
			
		||||
        private MainSettingsController mainSettingsController;
 | 
			
		||||
 | 
			
		||||
        public void setDigitsPerGroup(int newDigitsPerGroup) {
 | 
			
		||||
            digitsPerGroup = newDigitsPerGroup;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void setMainSettingsController(MainSettingsController mainSettingsController) {
 | 
			
		||||
            this.mainSettingsController = mainSettingsController;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @FXML
 | 
			
		||||
        private void initialize() {
 | 
			
		||||
            okButton.setOnAction(event -> handleOkButtonPress());
 | 
			
		||||
            cancelButton.setOnAction(event -> handleCancelButtonPress());
 | 
			
		||||
 | 
			
		||||
            // Set focus on the text field when the window is shown
 | 
			
		||||
            Platform.runLater(() -> prefixField.requestFocus());
 | 
			
		||||
 | 
			
		||||
            // Add event filter to handle Enter key press
 | 
			
		||||
            prefixField.addEventFilter(KeyEvent.ANY, event -> {
 | 
			
		||||
                if (event.getCode() == KeyCode.ENTER) {
 | 
			
		||||
                    handleOkButtonPress();
 | 
			
		||||
                    event.consume();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                int cursorPosition = prefixField.getCaretPosition();
 | 
			
		||||
 | 
			
		||||
                String character = event.getCharacter();
 | 
			
		||||
                KeyCode code = event.getCode();
 | 
			
		||||
 | 
			
		||||
                String str = event.getText();
 | 
			
		||||
 | 
			
		||||
                // Consume the event to block the default behavior
 | 
			
		||||
                if (!(code == KeyCode.DOWN ||
 | 
			
		||||
                      code == KeyCode.END ||
 | 
			
		||||
                      code == KeyCode.HOME ||
 | 
			
		||||
                      code == KeyCode.LEFT ||
 | 
			
		||||
                      code == KeyCode.PAGE_DOWN ||
 | 
			
		||||
                      code == KeyCode.PAGE_UP ||
 | 
			
		||||
                      code == KeyCode.RIGHT ||
 | 
			
		||||
                      code == KeyCode.UP)) {
 | 
			
		||||
                    event.consume();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (event.getEventType() == KeyEvent.KEY_PRESSED &&
 | 
			
		||||
                    (code == KeyCode.BACK_SPACE ||
 | 
			
		||||
                     code == KeyCode.DELETE)) {
 | 
			
		||||
 | 
			
		||||
                    String newText = prefixField.getText();
 | 
			
		||||
                    if (code == KeyCode.BACK_SPACE) {
 | 
			
		||||
                        newText = (newText.substring(0, cursorPosition - 1) + newText.substring(cursorPosition)).replaceAll(" ", "");
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (code == KeyCode.DELETE) {
 | 
			
		||||
                        newText = (newText.substring(0, cursorPosition) + newText.substring(cursorPosition + 1)).replaceAll(" ", "");
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    StringBuilder sb = new StringBuilder();
 | 
			
		||||
 | 
			
		||||
                    for (int i = 0; i < newText.length(); i++) {
 | 
			
		||||
                        sb.append(newText.charAt(i));
 | 
			
		||||
                        if ((i + 1) % (digitsPerGroup) == 0) {
 | 
			
		||||
                            sb.append(' ');
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    prefixField.setText(sb.toString());
 | 
			
		||||
                    if (code == KeyCode.BACK_SPACE) {
 | 
			
		||||
                        prefixField.positionCaret(cursorPosition - 1);
 | 
			
		||||
                    } else if (code == KeyCode.DELETE) {
 | 
			
		||||
                        prefixField.positionCaret(cursorPosition);
 | 
			
		||||
                    }
 | 
			
		||||
                 }
 | 
			
		||||
 | 
			
		||||
                if (event.getEventType() == KeyEvent.KEY_PRESSED &&
 | 
			
		||||
                    (code == KeyCode.DIGIT0 ||
 | 
			
		||||
                     code == KeyCode.DIGIT1 ||
 | 
			
		||||
                     code == KeyCode.DIGIT2 ||
 | 
			
		||||
                     code == KeyCode.DIGIT3 ||
 | 
			
		||||
                     code == KeyCode.DIGIT4 ||
 | 
			
		||||
                     code == KeyCode.DIGIT5 ||
 | 
			
		||||
                     code == KeyCode.DIGIT6 ||
 | 
			
		||||
                     code == KeyCode.DIGIT7 ||
 | 
			
		||||
                     code == KeyCode.DIGIT8 ||
 | 
			
		||||
                     code == KeyCode.DIGIT9)) {
 | 
			
		||||
 | 
			
		||||
                    String newText = prefixField.getText().substring(0, cursorPosition) + str + prefixField.getText().substring(cursorPosition);
 | 
			
		||||
                    newText = newText.replaceAll(" ", "");
 | 
			
		||||
 | 
			
		||||
                    StringBuilder sb = new StringBuilder();
 | 
			
		||||
 | 
			
		||||
                    for (int i = 0; i < newText.length(); i++) {
 | 
			
		||||
                        sb.append(newText.charAt(i));
 | 
			
		||||
                        if ((i + 1) % (digitsPerGroup) == 0) {
 | 
			
		||||
                            sb.append(' ');
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    prefixField.setText(sb.toString());
 | 
			
		||||
                    if (prefixField.getText().charAt(cursorPosition) == ' ') {
 | 
			
		||||
                        cursorPosition++;
 | 
			
		||||
                    }
 | 
			
		||||
                    prefixField.positionCaret(cursorPosition + 1);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void handleOkButtonPress() {
 | 
			
		||||
            String prefix = prefixField.getText();
 | 
			
		||||
            if (prefix != null && !prefix.isEmpty()) {
 | 
			
		||||
                mainSettingsController.addPrefix(prefix.replaceAll(" ", ""));
 | 
			
		||||
                closeWindow();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void handleCancelButtonPress() {
 | 
			
		||||
            closeWindow();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void closeWindow() {
 | 
			
		||||
            Stage stage = (Stage) okButton.getScene().getWindow();
 | 
			
		||||
            stage.close();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -0,0 +1,20 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
 | 
			
		||||
<?import javafx.scene.control.Button?>
 | 
			
		||||
<?import javafx.scene.control.Label?>
 | 
			
		||||
<?import javafx.scene.control.TextField?>
 | 
			
		||||
<?import javafx.scene.layout.AnchorPane?>
 | 
			
		||||
<?import javafx.scene.layout.VBox?>
 | 
			
		||||
 | 
			
		||||
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="92.0" prefWidth="312.0" xmlns="http://javafx.com/javafx/23.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="name.nathanmcrae.numbersstation.AddPrefixController">
 | 
			
		||||
   <children>
 | 
			
		||||
      <AnchorPane prefHeight="200.0" prefWidth="312.0">
 | 
			
		||||
         <children>
 | 
			
		||||
            <Button fx:id="okButton" layoutX="89.0" layoutY="67.0" mnemonicParsing="false" prefHeight="25.0" prefWidth="65.0" text="OK" AnchorPane.bottomAnchor="15.0" AnchorPane.rightAnchor="89.0" />
 | 
			
		||||
            <Button fx:id="cancelButton" layoutX="169.0" layoutY="67.0" mnemonicParsing="false" prefHeight="25.0" prefWidth="65.0" text="Cancel" AnchorPane.bottomAnchor="15.0" AnchorPane.rightAnchor="9.0" />
 | 
			
		||||
            <Label layoutX="14.0" layoutY="14.0" text="Enter a message prefix / identifier:" />
 | 
			
		||||
            <TextField fx:id="prefixField" layoutX="203.0" layoutY="10.0" prefHeight="25.0" prefWidth="105.0" AnchorPane.leftAnchor="203.0" AnchorPane.rightAnchor="10.0" />
 | 
			
		||||
         </children>
 | 
			
		||||
      </AnchorPane>
 | 
			
		||||
   </children>
 | 
			
		||||
</VBox>
 | 
			
		||||
@@ -21,8 +21,10 @@ import javafx.collections.FXCollections;
 | 
			
		||||
import javafx.collections.ObservableList;
 | 
			
		||||
import javafx.event.Event;
 | 
			
		||||
import javafx.fxml.FXML;
 | 
			
		||||
import javafx.fxml.FXMLLoader;
 | 
			
		||||
import javafx.scene.control.CheckBox;
 | 
			
		||||
import javafx.scene.control.DatePicker;
 | 
			
		||||
import javafx.scene.control.ListCell;
 | 
			
		||||
import javafx.scene.control.ListView;
 | 
			
		||||
import javafx.scene.control.RadioButton;
 | 
			
		||||
import javafx.scene.control.Spinner;
 | 
			
		||||
@@ -33,7 +35,11 @@ import javafx.scene.control.ToggleGroup;
 | 
			
		||||
import javafx.scene.input.KeyEvent;
 | 
			
		||||
import javafx.scene.input.KeyCode;
 | 
			
		||||
import javafx.scene.Node;
 | 
			
		||||
import javafx.scene.Parent;
 | 
			
		||||
import javafx.scene.Scene;
 | 
			
		||||
import javafx.stage.Modality;
 | 
			
		||||
import javafx.stage.Stage;
 | 
			
		||||
import javafx.util.Callback;
 | 
			
		||||
 | 
			
		||||
public class MainSettingsController {
 | 
			
		||||
    private IntegerProperty digitsPerGroup = new SimpleIntegerProperty();
 | 
			
		||||
@@ -278,19 +284,59 @@ public class MainSettingsController {
 | 
			
		||||
                stage.setUserData(false);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        prefixListView.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public ListCell<String> call(ListView<String> listView) {
 | 
			
		||||
                return new ListCell<String>() {
 | 
			
		||||
                    @Override
 | 
			
		||||
                    protected void updateItem(String item, boolean empty) {
 | 
			
		||||
                        super.updateItem(item, empty);
 | 
			
		||||
                        if (empty || item == null) {
 | 
			
		||||
                            setText(null);
 | 
			
		||||
                        } else {
 | 
			
		||||
 | 
			
		||||
                            String newText = item.replaceAll(" ", "");
 | 
			
		||||
                            StringBuilder sb = new StringBuilder();
 | 
			
		||||
 | 
			
		||||
                            for (int i = 0; i < newText.length(); i++) {
 | 
			
		||||
                                sb.append(newText.charAt(i));
 | 
			
		||||
                                if ((i + 1) % (digitsPerGroup.get()) == 0) {
 | 
			
		||||
                                    sb.append(' ');
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                            setText(sb.toString());
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @FXML
 | 
			
		||||
    private void handleAddPrefixButtonPress() {
 | 
			
		||||
        TextInputDialog dialog = new TextInputDialog();
 | 
			
		||||
        dialog.setTitle("New prefix");
 | 
			
		||||
        dialog.setHeaderText("Add a new prefix");
 | 
			
		||||
        dialog.setContentText("Enter a message prefix / identifier:");
 | 
			
		||||
        try {
 | 
			
		||||
            FXMLLoader loader = new FXMLLoader(getClass().getResource("AddPrefixView.fxml"));
 | 
			
		||||
            Parent root = loader.load();
 | 
			
		||||
 | 
			
		||||
        Optional<String> result = dialog.showAndWait();
 | 
			
		||||
        result.ifPresent(prefix -> {
 | 
			
		||||
            AddPrefixController controller = loader.getController();
 | 
			
		||||
            controller.setMainSettingsController(this);
 | 
			
		||||
            controller.setDigitsPerGroup(settings.getDigitsPerGroup());
 | 
			
		||||
 | 
			
		||||
            Stage stage = new Stage();
 | 
			
		||||
            stage.setTitle("New prefix");
 | 
			
		||||
            stage.setScene(new Scene(root));
 | 
			
		||||
            stage.initModality(Modality.APPLICATION_MODAL);
 | 
			
		||||
            stage.showAndWait();
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void addPrefix(String prefix) {
 | 
			
		||||
        if (!(prefix == null || prefix.isEmpty())) {
 | 
			
		||||
            prefixListView.getItems().add(prefix);
 | 
			
		||||
        });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @FXML
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user