Skip to content

Commit

Permalink
Update HistoryManager handling and refactor code
Browse files Browse the repository at this point in the history
Refactored the handling of HistoryManager across several classes for better encapsulation and flexibility. Also, updated 'UIUtil.java', replacing Node parameter with Styleable in all utility methods to handle a wider range of JavaFX styleable components. Lastly, added a 'set' method in the HistoryManager interface and implementations to allow setting a new history list.
  • Loading branch information
leewyatt committed May 27, 2024
1 parent 5a1ca08 commit 239019e
Show file tree
Hide file tree
Showing 12 changed files with 403 additions and 258 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,21 @@ public void start(Stage primaryStage) throws Exception {

private Node basicDemo() {
TextField textField = new TextField();

HistoryButton<String> historyButton = new HistoryButton<>(textField);

// Tips: We can set the delimiter and preferencesKey when creating, otherwise use the default value.
// StringHistoryManager historyManager = new StringHistoryManager(";", "history-records",
// Preferences.userNodeForPackage(HistoryManagerApp.class).node("simpleTextField"));

StringHistoryManager historyManager = new StringHistoryManager();

// Tips: If we want to persist the history after the application restarts, we need to set the preferences.
// historyManager.setPreferences(Preferences.userNodeForPackage(HistoryManagerApp.class).node("simpleTextField"));

HistoryButton<String> historyButton = new HistoryButton<>(textField, historyManager);
// Tips: If we want to enable the history function, we need to set the history manager.
historyButton.setHistoryManager(historyManager);

historyButton.setConfigureHistoryPopup(historyPopup -> {
// When choosing a history item, replace the text in the text field.
historyPopup.setOnHistoryItemConfirmed(item -> {
Expand Down Expand Up @@ -108,7 +119,8 @@ private Node advancedDemo() {
historyManager.set(List.of("One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"));
}

HistoryButton<String> historyButton = new HistoryButton<>(textField, historyManager);
HistoryButton<String> historyButton = new HistoryButton<>(textField);
historyButton.setHistoryManager(historyManager);

// add history item to the history when the enter key is pressed.
textField.setOnKeyPressed(e -> {
Expand Down Expand Up @@ -214,7 +226,8 @@ public Student fromString(String string) {

historyManager.setPreferences(Preferences.userNodeForPackage(HistoryManagerApp.class).node("list"));

HistoryButton<Student> historyButton = new HistoryButton<>(null, historyManager);
HistoryButton<Student> historyButton = new HistoryButton<>(null);
historyButton.setHistoryManager(historyManager);
historyButton.setText("History");

historyButton.setConfigureHistoryPopup(historyPopup -> {
Expand Down
51 changes: 48 additions & 3 deletions gemsfx-demo/src/main/java/com/dlsc/gemsfx/demo/SearchFieldApp.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package com.dlsc.gemsfx.demo;

import com.dlsc.gemsfx.SearchField;
import com.dlsc.gemsfx.util.HistoryManager;
import com.dlsc.gemsfx.util.StringHistoryManager;
import fr.brouillard.oss.cssfx.CSSFX;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.Separator;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
Expand All @@ -21,8 +24,15 @@
import java.util.prefs.Preferences;
import java.util.stream.Collectors;

/**
* This demo shows how to use the {@link SearchField} control.
* <p>
* About the HistoryManager, you can refer to: {@link HistoryManager} {@link SearchTextFieldApp}, {@link HistoryManagerApp}
*/
public class SearchFieldApp extends Application {

private StringHistoryManager historyManager;

private final List<Country> countries = new ArrayList<>();

@Override
Expand Down Expand Up @@ -81,10 +91,45 @@ public void start(Stage primaryStage) throws Exception {
CheckBox autoCommitOnFocusLostBox = new CheckBox("Auto commit on field lost focus.");
autoCommitOnFocusLostBox.selectedProperty().bindBidirectional(field.autoCommitOnFocusLostProperty());

CheckBox enableHistoryBox = new CheckBox("Enable History");
enableHistoryBox.selectedProperty().addListener((obs, oldVal, newVal) -> {
if (newVal) {
if (field.getHistoryManager() == null) {
historyManager = new StringHistoryManager(Preferences.userNodeForPackage(SearchFieldApp.class).node("field"));
// Optional: Set the maximum history size. default is 30.
historyManager.setMaxHistorySize(20);
// Optional: If the history items is empty, we can set a default history list.
if (historyManager.getAll().isEmpty()) {
historyManager.set(List.of("United Kingdom", "Switzerland"));
}
}
// If the history manager is not null, the search field will have a history feature.
field.setHistoryManager(historyManager);
} else {
// If the history manager is null, the search field will not have a history feature.
field.setHistoryManager(null);
}
primaryStage.sizeToScene();
});
enableHistoryBox.setSelected(true);

CheckBox addHistoryOnActionBox = new CheckBox("Add History on Enter");
addHistoryOnActionBox.setSelected(true);
field.addingItemToHistoryOnEnterProperty().bind(addHistoryOnActionBox.selectedProperty());

CheckBox addHistoryOnFocusLossBox = new CheckBox("Add History on Focus Loss");
addHistoryOnFocusLossBox.setSelected(true);
field.addingItemToHistoryOnFocusLostProperty().bind(addHistoryOnFocusLossBox.selectedProperty());

VBox historyControls = new VBox(10, new Separator(), addHistoryOnActionBox, addHistoryOnFocusLossBox);
historyControls.managedProperty().bind(enableHistoryBox.selectedProperty());
historyControls.visibleProperty().bind(enableHistoryBox.selectedProperty());

field.leftProperty().bind(Bindings.createObjectBinding(() -> showLeftRightNodes.isSelected() ? regionLeft : null, showLeftRightNodes.selectedProperty()));
field.rightProperty().bind(Bindings.createObjectBinding(() -> showLeftRightNodes.isSelected() ? regionRight : null, showLeftRightNodes.selectedProperty()));

VBox vbox = new VBox(20, createNewItemBox, showPromptText, usePlaceholder, hideWithSingleChoiceBox, hideWithNoChoiceBox, showSearchIconBox, showLeftRightNodes, autoCommitOnFocusLostBox, hBox, hBox2, field);
VBox vbox = new VBox(20, createNewItemBox, showPromptText, usePlaceholder, hideWithSingleChoiceBox, hideWithNoChoiceBox, showSearchIconBox, showLeftRightNodes,
autoCommitOnFocusLostBox, hBox, hBox2, enableHistoryBox, historyControls, field);
vbox.setPadding(new Insets(20));

Scene scene = new Scene(vbox);
Expand Down Expand Up @@ -123,8 +168,8 @@ public Country fromString(String string) {
setMatcher((broker, searchText) -> broker.getName().toLowerCase().startsWith(searchText.toLowerCase()));
setComparator(Comparator.comparing(Country::getName));
getEditor().setPromptText("Start typing country name ...");
// If not setPreferences() history records are only stored temporarily in memory and are not persisted locally.
getHistoryManager().setPreferences(Preferences.userNodeForPackage(SearchFieldApp.class).node("field"));
// Tips: If we don't set a HistoryManager, the search field will not have a history feature.
// setHistoryManager(new StringHistoryManager(Preferences.userNodeForPackage(SearchFieldApp.class).node("field")));
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package com.dlsc.gemsfx.demo;

import com.dlsc.gemsfx.SearchTextField;
import com.dlsc.gemsfx.Spacer;
import com.dlsc.gemsfx.util.HistoryManager;
import com.dlsc.gemsfx.util.StringHistoryManager;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
Expand All @@ -18,72 +19,85 @@

import java.time.LocalTime;
import java.util.List;
import java.util.Optional;
import java.util.prefs.Preferences;

public class SearchTextFieldApp extends Application {

private StringHistoryManager stringHistoryManager;

@Override
public void start(Stage primaryStage) throws Exception {

SearchTextField field1 = new SearchTextField();
StringHistoryManager historyManager1 = field1.getHistoryManager();
historyManager1.setPreferences(Preferences.userNodeForPackage(SearchTextFieldApp.class).node("field1"));

SearchTextField field2 = new SearchTextField(true);
StringHistoryManager historyManager2 = field2.getHistoryManager();
historyManager2.setPreferences(Preferences.userNodeForPackage(SearchTextFieldApp.class).node("field2"));
SearchTextField field = new SearchTextField();

CheckBox roundBox = new CheckBox("Round");
field.roundProperty().bind(roundBox.selectedProperty());

CheckBox enableHistoryBox = new CheckBox("Enable History");
enableHistoryBox.selectedProperty().addListener((obs, oldVal, newVal) -> {
if (newVal) {
if (stringHistoryManager == null) {
Preferences preferences = Preferences.userNodeForPackage(SearchTextFieldApp.class).node("field1");
stringHistoryManager = new StringHistoryManager(preferences);
}
field.setHistoryManager(stringHistoryManager);
} else {
field.setHistoryManager(null);
}
primaryStage.sizeToScene();
});
enableHistoryBox.setSelected(true);

Label label = new Label("Max History Size:");
Spinner<Integer> maxHistorySizeSpinner = new Spinner<>(5, 50, 10, 5);
historyManager1.maxHistorySizeProperty().bind(maxHistorySizeSpinner.valueProperty());
historyManager2.maxHistorySizeProperty().bind(maxHistorySizeSpinner.valueProperty());
maxHistorySizeSpinner.setMaxWidth(Double.MAX_VALUE);
HBox maxHistorySizeBox = new HBox(5, label, maxHistorySizeSpinner);
maxHistorySizeBox.setAlignment(Pos.CENTER_LEFT);
Spinner<Integer> maxHistorySizeSpinner = new Spinner<>(5, 50, 30, 5);
maxHistorySizeSpinner.valueProperty().addListener((obs, oldVal, newVal) -> {
HistoryManager<String> historyManager = field.getHistoryManager();
if (newVal != null && historyManager != null) {
historyManager.setMaxHistorySize(newVal);
}
});

CheckBox enableHistoryPopupBox = new CheckBox("Enable History Popup");
enableHistoryPopupBox.setSelected(true);
field1.enableHistoryPopupProperty().bindBidirectional(enableHistoryPopupBox.selectedProperty());
field2.enableHistoryPopupProperty().bindBidirectional(enableHistoryPopupBox.selectedProperty());
maxHistorySizeSpinner.setMaxWidth(140);
HBox maxHistorySizeBox = new HBox(5, label, new Spacer(), maxHistorySizeSpinner);
maxHistorySizeBox.setAlignment(Pos.CENTER_LEFT);

CheckBox addHistoryOnActionBox = new CheckBox("Add History on Enter");
addHistoryOnActionBox.setSelected(true);
field1.addingItemToHistoryOnEnterProperty().bind(addHistoryOnActionBox.selectedProperty());
field2.addingItemToHistoryOnEnterProperty().bind(addHistoryOnActionBox.selectedProperty());
field.addingItemToHistoryOnEnterProperty().bind(addHistoryOnActionBox.selectedProperty());

CheckBox addHistoryOnFocusLossBox = new CheckBox("Add History on Focus Loss");
addHistoryOnFocusLossBox.setSelected(true);
field1.addingItemToHistoryOnFocusLostProperty().bind(addHistoryOnFocusLossBox.selectedProperty());
field2.addingItemToHistoryOnFocusLostProperty().bind(addHistoryOnFocusLossBox.selectedProperty());
field.addingItemToHistoryOnFocusLostProperty().bind(addHistoryOnFocusLossBox.selectedProperty());

Button setHistoryButton = new Button("Set History");
setHistoryButton.setMaxWidth(Double.MAX_VALUE);
setHistoryButton.setOnAction(e -> {
List<String> list = List.of("One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten");
historyManager1.set(list);
historyManager2.set(list);
Optional.ofNullable(field.getHistoryManager()).ifPresent(historyManager -> {
historyManager.set(list);
System.out.println("History set to: " + list);
});
});

Button addHistoryButton = new Button("Add History");
addHistoryButton.setMaxWidth(Double.MAX_VALUE);
addHistoryButton.setOnAction(e -> {
historyManager1.add("New " + LocalTime.now());
historyManager2.add("New" + LocalTime.now());
});
addHistoryButton.setOnAction(e -> Optional.ofNullable(field.getHistoryManager()).ifPresent(historyManager -> historyManager.add("New " + LocalTime.now())));

Button removeStandardHistoryButton = createRemoveHistoryButton("Standard Field Remove First History Item", historyManager1);
Button removeRoundHistoryButton = createRemoveHistoryButton("Round Field Remove First History Item", historyManager2);
Button removeHistoryButton = new Button("Remove First History Item");
removeHistoryButton.setMaxWidth(Double.MAX_VALUE);
removeHistoryButton.setOnAction(e -> Optional.ofNullable(field.getHistoryManager()).ifPresent(historyManager -> historyManager.remove(historyManager.getAll().get(0))));

Button clearButton = new Button("Clear History");
clearButton.setMaxWidth(Double.MAX_VALUE);
clearButton.setOnAction(e -> {
historyManager1.clear();
historyManager2.clear();
});
clearButton.setOnAction(e -> Optional.ofNullable(field.getHistoryManager()).ifPresent(HistoryManager::clear));

VBox historyControls = new VBox(5, new Separator(), maxHistorySizeBox, addHistoryOnActionBox, addHistoryOnFocusLossBox,
setHistoryButton, addHistoryButton, clearButton);
historyControls.managedProperty().bind(enableHistoryBox.selectedProperty());
historyControls.visibleProperty().bind(enableHistoryBox.selectedProperty());

VBox vbox = new VBox(20, new Label("Standard"), field1, new Label("Round"), field2,
new Separator(), maxHistorySizeBox, enableHistoryPopupBox, addHistoryOnActionBox, addHistoryOnFocusLossBox,
setHistoryButton, addHistoryButton, removeStandardHistoryButton, removeRoundHistoryButton, clearButton);
VBox vbox = new VBox(20, new Label("Standard"), field, roundBox, enableHistoryBox, historyControls);
vbox.setPadding(new Insets(20));

Scene scene = new Scene(vbox);
Expand All @@ -94,14 +108,6 @@ public void start(Stage primaryStage) throws Exception {
primaryStage.show();
}

private Button createRemoveHistoryButton(String text, StringHistoryManager historyManager) {
Button removeHistoryButton2 = new Button(text);
removeHistoryButton2.disableProperty().bind(Bindings.createObjectBinding(() -> historyManager.getAll().isEmpty(), historyManager.getAll()));
removeHistoryButton2.setMaxWidth(Double.MAX_VALUE);
removeHistoryButton2.setOnAction(e -> historyManager.remove(historyManager.getAll().get(0)));
return removeHistoryButton2;
}

public static void main(String[] args) {
launch(args);
}
Expand Down
Loading

0 comments on commit 239019e

Please sign in to comment.