...
This makes it very easy to create your own defaults for SearchPanel controls: just create a factory, register it and make it return the correct score when you recognise a property you'd want to handle.
Example: creating your own component and builder
In this example we are going to make a screen to search inside the Tracks table.
We will use the EnumSetInput control to select zero to one Genre's from the database, then limit the search to those genres selected. The completed thing looks like this:
We will start with the page's code:
Code Block |
---|
@Override public void createContent() throws Exception {
ContentPanel cp = new ContentPanel();
add(cp);
SearchPanel<Track> lf = new SearchPanel<>(Track.class);
cp.add(lf);
lf.setClicked(a -> search(lf.getCriteria()));
//-- For Genre we will use a new control
EnumSetInput<Genre> genreC = new EnumSetInput<>(Genre.class);
List<Genre> genreList = getSharedContext().query(QCriteria.create(Genre.class));
genreC.setData(genreList);
Set<Genre> def = new HashSet<>();
def.add(genreList.get(0));
def.add(genreList.get(1));
lf.add().property("genre").defaultValue(def).control(new EnumSetQueryBuilder<>("genre"), genreC);
lf.add().property("name").control();
lf.add().property("album").control(); // Allow searching for a total
} |
We add the usual panel, then we prepare the EnumSetInput:
- We read all Genre records from the database in genreList
- We prepare a default (just for show) of the 1st two genres returned
- Then we add the control for the Genre to the SearchPanel.
The EnumSetInput returns a Set<Genre> for all of the selected items. This set of course is not understood by any of the existing query builders, so we made one ourself: the EnumSetQueryBuilder:
Code Block |
---|
public class EnumSetQueryBuilder<V> implements ILookupQueryBuilder<Set<V>> {
private final String m_propertyName;
public EnumSetQueryBuilder(String propertyName) {
m_propertyName = propertyName;
}
@Nonnull @Override public <T> LookupQueryBuilderResult appendCriteria(@Nonnull QCriteria<T> criteria, @Nullable Set<V> lookupValue) {
if(lookupValue == null || lookupValue.isEmpty())
return LookupQueryBuilderResult.EMPTY;
QRestrictor<T> or = criteria.or();
lookupValue.forEach(value -> or.eq(m_propertyName, value));
return LookupQueryBuilderResult.VALID;
}
} |
An instance of this class gets connected to the search item. It works as follows:
- The class gets instantiated with the property name to search for, which in this case will be "genre" inside the Track entity.
- When it is time to create the query the appendCriteria call gets called. It:
- Checks whether data was actually there. If not it returns the EMPTY indicator. This indicator is used when searching is only allowed with at least one clause filled in.
- For complex data you would also check the input here and throw a ValidationException if the data was wrong.
- We can now create the query: we add an or of all values in the set.