package org.ovirt.engine.ui.common.widget.editor;
import java.util.ArrayList;
import java.util.List;
import org.ovirt.engine.ui.uicommonweb.HasCleanup;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Overflow;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.dom.client.KeyUpHandler;
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.uibinder.client.UiField;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HasConstrainedValue;
import com.google.gwt.user.client.ui.MenuBar;
import com.google.gwt.user.client.ui.MultiWordSuggestOracle;
import com.google.gwt.user.client.ui.SuggestBox;
import com.google.gwt.user.client.ui.SuggestBox.DefaultSuggestionDisplay;
import com.google.gwt.user.client.ui.SuggestOracle.Suggestion;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.TextBoxBase;
/**
* Base SuggestBox widget that adapts to UiCommon list model items.
*/
public abstract class BaseListModelSuggestBox<T> extends Composite implements
EditorWidget<T, TakesConstrainedValueEditor<T>>, HasConstrainedValue<T>, HasCleanup {
private TakesConstrainedValueEditor<T> editor;
private T value;
@UiField(provided = true)
protected SuggestBox suggestBox;
private ListModelSuggestionDisplay suggestionDisplay;
protected List<HandlerRegistration> handlerRegistrations = new ArrayList<>();
public BaseListModelSuggestBox(MultiWordSuggestOracle suggestOracle) {
this(suggestOracle, 445);
}
public BaseListModelSuggestBox(MultiWordSuggestOracle suggestOracle, int maxSuggestionPanelHeightInPx) {
suggestionDisplay = new ListModelSuggestionDisplay(maxSuggestionPanelHeightInPx);
suggestBox = new SuggestBox(suggestOracle, new TextBox(), suggestionDisplay);
suggestBox.removeStyleName("gwt-SuggestBox"); //$NON-NLS-1$
handlerRegistrations.add(suggestBox.addSelectionHandler(event -> ValueChangeEvent.fire(suggestBox, event.getSelectedItem().getReplacementString())));
}
protected Suggestion getCurrentSelection() {
return suggestionDisplay.getCurrentSelection();
}
protected void hideSuggestions() {
suggestionDisplay.hide();
}
protected boolean isSuggestionListShowing() {
return suggestionDisplay.isSuggestionListShowing();
}
@Override
public TakesConstrainedValueEditor<T> asEditor() {
if (editor == null) {
editor = TakesConstrainedValueEditor.<T> of(this, this, this);
}
return editor;
}
public SuggestBox asSuggestBox() {
return suggestBox;
}
public TextBoxBase asTextBox() {
return asSuggestBox().getTextBox();
}
@Override
public HandlerRegistration addKeyUpHandler(KeyUpHandler handler) {
HandlerRegistration handlerRegistration = asSuggestBox().addKeyUpHandler(handler);
handlerRegistrations.add(handlerRegistration);
return handlerRegistration;
}
@Override
public HandlerRegistration addKeyDownHandler(KeyDownHandler handler) {
HandlerRegistration handlerRegistration = asSuggestBox().addKeyDownHandler(handler);
handlerRegistrations.add(handlerRegistration);
return handlerRegistration;
}
@Override
public HandlerRegistration addKeyPressHandler(KeyPressHandler handler) {
HandlerRegistration handlerRegistration = asSuggestBox().addKeyPressHandler(handler);
handlerRegistrations.add(handlerRegistration);
return handlerRegistration;
}
@Override
public int getTabIndex() {
return asSuggestBox().getTabIndex();
}
@Override
public void setAccessKey(char key) {
asSuggestBox().setAccessKey(key);
}
@Override
public void setFocus(boolean focused) {
asSuggestBox().getValueBox().setFocus(focused);
}
@Override
public void setTabIndex(int index) {
asSuggestBox().setTabIndex(index);
}
@Override
public boolean isEnabled() {
return asTextBox().isEnabled();
}
@Override
public void setEnabled(boolean enabled) {
asTextBox().setEnabled(enabled);
}
public MenuBar getSuggestionMenu() {
return suggestionDisplay.getSuggestionMenu();
}
@Override
public void setValue(T value) {
setValue(value, false);
}
@Override
public void setValue(T value, boolean fireEvents) {
this.value = value;
render(value, fireEvents);
}
public void setAutoHideEnabled(boolean enabled) {
suggestionDisplay.setAutoHideEnabled(enabled);
}
/**
* Renders the value to the suggest box as a String
* @param value the current value
* @param fireEvents if the suggest box should fire events
*/
protected abstract void render(T value, boolean fireEvents);
/**
* Returns the entity representation of the given String which was passed to the suggest box.
* @param value String from the suggest box
* @return the entity representation
* @throws IllegalArgumentException if incorrect value has been passed
*/
protected abstract T asEntity(String value);
protected void scrollSelectedItemIntoView() {
}
@Override
public T getValue() {
return value;
}
@Override
public HandlerRegistration addValueChangeHandler(final ValueChangeHandler<T> handler) {
HandlerRegistration handlerRegistration = asSuggestBox().addValueChangeHandler(event -> {
try {
T value = asEntity(event.getValue());
handler.onValueChange(new ValueChangeEvent<T>(value) {});
} catch (IllegalArgumentException e) {
// ignore - the user entered an incorrect string. Just do not notify the listeners
}
});
handlerRegistrations.add(handlerRegistration);
return handlerRegistration;
}
@Override
public void cleanup() {
for (HandlerRegistration registration : handlerRegistrations) {
registration.removeHandler();
}
}
class ListModelSuggestionDisplay extends DefaultSuggestionDisplay {
public ListModelSuggestionDisplay(int maxSuggestionPanelHeightInPx) {
getPopupPanel().getElement().getStyle().setZIndex(1);
Element popupPanelElement = getPopupPanel().getWidget().getElement();
Style popupPanel = popupPanelElement.getStyle();
popupPanel.setDisplay(Style.Display.BLOCK);
popupPanel.setProperty("height", "auto"); //$NON-NLS-1$ //$NON-NLS-2$
popupPanel.setPropertyPx("maxHeight", maxSuggestionPanelHeightInPx); //$NON-NLS-1$
popupPanel.setOverflowY(Overflow.SCROLL);
popupPanel.setOverflowX(Overflow.HIDDEN);
Style suggestPopupContentStyle = popupPanelElement.getParentElement().getStyle();
suggestPopupContentStyle.setProperty("height", "auto"); //$NON-NLS-1$ //$NON-NLS-2$
suggestPopupContentStyle.setPropertyPx("maxHeight", maxSuggestionPanelHeightInPx); //$NON-NLS-1$
suggestPopupContentStyle.setOverflowX(Overflow.HIDDEN);
suggestPopupContentStyle.setProperty("display", "table"); //$NON-NLS-1$ //$NON-NLS-2$
}
// just to make it public
@Override
public Suggestion getCurrentSelection() {
return super.getCurrentSelection();
}
public void hide() {
getPopupPanel().hide();
}
public void setAutoHideEnabled(boolean enabled) {
getPopupPanel().setAutoHideEnabled(enabled);
}
public MenuBar getSuggestionMenu() {
return super.getSuggestionMenu();
}
@Override
protected void moveSelectionUp() {
super.moveSelectionUp();
scrollSelectedItemIntoView();
}
@Override
protected void moveSelectionDown() {
super.moveSelectionDown();
scrollSelectedItemIntoView();
}
}
}