/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE file at the root of the source
* tree and available online at
*
* https://github.com/keeps/roda
*/
package org.roda.wui.client.common.search;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.roda.core.data.common.RodaConstants;
import org.roda.core.data.v2.index.filter.BasicSearchFilterParameter;
import org.roda.core.data.v2.index.filter.EmptyKeyFilterParameter;
import org.roda.core.data.v2.index.filter.Filter;
import org.roda.core.data.v2.index.filter.FilterParameter;
import org.roda.core.data.v2.index.filter.NotSimpleFilterParameter;
import org.roda.core.data.v2.index.filter.OrFiltersParameters;
import org.roda.core.data.v2.index.filter.SimpleFilterParameter;
import org.roda.wui.client.common.lists.utils.AsyncTableCell;
import org.roda.wui.client.common.utils.JavascriptUtils;
import org.roda.wui.common.client.widgets.wcag.AccessibleFocusPanel;
import org.roda.wui.common.client.widgets.wcag.WCAGUtilities;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
import config.i18n.client.ClientMessages;
public class SearchPanel extends Composite implements HasValueChangeHandlers<String> {
private static final String FILTER_ICON = "<i class='fa fa-filter' aria-hidden='true'></i>";
private static final ClientMessages messages = GWT.create(ClientMessages.class);
private static final Binder binder = GWT.create(Binder.class);
interface Binder extends UiBinder<Widget, SearchPanel> {
}
@UiField
FlowPanel searchPanel;
@UiField
Dropdown searchInputListBox;
@UiField
TextBox searchInputBox;
@UiField
AccessibleFocusPanel searchInputButton;
@UiField
AccessibleFocusPanel searchAdvancedDisclosureButton;
@UiField
FlowPanel searchAdvancedPanel;
@UiField
FlowPanel searchAdvancedPanelButtons;
@UiField
Button searchAdvancedFieldOptionsAdd;
@UiField
Button searchAdvancedGo;
@UiField
Button searchAdvancedClean;
@UiField
FlowPanel searchPreFilters;
private Filter defaultFilter;
private String allFilter;
private boolean defaultFilterIncremental = false;
private FlowPanel fieldsPanel;
private AsyncTableCell<?, ?> list;
private boolean hidePreFilters;
public SearchPanel(Filter defaultFilter, String allFilter, boolean incremental, String placeholder,
boolean showSearchInputListBox, boolean showSearchAdvancedDisclosureButton, boolean hidePreFilters) {
this.defaultFilter = defaultFilter;
this.allFilter = allFilter;
this.hidePreFilters = hidePreFilters;
this.defaultFilterIncremental = incremental;
initWidget(binder.createAndBindUi(this));
if (placeholder != null) {
searchInputBox.getElement().setPropertyString("placeholder", placeholder);
}
searchInputListBox.setVisible(showSearchInputListBox);
searchAdvancedDisclosureButton.setVisible(showSearchAdvancedDisclosureButton);
searchAdvancedPanel.setVisible(false);
searchInputBox.addKeyDownHandler(new KeyDownHandler() {
@Override
public void onKeyDown(KeyDownEvent event) {
if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
doSearch();
}
}
});
searchInputButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
doSearch();
}
});
searchAdvancedDisclosureButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
showSearchAdvancedPanel();
}
});
searchInputListBox.addValueChangeHandler(new ValueChangeHandler<String>() {
@Override
public void onValueChange(ValueChangeEvent<String> event) {
onChange();
}
});
if (showSearchAdvancedDisclosureButton) {
searchPanel.addStyleName("searchPanelAdvanced");
}
if (!hidePreFilters) {
drawSearchPreFilters();
}
WCAGUtilities.getInstance().makeAccessible(searchInputListBox.getElement());
}
private void drawSearchPreFilters() {
searchPreFilters.clear();
searchPreFilters.setVisible(defaultFilter != null && !defaultFilter.getParameters().isEmpty());
if (defaultFilter != null) {
for (FilterParameter parameter : defaultFilter.getParameters()) {
HTML html = null;
if (parameter instanceof SimpleFilterParameter) {
SimpleFilterParameter p = (SimpleFilterParameter) parameter;
html = new HTML(messages.searchPreFilterSimpleFilterParameter(messages.searchPreFilterName(p.getName()),
messages.searchPreFilterValue(p.getValue())));
} else if (parameter instanceof BasicSearchFilterParameter) {
BasicSearchFilterParameter p = (BasicSearchFilterParameter) parameter;
// TODO put '*' in some constant, see Search
if (!"*".equals(p.getValue())) {
html = new HTML(messages.searchPreFilterBasicSearchFilterParameter(
messages.searchPreFilterName(p.getName()), messages.searchPreFilterValue(p.getValue())));
}
} else if (parameter instanceof NotSimpleFilterParameter) {
NotSimpleFilterParameter p = (NotSimpleFilterParameter) parameter;
html = new HTML(messages.searchPreFilterNotSimpleFilterParameter(messages.searchPreFilterName(p.getName()),
messages.searchPreFilterValue(p.getValue())));
} else if (parameter instanceof EmptyKeyFilterParameter) {
EmptyKeyFilterParameter p = (EmptyKeyFilterParameter) parameter;
html = new HTML(messages.searchPreFilterEmptyKeyFilterParameter(messages.searchPreFilterName(p.getName())));
} else {
html = new HTML(SafeHtmlUtils.fromString(parameter.getClass().getSimpleName()));
}
if (html != null) {
HTML header = new HTML(SafeHtmlUtils.fromSafeConstant(FILTER_ICON));
header.addStyleName("inline gray");
searchPreFilters.add(header);
html.addStyleName("xsmall gray inline nowrap");
searchPreFilters.add(html);
}
}
}
}
public void doSearch() {
Filter filter = buildSearchFilter(searchInputBox.getText(), defaultFilter, allFilter, fieldsPanel,
defaultFilterIncremental);
list.setFilter(filter);
}
private Filter buildSearchFilter(String basicQuery, Filter defaultFilter, String allFilter, FlowPanel fieldsPanel,
boolean defaultFilterIncremental) {
List<FilterParameter> parameters = new ArrayList<>();
Map<String, FilterParameter> advancedSearchFilters = new HashMap<>();
if (basicQuery != null && basicQuery.trim().length() > 0) {
parameters.add(new BasicSearchFilterParameter(allFilter, basicQuery));
}
if (fieldsPanel != null && fieldsPanel.getParent() != null && fieldsPanel.getParent().isVisible()) {
for (int i = 0; i < fieldsPanel.getWidgetCount(); i++) {
SearchFieldPanel searchAdvancedFieldPanel = (SearchFieldPanel) fieldsPanel.getWidget(i);
String searchFieldId = searchAdvancedFieldPanel.getSearchField().getId();
FilterParameter oldFilterParameter = advancedSearchFilters.get(searchFieldId);
FilterParameter filterParameter = searchAdvancedFieldPanel.getFilter();
if (filterParameter instanceof SimpleFilterParameter) {
SimpleFilterParameter parameter = (SimpleFilterParameter) filterParameter;
if (RodaConstants.AIP_LEVEL.equals(parameter.getName())
&& RodaConstants.NONE_SELECTED_LEVEL.equals(parameter.getValue())) {
filterParameter = null;
}
}
if (filterParameter != null) {
if (oldFilterParameter != null) {
if (oldFilterParameter instanceof OrFiltersParameters) {
List<FilterParameter> filterParameters = ((OrFiltersParameters) oldFilterParameter).getValues();
filterParameters.add(filterParameter);
((OrFiltersParameters) oldFilterParameter).setValues(filterParameters);
advancedSearchFilters.put(searchFieldId, oldFilterParameter);
} else {
List<FilterParameter> filterParameters = new ArrayList<>();
filterParameters.add(oldFilterParameter);
filterParameters.add(filterParameter);
advancedSearchFilters.put(searchFieldId, new OrFiltersParameters(filterParameters));
}
} else {
advancedSearchFilters.put(searchFieldId, filterParameter);
}
}
}
for (FilterParameter value : advancedSearchFilters.values()) {
parameters.add(value);
}
}
Filter filter;
if (defaultFilterIncremental) {
filter = defaultFilter != null ? new Filter(defaultFilter) : new Filter();
filter.add(parameters);
searchPreFilters.setVisible(!filter.getParameters().isEmpty());
} else if (parameters.isEmpty()) {
filter = defaultFilter;
searchPreFilters.setVisible(filter != null && !filter.getParameters().isEmpty());
} else {
filter = new Filter(parameters);
searchPreFilters.setVisible(false);
}
return filter;
}
public String getDropdownSelectedValue() {
return searchInputListBox.getSelectedValue();
}
public boolean setDropdownSelectedValue(String value) {
return setDropdownSelectedValue(value, true);
}
public boolean setDropdownSelectedValue(String value, boolean fire) {
return searchInputListBox.setSelectedValue(value, fire);
}
public void setDropdownLabel(String label) {
searchInputListBox.setLabel(label);
}
public void addDropdownItem(String label, String value) {
searchInputListBox.addItem(label, value);
}
private void showSearchAdvancedPanel() {
searchAdvancedPanel.setVisible(!searchAdvancedPanel.isVisible());
if (searchAdvancedPanel.isVisible()) {
searchAdvancedDisclosureButton.addStyleName("open");
} else {
searchAdvancedDisclosureButton.removeStyleName("open");
}
}
public void addDropdownPopupStyleName(String styleName) {
searchInputListBox.addPopupStyleName(styleName);
}
public void setFieldsPanel(FlowPanel fieldsPanel) {
this.fieldsPanel = fieldsPanel;
searchAdvancedPanel.clear();
searchAdvancedPanel.add(fieldsPanel);
searchAdvancedPanel.add(searchAdvancedPanelButtons);
}
public void setList(AsyncTableCell<?, ?> list) {
this.list = list;
}
public void setDefaultFilter(Filter defaultFilter, boolean incremental) {
this.defaultFilter = defaultFilter;
if (!hidePreFilters) {
drawSearchPreFilters();
}
this.defaultFilterIncremental = incremental;
}
public void setAllFilter(String allFilter) {
this.allFilter = allFilter;
}
public void setVariables(Filter defaultFilter, String allFilter, boolean incremental, AsyncTableCell<?, ?> list,
FlowPanel fieldsPanel) {
setDefaultFilter(defaultFilter, incremental);
setAllFilter(allFilter);
setList(list);
setFieldsPanel(fieldsPanel);
}
public void setDefaultFilterIncremental(boolean incremental) {
this.defaultFilterIncremental = incremental;
}
public boolean isDefaultFilterIncremental() {
return defaultFilterIncremental;
}
public void clearSearchInputBox() {
searchInputBox.setText("");
}
public void setSearchAdvancedFieldOptionsAddVisible(boolean visible) {
searchAdvancedFieldOptionsAdd.setVisible(visible);
}
public void setSearchAdvancedGoEnabled(boolean enabled) {
searchAdvancedGo.setEnabled(enabled);
}
public void addSearchAdvancedFieldAddHandler(ClickHandler handler) {
searchAdvancedFieldOptionsAdd.addClickHandler(handler);
}
public void hidePreFilters() {
searchPreFilters.clear();
searchPreFilters.setVisible(false);
}
@UiHandler("searchAdvancedClean")
void handleSearchAdvancedClean(ClickEvent e) {
JavascriptUtils.cleanAdvancedSearch();
}
@UiHandler("searchAdvancedGo")
void handleSearchAdvancedGo(ClickEvent e) {
doSearch();
}
@Override
public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> handler) {
return addHandler(handler, ValueChangeEvent.getType());
}
protected void onChange() {
ValueChangeEvent.fire(this, searchInputListBox.getSelectedValue());
}
public void addKeyDownEvent(KeyDownHandler handler) {
searchInputBox.addKeyDownHandler(handler);
}
}