/**
* 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.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.DateIntervalFilterParameter;
import org.roda.core.data.v2.index.filter.FilterParameter;
import org.roda.core.data.v2.index.filter.LongRangeFilterParameter;
import org.roda.core.data.v2.index.filter.SimpleFilterParameter;
import org.roda.wui.client.common.utils.ListboxUtils;
import org.roda.wui.client.common.utils.Tree;
import org.roda.wui.common.client.ClientLogger;
import org.roda.wui.common.client.tools.Humanize;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickHandler;
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.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.datepicker.client.DateBox;
import com.google.gwt.user.datepicker.client.DateBox.DefaultFormat;
import config.i18n.client.ClientMessages;
public class SearchFieldPanel extends Composite implements HasValueChangeHandlers<String> {
private static final ClientMessages messages = GWT.create(ClientMessages.class);
@SuppressWarnings("unused")
private ClientLogger logger = new ClientLogger(getClass().getName());
private FlowPanel panel;
private FlowPanel leftPanel;
private FlowPanel inputPanel;
private Button remove = new Button("<i class=\"fa fa-close\"></i>");
private Label duplicateWarning;
private SearchField searchField;
// Simple search field
private Label fieldLabel;
private ListBox fieldBox;
// Complex search field
private ListBox searchAdvancedFields;
private Map<String, SearchField> searchFields;
// Text
private TextBox inputText;
// Date
private DateBox inputDateBox;
// Date interval
private DateBox inputDateBoxFrom;
private DateBox inputDateBoxTo;
// Numeric
private TextBox inputNumeric;
// Numeric interval
private TextBox inputNumericFrom;
private TextBox inputNumericTo;
// Storage
private TextBox inputStorageSizeFrom;
private TextBox inputStorageSizeTo;
private ListBox inputStorageSizeList;
// Boolean
private CheckBox inputCheckBox;
// Suggestion
private SearchSuggestBox<?> inputSearchSuggestBox = null;
// controlled
private ListBox inputControlled;
public SearchFieldPanel() {
panel = new FlowPanel();
leftPanel = new FlowPanel();
inputPanel = new FlowPanel();
fieldLabel = new Label();
fieldBox = new ListBox();
searchAdvancedFields = new ListBox();
duplicateWarning = new Label();
DefaultFormat dateFormat = new DateBox.DefaultFormat(DateTimeFormat.getFormat("yyyy-MM-dd"));
inputText = new TextBox();
inputText.getElement().setAttribute("title", "input text box");
inputDateBox = new DateBox();
inputDateBox.setFormat(dateFormat);
inputDateBox.getDatePicker().setYearAndMonthDropdownVisible(true);
inputDateBox.getDatePicker().setYearArrowsVisible(true);
inputDateBox.setFireNullValues(true);
inputDateBox.getElement().setPropertyString("placeholder", messages.searchFieldDatePlaceHolder());
inputDateBox.getElement().setAttribute("title", "input date box");
inputDateBoxFrom = new DateBox();
inputDateBoxFrom.setFormat(dateFormat);
inputDateBox.getDatePicker().setYearAndMonthDropdownVisible(true);
inputDateBoxFrom.getDatePicker().setYearArrowsVisible(true);
inputDateBoxFrom.setFireNullValues(true);
inputDateBoxFrom.getElement().setPropertyString("placeholder", messages.searchFieldDateFromPlaceHolder());
inputDateBoxFrom.getElement().setAttribute("title", "input date box from");
inputDateBoxTo = new DateBox();
inputDateBoxTo.setFormat(dateFormat);
inputDateBox.getDatePicker().setYearAndMonthDropdownVisible(true);
inputDateBoxTo.getDatePicker().setYearArrowsVisible(true);
inputDateBoxTo.setFireNullValues(true);
inputDateBoxTo.getElement().setPropertyString("placeholder", messages.searchFieldDateToPlaceHolder());
inputDateBoxTo.getElement().setAttribute("title", "input date box to");
inputNumeric = new TextBox();
inputNumeric.getElement().setPropertyString("placeholder", messages.searchFieldNumericPlaceHolder());
inputNumeric.getElement().setAttribute("type", "number");
inputNumeric.getElement().setAttribute("title", "input numeric box");
inputNumericFrom = new TextBox();
inputNumericFrom.getElement().setPropertyString("placeholder", messages.searchFieldNumericFromPlaceHolder());
inputNumericFrom.getElement().setAttribute("type", "number");
inputNumericFrom.getElement().setAttribute("title", "input numeric box from");
inputNumericTo = new TextBox();
inputNumericTo.getElement().setPropertyString("placeholder", messages.searchFieldNumericToPlaceHolder());
inputNumericTo.getElement().setAttribute("type", "number");
inputNumericTo.getElement().setAttribute("title", "input numeric box from to");
inputStorageSizeFrom = new TextBox();
inputStorageSizeFrom.getElement().setPropertyString("placeholder", messages.searchFieldNumericFromPlaceHolder());
inputStorageSizeFrom.getElement().setAttribute("type", "number");
inputStorageSizeFrom.getElement().setAttribute("title", "input storage size from");
inputStorageSizeTo = new TextBox();
inputStorageSizeTo.getElement().setPropertyString("placeholder", messages.searchFieldNumericToPlaceHolder());
inputStorageSizeTo.getElement().setAttribute("type", "number");
inputStorageSizeTo.getElement().setAttribute("title", "input storage size to");
inputStorageSizeList = new ListBox();
for (String unit : Humanize.UNITS) {
inputStorageSizeList.addItem(unit, unit);
}
inputStorageSizeList.getElement().setAttribute("title", "input storage size list");
inputCheckBox = new CheckBox();
inputCheckBox.getElement().setAttribute("title", "input checkbox");
inputControlled = new ListBox();
inputControlled.getElement().setAttribute("title", "input controlled");
panel.add(leftPanel);
initWidget(panel);
searchAdvancedFields.addChangeHandler(new ChangeHandler() {
@Override
public void onChange(ChangeEvent event) {
listBoxSearchField(searchAdvancedFields.getSelectedValue());
SearchFieldPanel.this.onChange();
}
});
panel.addStyleName("search-field");
leftPanel.addStyleName("search-field-left-panel");
inputPanel.addStyleName("search-field-input-panel");
inputPanel.addStyleName("full_width");
remove.addStyleName("search-field-remove");
fieldLabel.addStyleName("search-field-label");
fieldBox.addStyleName("form-listbox");
searchAdvancedFields.addStyleName("form-listbox");
duplicateWarning.addStyleName("search-field-warning-label");
duplicateWarning.setVisible(false);
inputText.addStyleName("form-textbox");
inputDateBox.addStyleName("form-textbox form-textbox-small");
inputDateBoxFrom.addStyleName("form-textbox form-textbox-small");
inputDateBoxTo.addStyleName("form-textbox form-textbox-small");
inputNumeric.addStyleName("form-textbox form-textbox-small");
inputNumericFrom.addStyleName("form-textbox form-textbox-small");
inputNumericTo.addStyleName("form-textbox form-textbox-small");
inputStorageSizeFrom.addStyleName("form-textbox form-textbox-small");
inputStorageSizeTo.addStyleName("form-textbox form-textbox-small");
inputStorageSizeList.addStyleName("form-listbox");
inputCheckBox.addStyleName("form-checkbox");
inputControlled.addStyleName("form-controlled");
}
public SearchField getSearchField() {
return searchField;
}
public void setSearchField(SearchField searchField) {
this.searchField = searchField;
if (searchField.getTerms() != null) {
for (Tree<String> term : searchField.getTerms().getChildren()) {
inputControlled.addItem(term.getLabel(), term.getValue());
}
// TODO add terms to listbox
}
}
public void setSearchAdvancedFields(ListBox searchAdvancedFieldOptions) {
ListboxUtils.copyValues(searchAdvancedFieldOptions, searchAdvancedFields);
}
public void setSearchFields(Map<String, SearchField> searchFields) {
this.searchFields = searchFields;
}
public void selectSearchField(String field) {
ListboxUtils.select(searchAdvancedFields, field);
listBoxSearchField(field);
}
public void selectFirstSearchField() {
if (searchAdvancedFields.getItemCount() > 0) {
listBoxSearchField(searchAdvancedFields.getValue(0));
}
}
public String getFirstSearchField() {
String searchField = null;
if (searchAdvancedFields.getItemCount() > 0) {
searchField = searchAdvancedFields.getValue(0);
}
return searchField;
}
public ListBox getAdvancedFieldBox() {
return searchAdvancedFields;
}
public void addRemoveClickHandler(ClickHandler clickHandler) {
remove.addClickHandler(clickHandler);
}
public String getField() {
return searchAdvancedFields.getSelectedValue();
}
public FilterParameter getFilter() {
FilterParameter filterParameter = null;
String type = searchField.getType();
List<String> searchFields = searchField.getSearchFields();
if (searchFields != null && !searchFields.isEmpty()) {
String field = searchFields.get(0);
if (type.equals(RodaConstants.SEARCH_FIELD_TYPE_DATE) && dateValid(inputDateBox)) {
filterParameter = new SimpleFilterParameter(field, inputDateBox.getValue().toString());
} else if (type.equals(RodaConstants.SEARCH_FIELD_TYPE_DATE_INTERVAL)
&& dateIntervalValid(inputDateBoxFrom, inputDateBoxTo) && searchFields.size() >= 2) {
String fieldTo = searchField.getSearchFields().get(1);
filterParameter = new DateIntervalFilterParameter(field, fieldTo, inputDateBoxFrom.getValue(),
inputDateBoxTo.getValue());
} else if (type.equals(RodaConstants.SEARCH_FIELD_TYPE_DATE_INTERVAL)
&& dateIntervalValid(inputDateBoxFrom, inputDateBoxTo)) {
filterParameter = new DateIntervalFilterParameter(field, field, inputDateBoxFrom.getValue(),
inputDateBoxTo.getValue());
} else if (type.equals(RodaConstants.SEARCH_FIELD_TYPE_NUMERIC) && valid(inputNumeric)) {
filterParameter = new BasicSearchFilterParameter(field, inputNumeric.getValue());
} else if (type.equals(RodaConstants.SEARCH_FIELD_TYPE_NUMERIC_INTERVAL)
&& intervalValid(inputNumericFrom, inputNumericTo)) {
filterParameter = new LongRangeFilterParameter(field, Long.valueOf(inputNumericFrom.getValue()),
Long.valueOf(inputNumericTo.getValue()));
} else if (type.equals(RodaConstants.SEARCH_FIELD_TYPE_STORAGE)
&& intervalValid(inputStorageSizeFrom, inputStorageSizeTo)) {
filterParameter = new LongRangeFilterParameter(field,
Humanize.parseFileSize(inputStorageSizeFrom.getValue(), inputStorageSizeList.getSelectedValue()),
Humanize.parseFileSize(inputStorageSizeTo.getValue(), inputStorageSizeList.getSelectedValue()));
} else if (type.equals(RodaConstants.SEARCH_FIELD_TYPE_BOOLEAN) && valid(inputCheckBox)) {
filterParameter = new SimpleFilterParameter(field, Boolean.toString(inputCheckBox.getValue()));
} else if (type.equals(RodaConstants.SEARCH_FIELD_TYPE_SUGGEST) && valid(inputSearchSuggestBox)) {
filterParameter = new SimpleFilterParameter(
inputSearchSuggestBox.isAllowPartial() ? field + RodaConstants.INDEX_SEARCH_SUFFIX : field,
inputSearchSuggestBox.getValue());
} else if (type.equals(RodaConstants.SEARCH_FIELD_TYPE_CONTROLLED)) {
filterParameter = new SimpleFilterParameter(field, inputControlled.getSelectedValue());
} else if (valid(inputText)) {
filterParameter = new BasicSearchFilterParameter(field, inputText.getValue());
}
}
return filterParameter;
}
public void listBoxSearchField(String field) {
SearchField searchField = searchFields.get(field);
setSearchField(searchField);
leftPanel.clear();
leftPanel.add(searchAdvancedFields);
leftPanel.add(inputPanel);
setInputPanel(searchField.getType());
panel.add(remove);
panel.add(duplicateWarning);
panel.removeStyleName("full_width");
}
public void simpleSearchField(String field, String label, String type, Tree<String> terms) {
List<String> searchFields = new ArrayList<>();
searchFields.add(field);
setSearchField(new SearchField(field, searchFields, label, type, terms));
fieldLabel.setText(label);
leftPanel.clear();
leftPanel.add(fieldBox);
leftPanel.add(inputPanel);
setInputPanel(type);
panel.add(remove);
panel.removeStyleName("full_width");
}
private void setInputPanel(String type) {
inputPanel.clear();
inputPanel.removeStyleName("full_width");
if (type.equals(RodaConstants.SEARCH_FIELD_TYPE_DATE)) {
inputPanel.add(inputDateBox);
} else if (type.equals(RodaConstants.SEARCH_FIELD_TYPE_DATE_INTERVAL)) {
inputPanel.add(inputDateBoxFrom);
inputPanel.add(inputDateBoxTo);
} else if (type.equals(RodaConstants.SEARCH_FIELD_TYPE_NUMERIC)) {
inputPanel.add(inputNumeric);
} else if (type.equals(RodaConstants.SEARCH_FIELD_TYPE_NUMERIC_INTERVAL)) {
inputPanel.add(inputNumericFrom);
inputPanel.add(inputNumericTo);
} else if (type.equals(RodaConstants.SEARCH_FIELD_TYPE_STORAGE)) {
inputPanel.add(inputStorageSizeFrom);
inputPanel.add(inputStorageSizeTo);
inputPanel.add(inputStorageSizeList);
} else if (type.equals(RodaConstants.SEARCH_FIELD_TYPE_BOOLEAN)) {
inputPanel.add(inputCheckBox);
} else if (type.equals(RodaConstants.SEARCH_FIELD_TYPE_SUGGEST)) {
} else if (type.equals(RodaConstants.SEARCH_FIELD_TYPE_CONTROLLED)) {
inputPanel.add(inputControlled);
} else {
inputPanel.add(inputText);
inputPanel.addStyleName("full_width");
}
}
public void addInputSearchSuggestBox(SearchSuggestBox<?> searchSuggestBox) {
this.inputSearchSuggestBox = searchSuggestBox;
inputPanel.add(searchSuggestBox);
inputSearchSuggestBox.addStyleName("form-textbox");
inputPanel.addStyleName("full_width");
}
private boolean dateIntervalValid(DateBox inputFrom, DateBox inputTo) {
if (inputFrom.getValue() != null && inputTo.getValue() != null) {
return true;
}
if (inputFrom.getValue() != null && inputTo.getTextBox().getText().isEmpty()) {
return true;
}
if (inputFrom.getTextBox().getText().isEmpty() && inputTo.getValue() != null) {
return true;
}
return false;
}
private boolean dateValid(DateBox input) {
return input.getValue() != null;
}
private boolean valid(TextBox input) {
return !input.getValue().isEmpty();
}
private boolean valid(SearchSuggestBox<?> input) {
return !input.getValue().isEmpty();
}
private boolean valid(CheckBox input) {
return input.getValue();
}
private boolean intervalValid(TextBox inputFrom, TextBox inputTo) {
try {
if (!inputFrom.getValue().isEmpty() && !inputTo.getValue().isEmpty()) {
return true;
}
if (!inputFrom.getValue().isEmpty() || !inputTo.getValue().isEmpty()) {
return true;
}
} catch (Exception e) {
// do nothing
}
return false;
}
@Override
public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> handler) {
return addHandler(handler, ValueChangeEvent.getType());
}
public HandlerRegistration addListBoxChangeHandler(ChangeHandler handler) {
return searchAdvancedFields.addChangeHandler(handler);
}
protected void onChange() {
ValueChangeEvent.fire(this, searchField.getId());
}
public void setWarningVisible(boolean visible) {
setWarningVisible(visible, null);
}
public void setWarningVisible(boolean visible, String field) {
duplicateWarning.setVisible(visible);
if (visible) {
duplicateWarning.setText(messages.searchDuplicateWarningMessage(field));
duplicateWarning.getElement().getStyle().setMarginLeft(searchAdvancedFields.getOffsetWidth() + 2, Unit.PX);
panel.removeStyleName("search-field");
panel.addStyleName("search-field-warning");
} else {
panel.removeStyleName("search-field-warning");
panel.addStyleName("search-field");
}
}
}