From 9d4ed88e3d64065630c3e645c2b7b8c56b94128b Mon Sep 17 00:00:00 2001 From: Dirk Lemmermann Date: Thu, 30 May 2024 17:26:18 +0200 Subject: [PATCH] Various changes, especially related to the history manager. --- .../dlsc/gemsfx/demo/HistoryManagerApp.java | 70 +++-- .../com/dlsc/gemsfx/demo/SearchFieldApp.java | 4 +- .../dlsc/gemsfx/demo/SearchTextFieldApp.java | 6 +- .../java/com/dlsc/gemsfx/HistoryButton.java | 7 +- .../com/dlsc/gemsfx/util/HistoryManager.java | 175 +++++++++---- .../gemsfx/util/InMemoryHistoryManager.java | 18 ++ .../util/PreferencesHistoryManager.java | 246 ++---------------- .../gemsfx/util/StringHistoryManager.java | 26 +- .../com/dlsc/gemsfx/history-button.css | 6 +- 9 files changed, 208 insertions(+), 350 deletions(-) create mode 100644 gemsfx/src/main/java/com/dlsc/gemsfx/util/InMemoryHistoryManager.java diff --git a/gemsfx-demo/src/main/java/com/dlsc/gemsfx/demo/HistoryManagerApp.java b/gemsfx-demo/src/main/java/com/dlsc/gemsfx/demo/HistoryManagerApp.java index 2ce292d4..73c43375 100644 --- a/gemsfx-demo/src/main/java/com/dlsc/gemsfx/demo/HistoryManagerApp.java +++ b/gemsfx-demo/src/main/java/com/dlsc/gemsfx/demo/HistoryManagerApp.java @@ -3,6 +3,7 @@ import com.dlsc.gemsfx.HistoryButton; import com.dlsc.gemsfx.Spacer; import com.dlsc.gemsfx.util.HistoryManager; +import com.dlsc.gemsfx.util.InMemoryHistoryManager; import com.dlsc.gemsfx.util.PreferencesHistoryManager; import com.dlsc.gemsfx.util.StringHistoryManager; import javafx.application.Application; @@ -36,9 +37,9 @@ public void start(Stage primaryStage) throws Exception { TabPane tabPane = new TabPane(); tabPane.setTabClosingPolicy(TabPane.TabClosingPolicy.UNAVAILABLE); tabPane.getTabs().addAll( - new Tab("Basic", basicDemo()), - new Tab("Advanced", advancedDemo()), - new Tab("Other", otherDemo()) + new Tab("In-Memory History Manager", inMemoryDemmo()), + new Tab("String History Manager", stringHistoryDemo()), + new Tab("Preferences History Manager)", prefsDemo()) ); primaryStage.setScene(new Scene(tabPane, 800, 600)); @@ -46,22 +47,14 @@ public void start(Stage primaryStage) throws Exception { primaryStage.show(); } - private Node basicDemo() { + private Node inMemoryDemmo() { TextField textField = new TextField(); HistoryButton 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")); - - // Tips: If we want to enable the history function, we need to set the history manager. + InMemoryHistoryManager historyManager = new InMemoryHistoryManager<>(); historyButton.setHistoryManager(historyManager); + historyButton.setOnItemSelected(item -> { historyButton.hidePopup(); textField.setText(item); @@ -92,19 +85,14 @@ private Node basicDemo() { /** * Creates a text field with a history button. */ - private Node advancedDemo() { + private Node stringHistoryDemo() { TextField textField = new TextField(); - StringHistoryManager historyManager = new StringHistoryManager(); - // Tips: You can set the delimiter and preferencesKey when creating, otherwise use the default value. - // PreferencesHistoryManager historyManager = new PreferencesHistoryManager(";", "save-items"); - - // Tips: If you want to persist the history after the application restarts, Please set the preferences. - historyManager.setPreferences(Preferences.userNodeForPackage(HistoryManagerApp.class).node("textField")); - // Optional: Set the maximum history size.default is 30. + StringHistoryManager historyManager = new StringHistoryManager(Preferences.userNodeForPackage(HistoryManagerApp.class), "advanced-demo"); historyManager.setMaxHistorySize(10); + // Optional: if the history is empty, set some default values - if (historyManager.getAll().isEmpty()) { + if (historyManager.getAllUnmodifiable().isEmpty()) { historyManager.set(List.of("One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten")); } @@ -128,7 +116,7 @@ private Node advancedDemo() { historyButton.hidePopup(); }); clearAll.managedProperty().bind(clearAll.visibleProperty()); - clearAll.visibleProperty().bind(Bindings.isNotEmpty(historyManager.getAll())); + clearAll.visibleProperty().bind(Bindings.isNotEmpty(historyManager.getAllUnmodifiable())); leftBox.getChildren().addAll(group, new Spacer(), clearAll); leftBox.setAlignment(Pos.CENTER); @@ -162,7 +150,7 @@ private Node advancedDemo() { /** * Creates a list view with a history button. */ - private Node otherDemo() { + private Node prefsDemo() { ListView listView = new ListView<>(); listView.getItems().addAll( new Student("John", 90), @@ -177,20 +165,22 @@ private Node otherDemo() { new Student("David", 83) ); - PreferencesHistoryManager historyManager = new PreferencesHistoryManager<>( - new StringConverter<>() { - @Override - public String toString(Student object) { - return object.name() + " : " + object.score(); - } - - @Override - public Student fromString(String string) { - String[] parts = string.split(" : "); - return new Student(parts[0], Integer.parseInt(parts[1])); - } - } - ); + StringConverter converter = new StringConverter<>() { + @Override + public String toString(Student object) { + return object.name() + " : " + object.score(); + } + + @Override + public Student fromString(String string) { + String[] parts = string.split(" : "); + return new Student(parts[0], Integer.parseInt(parts[1])); + } + }; + + Preferences preferences = Preferences.userNodeForPackage(HistoryManagerApp.class); + + PreferencesHistoryManager historyManager = new PreferencesHistoryManager<>(preferences, "list", converter); listView.setOnMouseClicked(e -> { if (e.getClickCount() == 2) { @@ -198,8 +188,6 @@ public Student fromString(String string) { } }); - historyManager.setPreferences(Preferences.userNodeForPackage(HistoryManagerApp.class).node("list")); - HistoryButton historyButton = new HistoryButton<>(); historyButton.setHistoryManager(historyManager); historyButton.setText("History"); diff --git a/gemsfx-demo/src/main/java/com/dlsc/gemsfx/demo/SearchFieldApp.java b/gemsfx-demo/src/main/java/com/dlsc/gemsfx/demo/SearchFieldApp.java index aae33573..b91a7e9c 100644 --- a/gemsfx-demo/src/main/java/com/dlsc/gemsfx/demo/SearchFieldApp.java +++ b/gemsfx-demo/src/main/java/com/dlsc/gemsfx/demo/SearchFieldApp.java @@ -95,11 +95,11 @@ public void start(Stage primaryStage) throws Exception { enableHistoryBox.selectedProperty().addListener((obs, oldVal, newVal) -> { if (newVal) { if (field.getHistoryManager() == null) { - historyManager = new StringHistoryManager(Preferences.userNodeForPackage(SearchFieldApp.class).node("field")); + historyManager = new StringHistoryManager(Preferences.userNodeForPackage(SearchFieldApp.class), "search-field-id"); // 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()) { + if (historyManager.getAllUnmodifiable().isEmpty()) { historyManager.set(List.of("United Kingdom", "Switzerland")); } } diff --git a/gemsfx-demo/src/main/java/com/dlsc/gemsfx/demo/SearchTextFieldApp.java b/gemsfx-demo/src/main/java/com/dlsc/gemsfx/demo/SearchTextFieldApp.java index c57bac2c..761eff6f 100644 --- a/gemsfx-demo/src/main/java/com/dlsc/gemsfx/demo/SearchTextFieldApp.java +++ b/gemsfx-demo/src/main/java/com/dlsc/gemsfx/demo/SearchTextFieldApp.java @@ -38,8 +38,8 @@ public void start(Stage primaryStage) throws Exception { enableHistoryBox.selectedProperty().addListener((obs, oldVal, newVal) -> { if (newVal) { if (stringHistoryManager == null) { - Preferences preferences = Preferences.userNodeForPackage(SearchTextFieldApp.class).node("field1"); - stringHistoryManager = new StringHistoryManager(preferences); + Preferences preferences = Preferences.userNodeForPackage(SearchTextFieldApp.class); + stringHistoryManager = new StringHistoryManager(preferences, "search-text-field-id"); } field.setHistoryManager(stringHistoryManager); } else { @@ -86,7 +86,7 @@ public void start(Stage primaryStage) throws Exception { 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)))); + removeHistoryButton.setOnAction(e -> Optional.ofNullable(field.getHistoryManager()).ifPresent(historyManager -> historyManager.remove(historyManager.getAllUnmodifiable().get(0)))); Button clearButton = new Button("Clear History"); clearButton.setMaxWidth(Double.MAX_VALUE); diff --git a/gemsfx/src/main/java/com/dlsc/gemsfx/HistoryButton.java b/gemsfx/src/main/java/com/dlsc/gemsfx/HistoryButton.java index 5e4f74fb..ee7f747c 100644 --- a/gemsfx/src/main/java/com/dlsc/gemsfx/HistoryButton.java +++ b/gemsfx/src/main/java/com/dlsc/gemsfx/HistoryButton.java @@ -1,6 +1,7 @@ package com.dlsc.gemsfx; import com.dlsc.gemsfx.util.HistoryManager; +import javafx.application.Platform; import javafx.beans.binding.Bindings; import javafx.beans.property.*; import javafx.css.PseudoClass; @@ -392,15 +393,15 @@ private ListView createListView() { HistoryManager historyManager = getHistoryManager(); if (historyManager != null) { - Bindings.bindContent(listView.getItems(), historyManager.getAll()); + Bindings.bindContent(listView.getItems(), historyManager.getAllUnmodifiable()); } historyManagerProperty().addListener((observable, oldManager, newManager) -> { if (oldManager != null) { - Bindings.unbindContent(listView.getItems(), oldManager.getAll()); + Bindings.unbindContent(listView.getItems(), oldManager.getAllUnmodifiable()); } if (newManager != null) { - Bindings.bindContent(listView.getItems(), newManager.getAll()); + Bindings.bindContent(listView.getItems(), newManager.getAllUnmodifiable()); } }); diff --git a/gemsfx/src/main/java/com/dlsc/gemsfx/util/HistoryManager.java b/gemsfx/src/main/java/com/dlsc/gemsfx/util/HistoryManager.java index 37a622ad..f9eda503 100644 --- a/gemsfx/src/main/java/com/dlsc/gemsfx/util/HistoryManager.java +++ b/gemsfx/src/main/java/com/dlsc/gemsfx/util/HistoryManager.java @@ -1,114 +1,179 @@ package com.dlsc.gemsfx.util; +import javafx.beans.Observable; import javafx.beans.property.IntegerProperty; import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleIntegerProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.collections.FXCollections; import javafx.collections.ObservableList; import java.util.List; +import java.util.Objects; import java.util.function.Predicate; +import java.util.logging.Logger; /** - * The HistoryManager interface defines the standard operations to manage history storage + * The HistoryManager class defines the standard operations to manage history storage * for any type of items, allowing for implementation of various data storage mechanisms. * * @param the type of items stored in the history */ -public interface HistoryManager { +public abstract class HistoryManager { - /** - * Adds a single item to the history storage. - * If the item already exists, its position is updated. - * - * @param item The history item to be added. - */ - void add(T item); + private static final Logger LOG = Logger.getLogger(HistoryManager.class.getName()); - /** - * Adds multiple items to the history storage. - * Duplicates in the input list are not added twice. - * - * @param items The list of history items to be added. - */ - void add(List items); + private static final int DEFAULT_MAX_HISTORY_SIZE = 30; + + private final ObservableList history = FXCollections.observableArrayList(); + + public HistoryManager() { + maxHistorySizeProperty().addListener(it -> { + // Check if the max history size is negative. If so, log a warning. + if (getMaxHistorySize() < 0) { + LOG.warning("Max history size must be greater than or equal to 0. "); + } + trimHistory(); + }); + + unmodifiableHistory.addListener((Observable it) -> storeHistory()); + } + + protected abstract void loadHistory(); + + protected abstract void storeHistory(); /** - * Sets the history of the HistoryManager with the provided list of items. + * Sets the history of the HistoryManager with the provided list of strings. * The method ensures that duplicates are removed from the list. * - * @param items the list of items representing the history + * @param history the list of strings representing the history */ - void set(List items); + public final void set(List history) { + this.history.setAll(convertToUniqueList(history)); + } /** - * Removes a single item from the history storage. + * Adds the given item to the history. The method ensures that duplicates will not be added. * - * @param item The history item to be removed. - * @return true if the item was successfully removed, false if the item was not found. + * @param item the item to add */ - boolean remove(T item); + public final void add(T item) { + if (item != null && getFilter().test(item)) { + history.remove(item); + history.add(0, item); + trimHistory(); + } + } /** - * Removes multiple items from the history storage. + * Adds the given items to the history. * - * @param items The list of history items to be removed. + * @param items the items to add */ - void remove(List items); + public final void add(List items) { + List uniqueItems = convertToUniqueList(items); + if (!uniqueItems.isEmpty()) { + history.removeAll(uniqueItems); + history.addAll(0, uniqueItems); + trimHistory(); + } + } /** - * Clears all items from the history storage. + * Removes the given item from the history. + * + * @param item the item to remove + * @return true if the item was removed, false otherwise */ - void clear(); + public final boolean remove(T item) { + return history.remove(item); + } /** - * Retrieves all stored history items. + * Removes the given items from the history. * - * @return A list of all history items. + * @param items the items to remove */ - ObservableList getAll(); + public final void remove(List items) { + history.removeAll(items); + } /** - * Returns the property object for the maximum history size. This property can be - * used to bind the history size limit to UI components or to observe changes. - * - * @return The IntegerProperty representing the maximum number of history items allowed. + * Clears the history. */ - IntegerProperty maxHistorySizeProperty(); + public final void clear() { + history.clear(); + } + + private final ObservableList unmodifiableHistory = FXCollections.unmodifiableObservableList(history); /** - * Gets the current maximum size of the history list. - * - * @return The current maximum number of items that can be stored in the history. + * Returns an unmodifiable list of the history. */ - int getMaxHistorySize(); + public final ObservableList getAllUnmodifiable() { + return unmodifiableHistory; + } + + private final IntegerProperty maxHistorySize = new SimpleIntegerProperty(this, "maxHistorySize", DEFAULT_MAX_HISTORY_SIZE); /** - * Sets the maximum size of the history list. If the current number of items - * exceeds the specified size, items will be removed from the end of the list. + * The maximum number of items that the history will store. If the number of items exceeds this value, the oldest + * items will be removed. * - * @param maxHistorySize The maximum number of items to retain in the history. + * @return the maximum number of items in the history */ - void setMaxHistorySize(int maxHistorySize); + public final IntegerProperty maxHistorySizeProperty() { + return maxHistorySize; + } + + public final int getMaxHistorySize() { + return maxHistorySize.get(); + } + + public final void setMaxHistorySize(int maxHistorySize) { + maxHistorySizeProperty().set(maxHistorySize); + } + + private final ObjectProperty> filter = new SimpleObjectProperty<>(this, "filter", it -> true); /** - * Returns the property that holds the filter used when adding items to the history. + * Returns the property object for the filter used when adding items to the history. * Only items that pass the filter will be added to the history. * - * @return the property containing the filter + * @return the property object for the filter */ - ObjectProperty> filterProperty(); + public final ObjectProperty> filterProperty() { + return filter; + } + + public final Predicate getFilter() { + return filter.get(); + } + + public final void setFilter(Predicate filter) { + this.filter.set(filter); + } /** - * Sets a filter to be used when adding items to the history. Only items that pass the - * filter will be added to the history. - * - * @param filter The filter to apply. + * Trims the history list to ensure it does not exceed the maximum allowed size. + * If the current history size is greater than the maximum size, the method removes + * the extra elements from the history list. */ - void setFilter(Predicate filter); + private void trimHistory() { + int max = Math.max(0, getMaxHistorySize()); + if (history.size() > max) { + history.remove(max, history.size()); + } + } /** - * Gets the current filter used for adding items to the history. + * Converts a given list of strings to a unique list of strings. Filters out empty strings. * - * @return The current filter. + * @param history the list of strings to convert + * @return the converted unique list of strings */ - Predicate getFilter(); + private List convertToUniqueList(List history) { + return history.stream().distinct().filter(Objects::nonNull).filter(getFilter()).limit(Math.max(0, getMaxHistorySize())).toList(); + } } diff --git a/gemsfx/src/main/java/com/dlsc/gemsfx/util/InMemoryHistoryManager.java b/gemsfx/src/main/java/com/dlsc/gemsfx/util/InMemoryHistoryManager.java new file mode 100644 index 00000000..981638ab --- /dev/null +++ b/gemsfx/src/main/java/com/dlsc/gemsfx/util/InMemoryHistoryManager.java @@ -0,0 +1,18 @@ +package com.dlsc.gemsfx.util; + +/** + * A simple history manager that does not persist its items anywhere. The history will + * always be clear after an application restart. + * + * @param the type of objects to store in the history list + */ +public class InMemoryHistoryManager extends HistoryManager { + + @Override + protected void loadHistory() { + } + + @Override + protected void storeHistory() { + } +} diff --git a/gemsfx/src/main/java/com/dlsc/gemsfx/util/PreferencesHistoryManager.java b/gemsfx/src/main/java/com/dlsc/gemsfx/util/PreferencesHistoryManager.java index 4ae465b0..cb11ec44 100644 --- a/gemsfx/src/main/java/com/dlsc/gemsfx/util/PreferencesHistoryManager.java +++ b/gemsfx/src/main/java/com/dlsc/gemsfx/util/PreferencesHistoryManager.java @@ -1,19 +1,13 @@ package com.dlsc.gemsfx.util; -import javafx.beans.Observable; -import javafx.beans.property.IntegerProperty; import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleObjectProperty; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; import javafx.util.StringConverter; import org.apache.commons.lang3.StringUtils; import java.util.Arrays; import java.util.List; import java.util.Objects; -import java.util.function.Predicate; import java.util.logging.Logger; import java.util.prefs.Preferences; import java.util.stream.Collectors; @@ -37,247 +31,51 @@ * @see HistoryManager * @see StringConverter */ -public class PreferencesHistoryManager implements HistoryManager { +public class PreferencesHistoryManager extends HistoryManager { private static final Logger LOG = Logger.getLogger(PreferencesHistoryManager.class.getName()); - private static final int DEFAULT_MAX_HISTORY_SIZE = 30; - /** * Using Unicode Record Separator as delimiter. * This character is not likely to be used in the history items. */ - public static final String DEFAULT_DELIMITER = "␞"; + public static String DELIMITER = "␞"; - /** - * Default preferences key used to store history items. - */ - public static final String DEFAULT_PREFERENCES_KEY = "history-items"; + private final Preferences preferences; - private final String delimiter; - private final String preferencesKey; - private final StringConverter converter; + private final String key; - public PreferencesHistoryManager(StringConverter converter) { - this(DEFAULT_DELIMITER, DEFAULT_PREFERENCES_KEY, converter); - } + private final StringConverter converter; - public PreferencesHistoryManager(String delimiter, String preferencesKey, StringConverter converter) { - this.delimiter = Objects.requireNonNull(delimiter); - this.preferencesKey = Objects.requireNonNull(preferencesKey); + public PreferencesHistoryManager(Preferences preferences, String key, StringConverter converter) { + this.preferences = Objects.requireNonNull(preferences); + this.key = Objects.requireNonNull(key); this.converter = Objects.requireNonNull(converter); - loadHistory(); - - maxHistorySizeProperty().addListener(it -> { - // Check if the max history size is negative. If so, log a warning. - if (getMaxHistorySize() < 0) { - LOG.warning("Max history size must be greater than or equal to 0. "); - } - trimHistory(); - }); - - unmodifiableHistory.addListener((Observable it) -> storeHistory()); - preferencesProperty().addListener(it -> loadHistory()); } /** * Stores the history items in the preferences. */ - private void storeHistory() { - Preferences preferences = getPreferences(); - if (preferences != null) { - String result = unmodifiableHistory.stream() - .map(converter::toString) - .collect(Collectors.joining(delimiter)); - preferences.put(preferencesKey, result); - } + @Override + protected void storeHistory() { + String result = getAllUnmodifiable().stream() + .map(converter::toString) + .collect(Collectors.joining(DELIMITER)); + preferences.put(key, result); } /** * Loads the history items from the preferences. */ - private void loadHistory() { - Preferences preferences = getPreferences(); - if (preferences != null) { - String items = preferences.get(preferencesKey, ""); - if (StringUtils.isNotEmpty(items)) { - String[] ary = items.split(delimiter); - Arrays.stream(ary) - .map(converter::fromString) - .forEach(history::add); - } - } - } - - private final ObservableList history = FXCollections.observableArrayList(); - - /** - * Sets the history of the HistoryManager with the provided list of strings. - * The method ensures that duplicates are removed from the list. - * - * @param history the list of strings representing the history - */ - public final void set(List history) { - this.history.setAll(convertToUniqueList(history)); - } - - /** - * Adds the given item to the history. The method ensures that duplicates will not be added. - * - * @param item the item to add - */ - public final void add(T item) { - if (item != null && getFilter().test(item)) { - history.remove(item); - history.add(0, item); - trimHistory(); - } - } - - /** - * Adds the given items to the history. - * - * @param items the items to add - */ - public final void add(List items) { - List uniqueItems = convertToUniqueList(items); - if (!uniqueItems.isEmpty()) { - history.removeAll(uniqueItems); - history.addAll(0, uniqueItems); - trimHistory(); + @Override + protected void loadHistory() { + String items = preferences.get(key, ""); + if (StringUtils.isNotEmpty(items)) { + String[] ary = items.split(DELIMITER); + set(Arrays.stream(ary) + .map(converter::fromString) + .toList()); } } - - /** - * Removes the given item from the history. - * - * @param item the item to remove - * @return true if the item was removed, false otherwise - */ - public final boolean remove(T item) { - return history.remove(item); - } - - /** - * Removes the given items from the history. - * - * @param items the items to remove - */ - public final void remove(List items) { - history.removeAll(items); - } - - /** - * Clears the history. - */ - public final void clear() { - history.clear(); - } - - private final ObservableList unmodifiableHistory = FXCollections.unmodifiableObservableList(history); - - /** - * Returns an unmodifiable list of the history. - */ - public final ObservableList getAll() { - return unmodifiableHistory; - } - - private final IntegerProperty maxHistorySize = new SimpleIntegerProperty(this, "maxHistorySize", DEFAULT_MAX_HISTORY_SIZE); - - /** - * The maximum number of items that the history will store. If the number of items exceeds this value, the oldest - * items will be removed. - * - * @return the maximum number of items in the history - */ - public final IntegerProperty maxHistorySizeProperty() { - return maxHistorySize; - } - - public final int getMaxHistorySize() { - return maxHistorySize.get(); - } - - public final void setMaxHistorySize(int maxHistorySize) { - maxHistorySizeProperty().set(maxHistorySize); - } - - private final ObjectProperty> filter = new SimpleObjectProperty<>(this, "filter", it -> true); - - /** - * Returns the property object for the filter used when adding items to the history. - * Only items that pass the filter will be added to the history. - * - * @return the property object for the filter - */ - public final ObjectProperty> filterProperty() { - return filter; - } - - public final Predicate getFilter() { - return filter.get(); - } - - public final void setFilter(Predicate filter) { - this.filter.set(filter); - } - - private final ObjectProperty preferences = new SimpleObjectProperty<>(this, "preferences"); - - /** - * Returns the property object representing the preferences used for persisting history records. - * This property can be used to set or get the `Preferences` instance for storing history items. - * - * @return the property object representing the preferences - */ - public final ObjectProperty preferencesProperty() { - return preferences; - } - - public final Preferences getPreferences() { - return preferences.get(); - } - - public final void setPreferences(Preferences preferences) { - this.preferences.set(preferences); - } - - /** - * Trims the history list to ensure it does not exceed the maximum allowed size. - * If the current history size is greater than the maximum size, the method removes - * the extra elements from the history list. - */ - private void trimHistory() { - int max = Math.max(0, getMaxHistorySize()); - if (history.size() > max) { - history.remove(max, history.size()); - } - } - - /** - * Converts a given list of strings to a unique list of strings. Filters out empty strings. - * - * @param history the list of strings to convert - * @return the converted unique list of strings - */ - private List convertToUniqueList(List history) { - return history.stream().distinct().filter(Objects::nonNull).filter(getFilter()).limit(Math.max(0, getMaxHistorySize())).toList(); - } - - /** - * @return the delimiter used to separate history items - */ - public final String getDelimiter() { - return delimiter; - } - - /** - * @return the preferences key used to store history items - */ - public final String getPreferencesKey() { - return preferencesKey; - } - } diff --git a/gemsfx/src/main/java/com/dlsc/gemsfx/util/StringHistoryManager.java b/gemsfx/src/main/java/com/dlsc/gemsfx/util/StringHistoryManager.java index eae92523..84f5f676 100644 --- a/gemsfx/src/main/java/com/dlsc/gemsfx/util/StringHistoryManager.java +++ b/gemsfx/src/main/java/com/dlsc/gemsfx/util/StringHistoryManager.java @@ -19,11 +19,11 @@ * Due to the limitations of the {@code Preferences} API, this manager is not suitable for * scenarios involving large-scale data or complex data structures. It is optimized for * lightweight history management tasks where history items are stored and retrieved - * straightforwardly without transformation. + * in a straight forward fashion without transformation. *

*

* Key features include: - * - Persisting history in a simple, local manner using {@code Preferences} + * - Persisting history locally in a simple approach using the {@code Preferences} API * - Adding items while ensuring uniqueness * - Removing specific history items or clearing all history * - Providing a read-only view of history items to external components @@ -32,7 +32,7 @@ */ public class StringHistoryManager extends PreferencesHistoryManager { - private static final StringConverter DEFAULT_STRING_CONVERTER = new StringConverter<>() { + private static final StringConverter CONVERTER = new StringConverter<>() { @Override public String toString(String object) { return object; @@ -44,24 +44,8 @@ public String fromString(String string) { } }; - public StringHistoryManager() { - super(DEFAULT_STRING_CONVERTER); + public StringHistoryManager(Preferences preferences, String key) { + super(preferences, key, CONVERTER); setFilter(StringUtils::isNotEmpty); } - - public StringHistoryManager(Preferences preferences) { - this(); - setPreferences(preferences); - } - - public StringHistoryManager(String delimiter, String preferencesKey) { - super(delimiter, preferencesKey, DEFAULT_STRING_CONVERTER); - setFilter(StringUtils::isNotEmpty); - } - - public StringHistoryManager(String delimiter, String preferencesKey, Preferences preferences) { - this(delimiter, preferencesKey); - setPreferences(preferences); - } - } diff --git a/gemsfx/src/main/resources/com/dlsc/gemsfx/history-button.css b/gemsfx/src/main/resources/com/dlsc/gemsfx/history-button.css index 423d2875..3bebd052 100644 --- a/gemsfx/src/main/resources/com/dlsc/gemsfx/history-button.css +++ b/gemsfx/src/main/resources/com/dlsc/gemsfx/history-button.css @@ -46,7 +46,7 @@ } .history-popup > .content-pane > .history-list-view > .virtual-flow > .clipped-container > .sheet > .list-cell:focused { - -fx-background-color: transparent; + -fx-background: -fx-accent; } .history-popup > .content-pane > .history-list-view > .virtual-flow > .clipped-container > .sheet > .list-cell:filled:selected, @@ -73,4 +73,8 @@ .history-popup > .content-pane > .history-list-view > .virtual-flow > .clipped-container > .sheet > .removable-list-cell:selected .remove-button .ikonli-font-icon, .history-popup > .content-pane > .history-list-view > .virtual-flow > .clipped-container > .sheet > .removable-list-cell .remove-button:pressed .ikonli-font-icon { -fx-icon-color: -fx-text-background-color; +} + +.history-popup > .content-pane > .history-list-view > .virtual-flow > .clipped-container > .sheet > .removable-list-cell:focused .remove-button .ikonli-font-icon { + -fx-icon-color: -fx-selection-bar-text; } \ No newline at end of file