From f47a5ebfdb543074a379836a4e887a65b186beb8 Mon Sep 17 00:00:00 2001 From: leewyatt Date: Fri, 24 May 2024 21:17:32 +0900 Subject: [PATCH] Enhancement: If there are a large number of elements, using replaceAll may cause performance issues. --- .../com/dlsc/gemsfx/MultiColumnListView.java | 31 ++-------- .../java/com/dlsc/gemsfx/util/ListUtils.java | 61 +++++++++++++++++++ 2 files changed, 66 insertions(+), 26 deletions(-) create mode 100644 gemsfx/src/main/java/com/dlsc/gemsfx/util/ListUtils.java diff --git a/gemsfx/src/main/java/com/dlsc/gemsfx/MultiColumnListView.java b/gemsfx/src/main/java/com/dlsc/gemsfx/MultiColumnListView.java index 4c24338a..2abc7e7b 100644 --- a/gemsfx/src/main/java/com/dlsc/gemsfx/MultiColumnListView.java +++ b/gemsfx/src/main/java/com/dlsc/gemsfx/MultiColumnListView.java @@ -1,6 +1,7 @@ package com.dlsc.gemsfx; import com.dlsc.gemsfx.skins.MultiColumnListViewSkin; +import com.dlsc.gemsfx.util.ListUtils; import javafx.beans.InvalidationListener; import javafx.beans.property.BooleanProperty; import javafx.beans.property.ListProperty; @@ -346,13 +347,7 @@ public ColumnListCell(MultiColumnListView multiColumnListView) { multiColumnListView.getDraggedItems().setAll(getListView().getSelectionModel().getSelectedItems()); - getListView().getItems().replaceAll(item -> { - if (item == getItem()) { - return multiColumnListView.getPlaceholderFrom(); - } - - return item; - }); + ListUtils.updateFirstMatching(getListView().getItems(), item -> item == getItem(), multiColumnListView.getPlaceholderFrom()); }); setOnDragOver(event -> { @@ -395,13 +390,7 @@ public ColumnListCell(MultiColumnListView multiColumnListView) { items.remove(multiColumnListView.getPlaceholderFrom()); T draggedItem = multiColumnListView.getDraggedItem(); - items.replaceAll(item -> { - if (item == multiColumnListView.getPlaceholderTo()) { - return draggedItem; - } - - return item; - }); + ListUtils.updateFirstMatching(items, item -> item == multiColumnListView.getPlaceholderTo(), draggedItem); if (!items.contains(draggedItem)) { // probably dropped on same list view / same column (hence no "to" placeholder) @@ -423,24 +412,14 @@ public ColumnListCell(MultiColumnListView multiColumnListView) { getListView().getItems().removeIf(item -> item == multiColumnListView.getPlaceholderFrom()); } else { log(" drop was not completed, replacing placeholder with dragged item"); - getListView().getItems().replaceAll(item -> { - if (item == multiColumnListView.getPlaceholderFrom()) { - return multiColumnListView.getDraggedItem(); - } - return item; - }); + ListUtils.updateFirstMatching(getListView().getItems(), item -> item == multiColumnListView.getPlaceholderFrom(), multiColumnListView.getDraggedItem()); } } else { log("drag done, not accepted"); // put the item back into the "from" location log("putting item back into 'from' location"); - getListView().getItems().replaceAll(item -> { - if (item == multiColumnListView.getPlaceholderFrom()) { - return multiColumnListView.getDraggedItem(); - } - return item; - }); + ListUtils.updateFirstMatching(getListView().getItems(), item -> item == multiColumnListView.getPlaceholderFrom(), multiColumnListView.getDraggedItem()); } multiColumnListView.setDraggedItem(null); diff --git a/gemsfx/src/main/java/com/dlsc/gemsfx/util/ListUtils.java b/gemsfx/src/main/java/com/dlsc/gemsfx/util/ListUtils.java new file mode 100644 index 00000000..8f353cab --- /dev/null +++ b/gemsfx/src/main/java/com/dlsc/gemsfx/util/ListUtils.java @@ -0,0 +1,61 @@ +package com.dlsc.gemsfx.util; + +import java.util.List; +import java.util.ListIterator; +import java.util.function.Predicate; + +public class ListUtils { + + /** + * Update matching elements in the list with the provided new value. + * + * @param list the list to operate on + * @param matchPredicate the predicate to match elements + * @param newValue the new value to replace matching elements + * @param breakAfterFirstMatch whether to break after the first match + * @param the type of elements in the list + * @return the number of elements updated + */ + public static int updateMatching(List list, Predicate matchPredicate, T newValue, boolean breakAfterFirstMatch) { + int updateCount = 0; + ListIterator iterator = list.listIterator(); + while (iterator.hasNext()) { + T currentElement = iterator.next(); + if (matchPredicate.test(currentElement)) { + iterator.set(newValue); + updateCount++; + if (breakAfterFirstMatch) { + break; + } + } + } + return updateCount; + } + + /** + * Update the first matching element in the list with the provided new value. + * + * @param list the list to operate on + * @param matchPredicate the predicate to match elements + * @param newValue the new value to replace matching elements + * @param the type of elements in the list + * @return the number of elements updated + */ + public static int updateFirstMatching(List list, Predicate matchPredicate, T newValue) { + return updateMatching(list, matchPredicate, newValue, true); + } + + /** + * Update all matching elements in the list with the provided new value. + * + * @param list the list to operate on + * @param matchPredicate the predicate to match elements + * @param newValue the new value to replace matching elements + * @param the type of elements in the list + * @return the number of elements updated + */ + public static int updateAllMatching(List list, Predicate matchPredicate, T newValue) { + return updateMatching(list, matchPredicate, newValue, false); + } +} +