From 7aa2c5330f1765b9e5a652e3393ffa416cb77c09 Mon Sep 17 00:00:00 2001 From: palexdev Date: Mon, 13 Nov 2023 12:54:42 +0100 Subject: [PATCH] :bug: Fix inconsistent filters (#313) Signed-off-by: palexdev --- demo/src/test/java/ContextTest.java | 8 ++-- demo/src/test/java/Reproducer.java | 47 +++++++++---------- .../palexdev/materialfx/beans/FilterBean.java | 6 +-- .../filter/base/AbstractFilter.java | 18 +++---- 4 files changed, 39 insertions(+), 40 deletions(-) diff --git a/demo/src/test/java/ContextTest.java b/demo/src/test/java/ContextTest.java index e10746e7..e44199a2 100644 --- a/demo/src/test/java/ContextTest.java +++ b/demo/src/test/java/ContextTest.java @@ -2,9 +2,9 @@ import io.github.palexdev.materialfx.controls.MFXButton; import io.github.palexdev.materialfx.controls.MFXContextMenu; import io.github.palexdev.materialfx.controls.MFXContextMenuItem; import io.github.palexdev.materialfx.factories.InsetsFactory; -import io.github.palexdev.mfxresources.fonts.MFXFontIcon; import io.github.palexdev.materialfx.utils.ColorUtils; import io.github.palexdev.materialfx.utils.StringUtils; +import io.github.palexdev.mfxresources.fonts.fontawesome.FontAwesomeSolid; import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Label; @@ -24,10 +24,10 @@ public class ContextTest extends Application { Label labelSeparator = new Label("Separator"); labelSeparator.setPadding(InsetsFactory.of(5, 3, 5, 0)); menu.addSeparator(labelSeparator); - menu.addItem(new MFXContextMenuItem("Separated Item", MFXFontIcon.getRandomIcon(12, ColorUtils.getRandomColor()))); + menu.addItem(new MFXContextMenuItem("Separated Item", FontAwesomeSolid.random(ColorUtils.getRandomColor(), 12))); menu.addLineSeparator(MFXContextMenu.Builder.getLineSeparator()); - menu.addItem(new MFXContextMenuItem("LSeparated Item", MFXFontIcon.getRandomIcon(12, ColorUtils.getRandomColor()))); + menu.addItem(new MFXContextMenuItem("LSeparated Item", FontAwesomeSolid.random(ColorUtils.getRandomColor(), 12))); menu.install(); @@ -40,7 +40,7 @@ public class ContextTest extends Application { private void populateMenu(MFXContextMenu menu, int num) { MFXContextMenuItem[] items = new MFXContextMenuItem[num]; for (int i = 0; i < num; i++) { - MFXContextMenuItem item = new MFXContextMenuItem("Menu Item " + (i + 1), MFXFontIcon.getRandomIcon(12, ColorUtils.getRandomColor())); + MFXContextMenuItem item = new MFXContextMenuItem("Menu Item " + (i + 1), FontAwesomeSolid.random(ColorUtils.getRandomColor(), 12)); item.setAccelerator("Alt + " + StringUtils.randAlphabetic(1).toUpperCase()); items[i] = item; } diff --git a/demo/src/test/java/Reproducer.java b/demo/src/test/java/Reproducer.java index a926b03e..076a76ca 100644 --- a/demo/src/test/java/Reproducer.java +++ b/demo/src/test/java/Reproducer.java @@ -1,35 +1,26 @@ -import io.github.palexdev.materialfx.controls.MFXComboBox; import io.github.palexdev.materialfx.controls.MFXTableColumn; import io.github.palexdev.materialfx.controls.MFXTableView; import io.github.palexdev.materialfx.controls.cell.MFXTableRowCell; import io.github.palexdev.materialfx.demo.model.Model; import io.github.palexdev.materialfx.demo.model.Person; +import io.github.palexdev.materialfx.filter.IntegerFilter; +import io.github.palexdev.materialfx.filter.StringFilter; import io.github.palexdev.materialfx.theming.CSSFragment; import io.github.palexdev.materialfx.theming.JavaFXThemes; import io.github.palexdev.materialfx.theming.MaterialFXStylesheets; import io.github.palexdev.materialfx.theming.UserAgentBuilder; +import io.github.palexdev.mfxcore.builders.InsetsBuilder; import javafx.application.Application; -import javafx.geometry.Insets; -import javafx.geometry.Pos; import javafx.scene.Scene; -import javafx.scene.layout.VBox; +import javafx.scene.layout.StackPane; import javafx.stage.Stage; public class Reproducer extends Application { @Override public void start(Stage stage) throws Exception { - VBox box = new VBox(20); - box.setAlignment(Pos.TOP_CENTER); - box.setPadding(new Insets(20)); - - UserAgentBuilder.builder() - .themes(JavaFXThemes.MODENA) - .themes(MaterialFXStylesheets.forAssemble(true)) - .setResolveAssets(true) - .setDeploy(true) - .build() - .setGlobal(); + StackPane pane = new StackPane(); + pane.setPadding(InsetsBuilder.all(10)); MFXTableView table = new MFXTableView<>(Model.people); MFXTableColumn name = new MFXTableColumn<>("Name"); @@ -39,7 +30,14 @@ public class Reproducer extends Application { MFXTableColumn age = new MFXTableColumn<>("Age"); age.setRowCellFactory(p -> new MFXTableRowCell<>(Person::getAge)); table.getTableColumns().addAll(name, surname, age); - box.getChildren().add(table); + pane.getChildren().add(table); + table.setMinSize(400.0, 400.0); + + table.getFilters().addAll( + new StringFilter<>("Name", Person::getName), + new StringFilter<>("Surname", Person::getSurname), + new IntegerFilter<>("Age", Person::getAge) + ); CSSFragment.Builder.build() .addSelector(".mfx-filter-pane") @@ -47,15 +45,14 @@ public class Reproducer extends Application { .closeSelector() .applyOn(table); - MFXComboBox combo = new MFXComboBox<>(Model.strings); - box.getChildren().add(combo); - CSSFragment.Builder.build() - .addSelector(".mfx-combo-box .combo-popup .virtual-flow") - .addStyle("-fx-background-color: gold") - .closeSelector() - .applyOn(combo); - - Scene scene = new Scene(box, 400, 400); + UserAgentBuilder.builder() + .themes(JavaFXThemes.MODENA) + .themes(MaterialFXStylesheets.forAssemble(false)) + .setResolveAssets(true) + .setDeploy(true) + .build() + .setGlobal(); + Scene scene = new Scene(pane, 600, 600); stage.setScene(scene); stage.show(); } diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/FilterBean.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/FilterBean.java index 095e6e9c..a9763383 100755 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/FilterBean.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/FilterBean.java @@ -31,7 +31,7 @@ import java.util.function.Predicate; * It wraps the following data: *

- A String which is the query *

- An object of type {@link AbstractFilter}, which is effectively responsible for producing the {@link Predicate} - *

- A {@link BiPredicateBean}, which is used by {@link AbstractFilter}, see {@link AbstractFilter#predicateFor(String)} or {@link AbstractFilter#predicateFor(String, BiPredicate)} + *

- A {@link BiPredicateBean}, which is used by {@link AbstractFilter}, see {@link AbstractFilter#predicateFor(String, FilterBean)} *

- A {@link ChainMode} enumeration to specify how this filter should be combined with other filters * * @param the type of objects to filter @@ -65,10 +65,10 @@ public class FilterBean { //================================================================================ /** - * Calls {@link AbstractFilter#predicateFor(String)} with the query specified by this bean. + * Calls {@link AbstractFilter#predicateFor(String, FilterBean)} with the query specified by this bean. */ public Predicate predicate() { - return filter.predicateFor(query); + return filter.predicateFor(query, this); } /** diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/filter/base/AbstractFilter.java b/materialfx/src/main/java/io/github/palexdev/materialfx/filter/base/AbstractFilter.java index df68c01a..f32f9310 100755 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/filter/base/AbstractFilter.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/filter/base/AbstractFilter.java @@ -43,7 +43,7 @@ import java.util.function.Predicate; * To make the filter system flexible and yet highly specialized, every implementation must specify a * {@link StringConverter} which is used to convert the query to an object of type U. *

- * At this point we have all the basic elements to describe how the {@link Predicate} is predicate is produced. + * At this point we have all the basic elements to describe how the {@link Predicate} is produced. * Every implementation of this base class has some predefined {@link BiPredicate} which operate on U objects. * The query is converted to an object of type U, and the extractor gets the U field from a T object, both U * objects are fed to the {@link BiPredicate}. In code: @@ -131,6 +131,12 @@ public abstract class AbstractFilter { * return t -> biPredicate.test(extractor.apply(t), convertedQuery); * } * + *

+ * WARN: this method should not be used to convert {@link FilterBean}s to {@link Predicate}. + * A {@link FilterBean} already has a {@link BiPredicate} that specifies its filter behavior. This method instead + * selects a {@link BiPredicate} according to the value of {@link #selectedPredicateIndexProperty()}, which may have + * changed since the creation of the {@link FilterBean}, leading to another filter being used instead. + * For this reason, use {@link #predicateFor(String, FilterBean)} instead. */ public Predicate predicateFor(String input) { checkIndex(); @@ -153,15 +159,11 @@ public abstract class AbstractFilter { * } * *

- * WARN: to be honest this method should have been removed but I wanted to keep it - * since it adds some flexibility to the filter system. Note that using this method may lead - * to inconsistencies in UI controls since the given argument is not a {@link BiPredicateBean}, - * which means that it won't be added to the predicates list of this filter, and the selected predicate index - * property won't be updated. This also means that any other method that relies on that index will fail. + * This is used by {@link FilterBean}s to convert themselves into a {@link Predicate}. */ - public Predicate predicateFor(String input, BiPredicate biPredicate) { + public Predicate predicateFor(String input, FilterBean bean) { U convertedInput = getValue(input); - return t -> biPredicate.test(extractor.apply(t), convertedInput); + return t -> bean.getPredicateBean().predicate().test(extractor.apply(t), convertedInput); } /**