...
- 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.
Generating the form
The search panel generates a form containing the labels and controls that are added. By default it generates a simple vertical form where each label/control pair are on a single line. How can we influence the form's layout? For that we need to know how the form gets generated.
The SearchPanel uses an ISearchFormBuilder implementation as the thing that actually builds the form:
Code Block |
---|
public interface ISearchFormBuilder {
/** Defines the target node for the form to be built. */
void setTarget(NodeContainer target) throws Exception;
void append(SearchControlLine<?> it) throws Exception;
void finish() throws Exception;
} |
All actions that create the form based UI are delegated to this interface. If you do nothing then SearchPanel uses the default implementation of this thing: DefaultSearchFormBuilder. This implementation is very basic:
Code Block |
---|
public class DefaultSearchFormBuilder implements ISearchFormBuilder {
@Nullable
private FormBuilder m_builder;
private Div m_target;
@Override public void setTarget(NodeContainer target) throws Exception {
Div root = m_target = new Div("ui-dfsb-panel");
target.add(root);
Div d = new Div("ui-dfsb-part");
root.add(d);
m_builder = new FormBuilder(d);
}
@Override public void append(SearchControlLine<?> it) throws Exception {
NodeContainer label = it.getLabel();
if(null != label)
fb().label(label);
IControl<?> control = it.getControl();
fb().control(control);
}
public void addBreak() {
NodeContainer target = requireNonNull(m_target);
Div d = new Div("ui-dfsb-part");
target.add(d);
m_builder = new FormBuilder(d);
}
@Override public void finish() throws Exception {
m_builder = null;
}
@Nonnull
public FormBuilder fb() {
return requireNonNull(m_builder);
}
} |
It just uses a normal FormBuilder to create the form, and it has an extra "method" to allow the form to be split into multiple columns: the "addBreak" method.
Controlling how the form looks can be done by creating your own implementation of ISearchFormBuilder. You can even make it the default layout by calling:
Code Block |
---|
SearchPanel.setDefaultSearchFormBuilder(Supplier<ISearchFormBuilder> factory) |
so that the supplier returns your factory.
To interact with your factory you can add special "actions" to the SearchForm's definition. For example, to use that "addBreak()" method we would code the following:
Code Block |
---|
SearchPanel sp = new SearchPanel(Invoice.class);
DefaultSearchFormBuilder bld = new DefaultSearchFormBuilder();
sp.setFormBuilder(bld); // Ensure that the DefaultFormBuilder is used
//-- add first two props
lf.add().property("type").control(typeC, new EnumSetQueryBuilder<>(Definition.pTYPE));
lf.add().property("type").control();
lf.add().action(() -> bld.addBreak());
lf.add().property("stage").control(); |
The action will be executed in the order of adding the controls.
Warning |
---|
You could of course also cast lf.getFormBuilder() to DefaultSearchFormBuilder instead of creating an instance yourself. This however will cause your code to break if the default ever changes. |