mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-23 12:33:53 +00:00
Refactored AbstractFilterablePanel and CustomizableFilterablePanel to
consistently use com.sap.sse.common.filter.Filter for the keyword filter and the extendible set of filters in CustomizableFilterablePanel
This commit is contained in:
1 parent
818c8dfb03
commit
2b1f0353a5
4 files changed
+106
-79
No files matched your search
+5
-1
@@ -46,6 +46,7 @@ import com.sap.sailing.gwt.ui.client.shared.controls.SelectionCheckboxColumn;
|
||||
import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil;
|
||||
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.filter.Filter;
|
||||
import com.sap.sse.common.util.NaturalComparator;
|
||||
import com.sap.sse.gwt.client.ErrorReporter;
|
||||
import com.sap.sse.gwt.client.async.MarkedAsyncCallback;
|
||||
@@ -53,7 +54,6 @@ import com.sap.sse.gwt.client.celltable.EntityIdentityComparator;
|
||||
import com.sap.sse.gwt.client.celltable.RefreshableSelectionModel;
|
||||
import com.sap.sse.gwt.client.celltable.RefreshableSingleSelectionModel;
|
||||
import com.sap.sse.gwt.client.panels.CustomizableFilterablePanel;
|
||||
import com.sap.sse.gwt.client.panels.CustomizableFilterablePanel.Filter;
|
||||
import com.sap.sse.gwt.client.shared.components.Component;
|
||||
import com.sap.sse.gwt.client.shared.components.SettingsDialogComponent;
|
||||
|
||||
@@ -172,6 +172,10 @@ public abstract class AbstractTrackedRacesListComposite extends SimplePanel
|
||||
public boolean matches(RaceDTO t) {
|
||||
return listBoxRegattas.getSelectedIndex() == 0 /* All */ || Util.equalsWithNull(listBoxRegattas.getSelectedValue(), t.getRegattaName());
|
||||
}
|
||||
@Override
|
||||
public String getName() {
|
||||
return "TrackedRacesByRegattaFilter";
|
||||
}
|
||||
});
|
||||
|
||||
Label lblFilterRacesByName = new Label(stringMessages.filterByNameOrBoatClass() + ":");
|
||||
|
||||
+7
-14
@@ -41,7 +41,7 @@ import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil;
|
||||
import com.sap.sailing.gwt.ui.shared.DeviceMappingDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.MarkDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.TypedDeviceMappingDTO;
|
||||
import com.sap.sse.common.filter.AbstractListFilter;
|
||||
import com.sap.sse.common.filter.AbstractKeywordFilter;
|
||||
import com.sap.sse.gwt.client.ErrorReporter;
|
||||
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
|
||||
import com.sap.sse.gwt.client.panels.LabeledAbstractFilterablePanel;
|
||||
@@ -181,24 +181,17 @@ public class RegattaLogTrackingDeviceMappingsDialog extends DataEntryDialog<Void
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractListFilter<DeviceMappingDTO> getFilterer() {
|
||||
final AbstractListFilter<DeviceMappingDTO> baseFilterer = super.getFilterer();
|
||||
return new AbstractListFilter<DeviceMappingDTO>() {
|
||||
protected AbstractKeywordFilter<DeviceMappingDTO> getFilterer() {
|
||||
final AbstractKeywordFilter<DeviceMappingDTO> baseFilterer = super.getFilterer();
|
||||
return new AbstractKeywordFilter<DeviceMappingDTO>() {
|
||||
@Override
|
||||
public Iterable<String> getStrings(DeviceMappingDTO t) {
|
||||
return baseFilterer.getStrings(t);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Iterable<DeviceMappingDTO> applyFilter(Iterable<String> keywords,
|
||||
Iterable<DeviceMappingDTO> all) {
|
||||
final List<DeviceMappingDTO> result = new ArrayList<>();
|
||||
for (final DeviceMappingDTO dm : super.applyFilter(keywords, all)) {
|
||||
if (showPingMappingsCb.getValue() || !"PING".equals(dm.deviceIdentifier.deviceType)) {
|
||||
result.add(dm);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
public boolean matches(DeviceMappingDTO dm) {
|
||||
return super.matches(dm) && showPingMappingsCb.getValue() || !"PING".equals(dm.deviceIdentifier.deviceType);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
+70
-44
@@ -1,6 +1,8 @@
|
||||
package com.sap.sse.gwt.client.panels;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.event.dom.client.KeyUpEvent;
|
||||
import com.google.gwt.event.dom.client.KeyUpHandler;
|
||||
@@ -12,25 +14,28 @@ import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.TextBox;
|
||||
import com.google.gwt.view.client.ListDataProvider;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.filter.AbstractKeywordFilter;
|
||||
import com.sap.sse.common.filter.AbstractListFilter;
|
||||
import com.sap.sse.common.filter.Filter;
|
||||
import com.sap.sse.gwt.client.celltable.EntityIdentityComparator;
|
||||
import com.sap.sse.gwt.client.celltable.RefreshableMultiSelectionModel;
|
||||
import com.sap.sse.gwt.client.celltable.RefreshableSelectionModel;
|
||||
import com.sap.sse.gwt.client.celltable.RefreshableSingleSelectionModel;
|
||||
|
||||
/**
|
||||
* This Panel contains a text box. Text entered into the text box filters the {@link CellTable} passed to
|
||||
* the constructor by adjusting the cell table's {@link ListDataProvider}'s contents using the {@link
|
||||
* applyFilter(String, List)} of the {@link AbstractListFilter} and then sorting the table again according the the
|
||||
* sorting criteria currently active (the sorting is the only reason why the {@link CellTable} actually needs to be
|
||||
* known to an instance of this class). To be initiated the method {@link #getSearchableStrings(Object)} has to be
|
||||
* defined, which gets those Strings from a <code>T</code> that should be considered when filtering, e.g. name or
|
||||
* boatClass. The cell table can be sorted independently from the text box (e.g., after adding new objects) by calling
|
||||
* the method {@link #updateAll(Iterable)} which then runs the filter over the new selection.<p>
|
||||
* This Panel contains a text box. Text entered into the text box filters the {@link CellTable} passed to the
|
||||
* constructor by adjusting the cell table's {@link ListDataProvider}'s contents using the {@link applyFilter(String,
|
||||
* List)} of the {@link AbstractListFilter} and then sorting the table again according the the sorting criteria
|
||||
* currently active (the sorting is the only reason why the {@link CellTable} actually needs to be known to an instance
|
||||
* of this class). To be initiated the method {@link #getSearchableStrings(Object)} has to be defined, which gets those
|
||||
* Strings from a <code>T</code> that should be considered when filtering, e.g. name or boatClass. The cell table can be
|
||||
* sorted independently from the text box (e.g., after adding new objects) by calling the method
|
||||
* {@link #updateAll(Iterable)} which then runs the filter over the new selection.
|
||||
* <p>
|
||||
*
|
||||
* Note that this panel does <em>not</em> contain the table that it filters. With this, this class's clients are free
|
||||
* to position the table wherever they want, not necessarily related to the text box provided by this panel in any
|
||||
* specific way.
|
||||
* Note that this panel does <em>not</em> contain the table that it filters. With this, this class's clients are free to
|
||||
* position the table wherever they want, not necessarily related to the text box provided by this panel in any specific
|
||||
* way.
|
||||
*
|
||||
* @param <T>
|
||||
* @author Nicolas Klose, Axel Uhl
|
||||
@@ -41,27 +46,28 @@ public abstract class AbstractFilterablePanel<T> extends HorizontalPanel {
|
||||
protected AbstractCellTable<T> display;
|
||||
protected final ListDataProvider<T> filtered;
|
||||
protected final TextBox textBox;
|
||||
|
||||
protected final AbstractListFilter<T> filterer = new AbstractListFilter<T>() {
|
||||
|
||||
protected final AbstractKeywordFilter<T> filterer = new AbstractKeywordFilter<T>() {
|
||||
@Override
|
||||
public Iterable<String> getStrings(T t) {
|
||||
return getSearchableStrings(t);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param all
|
||||
* the sequence of all objects that may be displayed in the table and from which the filter may choose.
|
||||
* This panel keeps a copy, so modifications to the <code>all</code> object do not reflect in the table
|
||||
* contents. Use {@link #updateAll(Iterable)} instead to update the sequence of available objects.
|
||||
* @param drawTextBox
|
||||
* if {@code true}, the default text box will be shown that can be used to provide the filter text; if {@code false},
|
||||
* the box may optionally be added later using the {@link #addDefaultTextBox()} method. This way, subclasses may choose
|
||||
* to add other filter elements before the default text filter box. Filtering will still use the text box contents,
|
||||
* even if the box is ultimately not shown; but under normal circumstances the text box will be empty in this case,
|
||||
* not making filtering any stricter.
|
||||
* if {@code true}, the default text box will be shown that can be used to provide the filter text; if
|
||||
* {@code false}, the box may optionally be added later using the {@link #addDefaultTextBox()} method.
|
||||
* This way, subclasses may choose to add other filter elements before the default text filter box.
|
||||
* Filtering will still use the text box contents, even if the box is ultimately not shown; but under
|
||||
* normal circumstances the text box will be empty in this case, not making filtering any stricter.
|
||||
*/
|
||||
public AbstractFilterablePanel(Iterable<T> all, AbstractCellTable<T> display, final ListDataProvider<T> filtered, boolean drawTextBox) {
|
||||
public AbstractFilterablePanel(Iterable<T> all, AbstractCellTable<T> display, final ListDataProvider<T> filtered,
|
||||
boolean drawTextBox) {
|
||||
setSpacing(5);
|
||||
this.all = new ListDataProvider<>();
|
||||
this.display = display;
|
||||
@@ -74,11 +80,11 @@ public abstract class AbstractFilterablePanel<T> extends HorizontalPanel {
|
||||
addDefaultTextBox();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public AbstractFilterablePanel(Iterable<T> all, AbstractCellTable<T> display, final ListDataProvider<T> filtered) {
|
||||
this(all, display, filtered, /* show default filter text box */ true);
|
||||
}
|
||||
|
||||
|
||||
private void setAll(Iterable<T> all) {
|
||||
this.all.getList().clear();
|
||||
if (all != null) {
|
||||
@@ -99,14 +105,13 @@ public abstract class AbstractFilterablePanel<T> extends HorizontalPanel {
|
||||
public abstract Iterable<String> getSearchableStrings(T t);
|
||||
|
||||
/**
|
||||
* Updates the set of all objects to be shown in the table and applies the search filter to update the
|
||||
* table view.
|
||||
* Updates the set of all objects to be shown in the table and applies the search filter to update the table view.
|
||||
*/
|
||||
public void updateAll(Iterable<T> all){
|
||||
public void updateAll(Iterable<T> all) {
|
||||
setAll(all);
|
||||
filter();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds an object and applies the search filter.
|
||||
*/
|
||||
@@ -122,14 +127,15 @@ public abstract class AbstractFilterablePanel<T> extends HorizontalPanel {
|
||||
all.getList().add(index, object);
|
||||
filter();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element.
|
||||
* Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not
|
||||
* contain the element.
|
||||
*/
|
||||
public int indexOf(T object) {
|
||||
return all.getList().indexOf(object);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes an object and applies the search filter.
|
||||
*/
|
||||
@@ -137,12 +143,12 @@ public abstract class AbstractFilterablePanel<T> extends HorizontalPanel {
|
||||
all.getList().remove(object);
|
||||
filter();
|
||||
}
|
||||
|
||||
|
||||
public void addAll(Iterable<T> objects) {
|
||||
Util.addAll(objects, all.getList());
|
||||
filter();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Would better be called {@code clear()}, but {@link #clear} is already the method inherited from {@link Panel}...
|
||||
* This method removes all entries from this filterable panel. The effect is the same as invoking
|
||||
@@ -152,12 +158,12 @@ public abstract class AbstractFilterablePanel<T> extends HorizontalPanel {
|
||||
all.getList().clear();
|
||||
filter();
|
||||
}
|
||||
|
||||
|
||||
public void removeAll(Iterable<T> objects) {
|
||||
Util.removeAll(objects, all.getList());
|
||||
filter();
|
||||
}
|
||||
|
||||
|
||||
public void filter() {
|
||||
filtered.getList().clear();
|
||||
retainElementsInFilteredThatPassFilter();
|
||||
@@ -166,21 +172,27 @@ public abstract class AbstractFilterablePanel<T> extends HorizontalPanel {
|
||||
}
|
||||
|
||||
protected void retainElementsInFilteredThatPassFilter() {
|
||||
Util.addAll(getFilterer().applyFilter(Arrays.asList(getTextBox().getText().split(" ")), all.getList()),
|
||||
filtered.getList());
|
||||
List<T> filteredElements = new ArrayList<>();
|
||||
for (T t : all.getList()) {
|
||||
if (getFilter().matches(t)) {
|
||||
filteredElements.add(t);
|
||||
}
|
||||
}
|
||||
Util.addAll(filteredElements, filtered.getList());
|
||||
}
|
||||
|
||||
|
||||
protected void sort() {
|
||||
if (display != null) {
|
||||
ColumnSortEvent.fire(display, display.getColumnSortList());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void addDefaultTextBox() {
|
||||
add(getTextBox());
|
||||
getTextBox().addKeyUpHandler(new KeyUpHandler() {
|
||||
@Override
|
||||
public void onKeyUp(KeyUpEvent event) {
|
||||
getFilterer().setKeywords(Arrays.asList(getTextBox().getText().split(" ")));
|
||||
filter();
|
||||
}
|
||||
});
|
||||
@@ -189,15 +201,15 @@ public abstract class AbstractFilterablePanel<T> extends HorizontalPanel {
|
||||
public TextBox getTextBox() {
|
||||
return textBox;
|
||||
}
|
||||
|
||||
|
||||
public Iterable<T> getAll() {
|
||||
return all.getList();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Registers a {@link RefreshableSelectionModel} on the all data structure. So the selection can be maintained when
|
||||
* the {@link CellTable} is filtered. You can use the {@link RefreshableSelectionModel} returned by this method
|
||||
* e.g. for a {@link CellTable} using {@link CellTable#setSelectionModel(com.google.gwt.view.client.SelectionModel)}
|
||||
* the {@link CellTable} is filtered. You can use the {@link RefreshableSelectionModel} returned by this method e.g.
|
||||
* for a {@link CellTable} using {@link CellTable#setSelectionModel(com.google.gwt.view.client.SelectionModel)}
|
||||
*
|
||||
* @param comp
|
||||
* {@link EntityIdentityComparator Comperator} to create the {@link RefreshableSelectionModel selection
|
||||
@@ -226,19 +238,33 @@ public abstract class AbstractFilterablePanel<T> extends HorizontalPanel {
|
||||
public ListDataProvider<T> getAllListDataProvider() {
|
||||
return all;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method can be used to set the CellTable, when the {@link CellTable} on which this Panel should work is
|
||||
* created after this Panel. When the table isn't set correctly the order of elements, could be wrong after
|
||||
* filtering the data.
|
||||
*
|
||||
* @param table {@link AbstractCellTable} on which this panel works.
|
||||
* @param table
|
||||
* {@link AbstractCellTable} on which this panel works.
|
||||
*/
|
||||
public void setTable(AbstractCellTable<T> table) {
|
||||
display = table;
|
||||
}
|
||||
|
||||
protected AbstractListFilter<T> getFilterer() {
|
||||
/**
|
||||
* @return the AbstractKeywordFilter to use for keyword-based filtering
|
||||
*/
|
||||
protected AbstractKeywordFilter<T> getFilterer() {
|
||||
return filterer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Filter} to be used for filtering the result list. By default, this is just the keyword filter
|
||||
* returned by {@link #getFilterer()}.
|
||||
*
|
||||
* May be overwritten by subclasses to e.g. define a composite filter or completely exchange the filter.
|
||||
*/
|
||||
protected Filter<T> getFilter() {
|
||||
return getFilterer();
|
||||
}
|
||||
}
|
||||
+24
-20
@@ -1,7 +1,6 @@
|
||||
package com.sap.sse.gwt.client.panels;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.gwt.user.cellview.client.AbstractCellTable;
|
||||
@@ -9,7 +8,7 @@ import com.google.gwt.user.client.ui.HasVerticalAlignment;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.google.gwt.view.client.ListDataProvider;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.filter.Filter;
|
||||
|
||||
/**
|
||||
* Customizable filter panel which allows to create a flexible filter panel with various number of filter inputs (e.g.
|
||||
@@ -20,11 +19,10 @@ import com.sap.sse.common.Util;
|
||||
*
|
||||
*/
|
||||
public abstract class CustomizableFilterablePanel<T> extends AbstractFilterablePanel<T> {
|
||||
public static interface Filter<T> {
|
||||
boolean matches(T t);
|
||||
}
|
||||
|
||||
private Set<Filter<T>> filters;
|
||||
private final Set<Filter<T>> filters;
|
||||
|
||||
private final Filter<T> compositeFilter = new CompositeFilter();
|
||||
|
||||
public CustomizableFilterablePanel(Iterable<T> all, AbstractCellTable<T> display, ListDataProvider<T> filtered) {
|
||||
super(all, display, filtered, /* show default filter text box */ false);
|
||||
@@ -39,21 +37,27 @@ public abstract class CustomizableFilterablePanel<T> extends AbstractFilterableP
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void retainElementsInFilteredThatPassFilter() {
|
||||
super.retainElementsInFilteredThatPassFilter();
|
||||
for (final Iterator<T> i = filtered.getList().iterator(); i.hasNext(); ) {
|
||||
final T t = i.next();
|
||||
for (final Filter<T> filter : filters) {
|
||||
if (!filter.matches(t)) {
|
||||
i.remove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
protected Filter<T> getFilter() {
|
||||
return compositeFilter;
|
||||
}
|
||||
|
||||
public void clearFilter() {
|
||||
filtered.getList().clear();
|
||||
Util.addAll(all.getList(), filtered.getList());
|
||||
public boolean matches(T t) {
|
||||
boolean matches = super.getFilter().matches(t);
|
||||
for (final Filter<T> filter : filters) {
|
||||
matches &= filter.matches(t);
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
private class CompositeFilter implements Filter<T> {
|
||||
@Override
|
||||
public boolean matches(T object) {
|
||||
return CustomizableFilterablePanel.this.matches(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user