Skip to content

Commit 1c413d3

Browse files
committed
Improve search results in treeview
1 parent e32df28 commit 1c413d3

File tree

2 files changed

+48
-5
lines changed

2 files changed

+48
-5
lines changed

src/main/java/net/sourceforge/pmd/util/fxdesigner/util/autocomplete/matchers/StringMatchUtil.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,18 @@ private StringMatchUtil() {
3030
/**
3131
* Selects the best {@link MatchResult} given a list of candidates and a query.
3232
*
33-
* The results are useless unless you provide the {@link MatchSelector} that
34-
* suits your use case.
33+
* <p>The results are useless unless you provide the {@link MatchSelector} that
34+
* suits your use case (limiter).
35+
*
36+
* @param candidates List of stuff to sort
37+
* @param matchExtractor Extracts the searchable text from an item
38+
* @param limiter Selects the best candidates, may process them further to break ties
39+
* @param query Text to search for
3540
*/
36-
public static <T> Stream<MatchResult<T>> filterResults(List<T> candidates, Function<T, String> matchExtractor, String query, MatchSelector<T> limiter) {
41+
public static <T> Stream<MatchResult<T>> filterResults(List<? extends T> candidates,
42+
Function<? super T, String> matchExtractor,
43+
String query,
44+
MatchSelector<T> limiter) {
3745
if (query.length() < MIN_QUERY_LENGTH) {
3846
return Stream.empty();
3947
}

src/main/java/net/sourceforge/pmd/util/fxdesigner/util/controls/SearchableTreeView.java

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@
4343
import javafx.scene.layout.StackPane;
4444
import javafx.stage.Popup;
4545

46+
/**
47+
*
48+
* @param <T> Item type
49+
* @see SearchableTreeItem
50+
* @see SearchableTreeCell
51+
*/
4652
public class SearchableTreeView<T> extends TreeView<T> {
4753

4854
public static final int MIN_QUERY_LENGTH = 1;
@@ -81,6 +87,9 @@ private SearchableTreeItem<T> getRealRoot() {
8187
}
8288

8389

90+
/**
91+
* Textfield for the search query.
92+
*/
8493
private void popSearchField() {
8594
TextField textField = new TextField();
8695
textField.setPrefWidth(150);
@@ -210,25 +219,27 @@ private Subscription subscribeKeyNav(int numResults, Var<Integer> curIdx, Node e
210219

211220
}
212221

213-
214222
private List<MatchResult<SearchableTreeItem<T>>> selectMatches(String query, List<SearchableTreeItem<T>> items) {
215223
MatchSelector<SearchableTreeItem<T>> limiter =
216224
CamelCaseMatcher.<SearchableTreeItem<T>>allQueryStarts()
217225
.andThen(c -> c.filter(it -> it.getScore() > 0))
218226
.andThen(Stream::parallel)
227+
.andThen(CamelCaseMatcher.onlyWordStarts())
219228
.andThen(MatchSelector.selectBestTies());
220229

221230
return StringMatchUtil.filterResults(items, SearchableTreeItem::getSearchableText, query, limiter)
222231
.sorted(Comparator.comparingInt(res -> res.getData().getTreeIndex()))
223232
.collect(Collectors.toList());
224233
}
225234

235+
226236
public abstract static class SearchableTreeItem<T> extends TreeItem<T> {
227237

228238
private final Var<SearchableTreeCell<T>> treeCell = Var.newSimpleVar(null);
229239
private final Var<MatchResult<SearchableTreeItem<T>>> currentSearchResult = Var.newSimpleVar(null);
230240
private final int treeIndex;
231241

242+
232243
public SearchableTreeItem(T n, int treeIndex) {
233244
super(n);
234245
this.treeIndex = treeIndex;
@@ -244,17 +255,33 @@ public Var<SearchableTreeCell<T>> treeCellProperty() {
244255
return treeCell;
245256
}
246257

258+
247259
public Val<MatchResult<SearchableTreeItem<T>>> currentSearchResultProperty() {
248260
return currentSearchResult;
249261
}
250262

263+
264+
/**
265+
* Text used to match search queries. This must be the
266+
* same text as is displayed on the cell in normal mode.
267+
*/
251268
public abstract String getSearchableText();
252269

270+
253271
public int getTreeIndex() {
254272
return treeIndex;
255273
}
256274
}
257275

276+
/**
277+
* A searchable tree cell is bound both ways to a searchable
278+
* tree item. It has three visual states:
279+
* <ul>
280+
* <li>unbound (no underlying item, not visible in tree)
281+
* <li>bound with a search result (in which case it displays the styled search result)
282+
* <li>bound without a search result (in which case it displays the searchable text, maybe with some styling)
283+
* </ul>
284+
*/
258285
public abstract static class SearchableTreeCell<T> extends TreeCell<T> {
259286

260287
public SearchableTreeCell() {
@@ -272,6 +299,7 @@ public SearchableTreeCell() {
272299
});
273300
}
274301

302+
275303
protected Val<MatchResult<SearchableTreeItem<T>>> searchResultProperty() {
276304
return realItemProperty().flatMap(SearchableTreeItem::currentSearchResultProperty);
277305
}
@@ -298,12 +326,19 @@ public void updateItem(T item, boolean empty) {
298326
}
299327
}
300328

329+
330+
/**
331+
* Update just for when the item is not a search result.
332+
*/
301333
protected void setNonSearchState(SearchableTreeItem<T> realItem) {
302334
setGraphic(null);
303-
// todo would be nicer if the treeview had colors
304335
setText(realItem.getSearchableText());
305336
}
306337

338+
339+
/**
340+
* Update for both visible states.
341+
*/
307342
public abstract void commonUpdate(T item);
308343

309344

0 commit comments

Comments
 (0)