Originariamente inviata da
fermat
bhe si grazie, quando hai tempo se ti va esponi!
almeno imparo qualcosa di nuovo!
Innanzitutto puoi fare una semplice interfaccia:
codice:
public interface TextMatcher {
boolean matches(String text);
}
Poi in modo specifico per Film (ma lo potrai fare similarmente per qualunque altro oggetto) fai una classe di implementazione di TextMatcher:
codice:
public class FilmTextMatcher implements TextMatcher {
private String titolo;
private String author;
private String note;
public FilmTextMatcher(Film film) {
titolo = film.getTitle().toLowerCase();
author = film.getAuthor().toLowerCase();
note = film.getNote().toLowerCase();
}
@Override
public boolean matches(String text) {
text = text.toLowerCase();
return titolo.contains(text) || author.contains(text) || note.contains(text);
}
}
Nota che in FilmTextMatcher NON c'è alcuna logica del "negativo". Un FilmTextMatcher fa solo una cosa: data una stringa la cerca all'interno dell'oggetto Film e restituisce se la trova o no. Per farlo deve stabilire: a) "dove" cercarla (in quali campi) e b) "come" cercarla (con contains() piuttosto che startWith() ecc...). Solo FilmTextMatcher "sa" come fare queste due cose (che sono specifiche di Film, ovviamente). E non fa altro.
Poi fai una classe SearchPattern che rappresenta il pattern inserito dall'utente e che ha la capacità di "matchare" con un TextMatcher.
codice:
public class SearchPattern {
private final Item[] items;
public SearchPattern(String text) {
String[] tokens = text.split("\\s+");
items = new Item[tokens.length];
for (int i = 0; i < items.length; i++) {
items[i] = new Item(tokens[i]);
}
}
public boolean matches(TextMatcher textMatcher) {
boolean allMatch = true;
for (int i = 0; allMatch && i < items.length; i++) {
Item item = items[i];
boolean match = textMatcher.matches(item.getText());
if (item.isNegative()) {
allMatch &= !match;
} else {
allMatch &= match;
}
}
return allMatch;
}
private static class Item {
final boolean negative;
final String text;
public Item(String text) {
if (text.startsWith("!")) {
this.text = text.substring(1);
negative = true;
} else {
this.text = text;
negative = false;
}
}
public boolean isNegative() {
return negative;
}
public String getText() {
return text;
}
}
}
Nota come SearchPattern analizza il pattern in input (es. "!stephen !king") e si "compila" una lista di Item che rappresentano ciascun pezzo del pattern, con o senza la negazione.
Quindi il matches semplicemente "prova" ciascuno di questi pezzi contro il TextMatcher. Ed è qui che viene usato il concetto di "negato". Se nel pattern c'è !stephen e stephen lo TROVO, allora per la negazione non è valido e allMatch diventa false.
A quel punto il tuo listener diventa:
codice:
txtSearch.textProperty().addListener((observable, oldValue, newValue) -> {
SearchPattern searchPattern = new SearchPattern(newValue);
filteredData.setPredicate(film -> searchPattern.matches(new FilmTextMatcher(film)));
});
che puoi ancora abbreviare, se vuoi.
Non è gestito il caso in cui newValue possa essere null ma in teoria non dovrebbe mai esserlo (non ho bene idea adesso sul textfield di JavaFX, dovrei documentarmi).