/*
* Copyright 2008-2013 Sergey Skladchikov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.geogebra.web.web.gui.advanced.client.ui.widget;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.geogebra.web.html5.gui.inputfield.AutoCompleteTextFieldW;
import org.geogebra.web.html5.main.AppW;
import org.geogebra.web.web.gui.advanced.client.datamodel.ComboBoxDataModel;
import org.geogebra.web.web.gui.advanced.client.datamodel.ListDataModel;
import org.geogebra.web.web.gui.advanced.client.datamodel.ListModelEvent;
import org.geogebra.web.web.gui.advanced.client.datamodel.ListModelListener;
import org.geogebra.web.web.gui.advanced.client.ui.widget.combo.ComboBoxChangeEvent;
import org.geogebra.web.web.gui.advanced.client.ui.widget.combo.DefaultListItemFactory;
import org.geogebra.web.web.gui.advanced.client.ui.widget.combo.DropDownPosition;
import org.geogebra.web.web.gui.advanced.client.ui.widget.combo.ListItemFactory;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.EventTarget;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.HasAllFocusHandlers;
import com.google.gwt.event.dom.client.HasAllKeyHandlers;
import com.google.gwt.event.dom.client.HasChangeHandlers;
import com.google.gwt.event.dom.client.HasClickHandlers;
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.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.event.logical.shared.HasCloseHandlers;
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.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.ToggleButton;
import com.google.gwt.user.client.ui.Widget;
/**
* This is a combo box widget implementation.
*
* @author <a href="mailto:sskladchikov@gmail.com">Sergey Skladchikov</a>
* @param <T>
* model type
* @since 1.2.0
*/
public class ComboBox<T extends ListDataModel> extends TextButtonPanel<String>
implements HasAllFocusHandlers, HasAllKeyHandlers, HasClickHandlers,
ListModelListener, HasChangeHandlers, HasCloseHandlers<PopupPanel> {
/**
* @param app
* application
*/
protected ComboBox(AppW app) {
super(app);
// TODO Auto-generated constructor stub
}
/** a combo box data model */
private ListDataModel model;
/** a list item factory */
private ListItemFactory listItemFactory;
/** a list popup panel */
private ListPopupPanel<T> listPanel;
/** a combo box delegate listener */
private DelegateHandler delegateHandler;
/** a keyboard events listener that switches off default browser handling and replaces it with conponents' */
private ComboBoxKeyboardManager keyboardManager;
/** a flag that is <code>true</code> if any control key is pressed */
private boolean keyPressed;
/**
* Setter for property 'model'.
*
* @param model Value to set for property 'model'.
*/
public void setModel(T model) {
if (model != null && this.model != model) {
if (this.model != null) {
this.model.removeListModelListener(this);
}
this.model = model;
this.model.addListModelListener(this);
prepareSelectedValue();
}
}
/**
* Setter for property 'listItemFactory'.
*
* @param listItemFactory Value to set for property 'listItemFactory'.
*/
public void setListItemFactory(ListItemFactory listItemFactory) {
if (listItemFactory != null) {
this.listItemFactory = listItemFactory;
}
if (isListPanelOpened()) {
getListPanel().prepareList();
}
}
@Override
public HandlerRegistration addBlurHandler(BlurHandler handler) {
return addHandler(handler, BlurEvent.getType());
}
@Override
public HandlerRegistration addFocusHandler(FocusHandler handler) {
return addHandler(handler, FocusEvent.getType());
}
@Override
public HandlerRegistration addKeyUpHandler(KeyUpHandler handler) {
return addHandler(handler, KeyUpEvent.getType());
}
@Override
public HandlerRegistration addKeyDownHandler(KeyDownHandler handler) {
return addHandler(handler, KeyDownEvent.getType());
}
@Override
public HandlerRegistration addKeyPressHandler(KeyPressHandler handler) {
return addHandler(handler, KeyPressEvent.getType());
}
/**
* Note that handlers added by this method will receive
* {@link org.geogebra.web.web.gui.advanced.client.ui.widget.combo.ComboBoxChangeEvent}s.
*
* @param handler the change handler
* @return a handler registration.
*/
@Override
public HandlerRegistration addChangeHandler(ChangeHandler handler) {
return addHandler(handler, ChangeEvent.getType());
}
@Override
public HandlerRegistration addClickHandler(ClickHandler handler) {
return addHandler(handler, ClickEvent.getType());
}
/**
* Getter for property 'model'.
*
* @return Value for property 'model'.
*/
public ListDataModel getModel() {
if (model == null) {
model = new ComboBoxDataModel();
model.addListModelListener(this);
}
return model;
}
/**
* Getter for property 'listItemFactory'.
*
* @return Value for property 'listItemFactory'.
*/
public ListItemFactory getListItemFactory() {
if (listItemFactory == null) {
listItemFactory = new DefaultListItemFactory();
}
return listItemFactory;
}
/**
* This method sets focus on this widget.<p/>
* But note that the combo box is not a focus event sourcer. It siply delegtes this functionality
* to the text box.
*
* @param focus is a flag of focus.
*/
public void setFocus(boolean focus) {
AutoCompleteTextFieldW tfValue = getSelectedValue();
if (isCustomTextAllowed()) {
tfValue.setFocus(focus);
} else {
getChoiceButton().setFocus(focus);
}
}
/**
* This method check the list panel status.
*
* @return <code>true</code> if it's opened.
*/
public boolean isListPanelOpened() {
return !getListPanel().isHidden();
}
/**
* This method returns a value currently displayed in the text box.
*
* @return a text value.
*
* @deprecated use {@link #getValue()} instead.
*/
@Deprecated
public String getText() {
return getSelectedValue().getText();
}
/**
* Gets a number of visible rows.<p/>
* Values <= 0 interpreted as undefined.
*
* @return a visible rows to be displayed without scrolling.
*/
public int getVisibleRows() {
return getListPanel().getVisibleRows();
}
/**
* Sets visible rows number.<p/>
* You can pass a value <= 0. It will mean that this parameter in undefined.
*
* @param visibleRows is a number of rows to be displayed without scrolling.
*/
public void setVisibleRows(int visibleRows) {
getListPanel().setVisibleRows(visibleRows);
}
/**
* Sets an item index that must be displayed on top.<p/>
* If the item is outside the currently visible area the list will be scrolled down
* to this item.
*
* @param index is an index of the item that must be displayed on top of the visible area.
*/
public void setStartItemIndex(int index) {
getListPanel().setStartItemIndex(index);
}
/**
* @return start index
*/
public int getStartItemIndex() {
return getListPanel().getStartItemIndex();
}
/**
* Sets text to the selected value box but doesn't change anything
* in the list of items.
*
* @param text is a text to set.
*
* @deprecated use {@link #setValue(String)} instead.
*/
@Deprecated
public void setText(String text) {
getSelectedValue().setText(text);
}
/**
* This method returns a selected item.
*
* @return is a selected item.
*/
public Object getSelected() {
return getModel().getSelected();
}
/**
* This method returns a selected item index.
*
* @return is a selected item index.
*/
public int getSelectedIndex() {
return getModel().getSelectedIndex();
}
/**
* This method returns a selected item ID.
*
* @return is a selected item ID.
*/
public String getSelectedId() {
return getModel().getSelectedId();
}
/**
* This method sets the selected item ID.
*
* @param id is an item ID to select.
*/
public void setSelectedId(String id) {
getModel().setSelectedId(id);
}
/**
* This method sets the selected item index.
*
* @param index a selected item index.
*/
public void setSelectedIndex(int index) {
getModel().setSelectedIndex(index);
}
/**
* Opens / closes list popup panel by request.
*
* @param opened <code>true</code> means "show".
*/
public void setListPopupOpened(boolean opened) {
if (opened) {
getListPanel().show();
} else {
getListPanel().hide();
}
}
/**
* This method gets a widget that is currently selected in the drop down list.
*
* @return <code>null</code> if the drop down list is collapsed.
*/
public Widget getSelectedWidget() {
if (isListPanelOpened() && getModel().getSelectedIndex() >= 0) {
FlowPanel list = getListPanel().getList();
if (list.getWidgetCount() > getModel().getSelectedIndex()) {
return list.getWidget(getModel().getSelectedIndex());
}
return null;
}
return null;
}
/** {@inheritDoc} */
@Override
public void cleanSelection() {
super.cleanSelection();
getModel().clear();
}
/**
* Gets a highlight row number.<p/>
* Note that sometimes this value is not equal to the selected row.
*
* @return a highlight row number or <code>-1</code> if nothing is highlight.
*/
public int getHighlightRow() {
return getListPanel().getHighlightRow();
}
/**
* Sets a highlight row number and display the row as selected but not actually
* select it.
*
* @param row is a row number to highlight. If it's out of range thus method does nothing.
*/
public void setHighlightRow(int row) {
getListPanel().setHighlightRow(row);
}
/**
* This method gets an actual number of items displayed in the drop down.
*
* @return an item count.
*/
public int getItemCount() {
return getListPanel().getItemCount();
}
/**
* Gets an item by its index<p/>
* If index < 0 or index >= {@link #getItemCount()} it throws an exception.
*
* @param index is an index of the item to get.
* @return a foudn item.
* @throws IndexOutOfBoundsException if index is invalid.
*/
public Widget getItem(int index) {
return getListPanel().getItem(index);
}
/**
* Gets an item index if it's displayed in the drop down list.<p/>
* Otherwise returns <code>-1</code>.
*
* @param item an item that is required to return.
* @return an item index value or <code>-1</code>.
*/
public int getItemIndex(Widget item) {
return getListPanel().getItemIndex(item);
}
/**
* This method shows the drop down list.
*
* @param prepareList forces the list to be prepared (refreshed) before displaying.
*/
public void showList(boolean prepareList) {
getListPanel().show();
if (prepareList) {
getListPanel().prepareList();
}
if (getItemCount() <= 0) {
getListPanel().hide();
}
}
/**
* Moves the cursor up or down.
*
* @param step is a number of items relative to the current cursor position.
*/
public void moveCursor(int step) {
int row = getListPanel().getHighlightRow();
if (step == 0 || row + step < 0 || row + step >= getItemCount()) {
return;
}
row += step;
if (row != getListPanel().getHighlightRow()) {
if (row >= getModel().getCount()) {
row = getModel().getCount() - 1;
}
if (row < 0) {
row = 0;
}
getListPanel().setHighlightRow(row);
Widget item = getListPanel().getList().getWidget(row);
getListPanel().ensureVisible(item);
}
}
/** Hides the drop down list. */
public void hideList() {
getListPanel().hide();
getChoiceButton().setDown(false);
}
/**
* Selects the specified item in the model and in the drop down list.
*
* @param row is a row index to select
*/
public void select(int row) {
getModel().setSelectedIndex(row);
getListPanel().hide();
getSelectedValue().removeStyleName("selected-row");
getChoiceButton().setDown(false);
}
/** {@inheritDoc} */
@Override
public void onModelEvent(ListModelEvent event) {
if (event.getType() == ListModelEvent.ADD_ITEM) {
add(event);
} else if (event.getType() == ListModelEvent.CLEAN) {
clean(event);
} else if (event.getType() == ListModelEvent.REMOVE_ITEM) {
remove(event);
} else if (event.getType() == ListModelEvent.SELECT_ITEM) {
select(event);
}
getListPanel().adjustSize();
}
/**
* Checks whether the lazy rendering option is enabled.
*
* @return a result of check.
*/
public boolean isLazyRenderingEnabled() {
return getListPanel().isLazyRenderingEnabled();
}
/**
* Enables or disables lazy rendering option.
* <p/>
* If this option is enabled the widget displays only several items on
* lazily renders other ones on scroll down.
* <p/>
* By default lazy rendering is disabled. Switch it on for really large
* (over 500 items) lists only.
* <p/>
* Note that <i>lazy rendering</i> is not <i>lazy data loading</i>. The
* second one means that the data is loaded into the model on request where
* as the first option assumes that all necessary data has already been
* loaded and put into the model. If you need <i>lazy loading</i> please
* consider using SuggestionBox
*
* @param lazyRenderingEnabled
* is an option value.
*/
public void setLazyRenderingEnabled(boolean lazyRenderingEnabled) {
getListPanel().setLazyRenderingEnabled(lazyRenderingEnabled);
}
/**
* Gets applied position of the drop down list.
*
* @return a drop down list position value.
*/
public DropDownPosition getDropDownPosition() {
return getListPanel().getDropDownPosition();
}
/**
* Sets applied position of the drop down list.<p/>
* Being set the drop down is immediately applied if the list is opened.
*
* @param dropDownPosition is a drop down list position value.
*/
public void setDropDownPosition(DropDownPosition dropDownPosition) {
getListPanel().setDropDownPosition(dropDownPosition);
}
/**
* Adds a close handler to the popup list of items.
*
* @param handler is a handler to add.
* @return a handler registration.
*/
@Override
public HandlerRegistration addCloseHandler(
CloseHandler<PopupPanel> handler) {
return getListPanel().addCloseHandler(handler);
}
/** Similar to {@link #getText()} */
@Override
public String getValue() {
return getSelectedValue().getText();
}
/** Similar to {@link #setText(String)} and doesn't send any event */
@Override
public void setValue(String value) {
setValue(value, false);
}
/** Similar to {@link #setText(String)} and sends {@code ValueChangeEvent} if {@code fireEvents = true} */
@Override
public void setValue(String value, boolean fireEvents) {
getSelectedValue().setText(value);
if (fireEvents) {
fireEvent(new ValueChangeEvent<String>(value) {
// nothing to implement
});
}
}
/**
* Adds a value change handler to the component that will be invoked only if
* {@link #setValue(String, boolean)} has the second parameter =
* {@code true}.
* <p/>
*
* Note that the widget doesn't fire the event if you don't use the method
* specified above.
*/
@Override
public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> handler) {
return addHandler(handler, ValueChangeEvent.getType());
}
/**
* Adds a new visual item into the drop down list every time when it's added into the data
* model.
*
* @param event is an event containing data about the item.
*/
protected void add(ListModelEvent event) {
if (isListPanelOpened()) {
for (Map.Entry<String, Integer> entry : event.getItemIndexes().entrySet()) {
if (entry.getValue() <= getItemCount()) {
Widget item = getListItemFactory().createWidget(event.getSource().get(entry.getKey()));
item = getListPanel().adoptItemWidget(item);
if (entry.getValue() < getListPanel().getList().getWidgetCount()) {
getListPanel().getList().insert(item, entry.getValue());
} else {
getListPanel().getList().add(item);
}
} else {
getListPanel().prepareList();
if (getItemCount() <= 0) {
getListPanel().hide();
}
}
}
}
}
/**
* This method cleans the drop down list on each data clean.
*
* @param event is a clean event.
*/
protected void clean(ListModelEvent event) {
if (isListPanelOpened()) {
getListPanel().getList().clear();
getListPanel().hide();
}
}
/**
* Removes a visual item from the drop down list if the remove event is received.
*
* @param event is an event that contains data of the removed item.
*/
protected void remove(ListModelEvent event) {
if (isListPanelOpened()) {
for (Map.Entry<String, Integer> entry : event.getItemIndexes().entrySet()) {
if (entry.getValue() < getListPanel().getList().getWidgetCount()) {
getListPanel().remove(getListPanel().getList().getWidget(entry.getValue()));
if (getListPanel().getList().getWidgetCount() <= 0) {
getListPanel().hide();
}
}
}
}
}
/**
* Highlights the visual item in the drop down list if it's selected in the model.
*
* @param event is an event that contains data about selected item.
*/
protected void select(ListModelEvent event) {
if (event.getItemIndex() >= 0) {
if (isListPanelOpened()) {
getListPanel().setHighlightRow(event.getItemIndex());
}
setValue(getListItemFactory().convert(model.getSelected()));
}
}
/**
* Returns <code>true</code> if cursor is moved by a control key.
*
* @return a flag value.
*/
protected boolean isKeyPressed() {
return keyPressed;
}
/**
* Sets the value of the key pressed flag.
*
* @param keyPressed is a key pressed flag value.
*/
protected void setKeyPressed(boolean keyPressed) {
this.keyPressed = keyPressed;
}
/** {@inheritDoc} */
@Override
protected void prepareSelectedValue() {
super.prepareSelectedValue();
getSelectedValue().setText(getListItemFactory().convert(getModel().getSelected()));
}
/** {@inheritDoc} */
@Override
protected void addComponentListeners() {
AutoCompleteTextFieldW value = getSelectedValue();
ToggleButton button = getChoiceButton();
getListPanel().addChangeHandler(getDelegateHandler());
// value.addChangeHandler(getDelegateHandler());
button.addFocusHandler(getDelegateHandler());
value.addFocusHandler(getDelegateHandler());
button.addBlurHandler(getDelegateHandler());
value.addBlurHandler(getDelegateHandler());
// value.addClickHandler(getDelegateHandler());
button.addClickHandler(getDelegateHandler());
value.addKeyUpHandler(getDelegateHandler());
// value.addKeyDownHandler(getDelegateHandler());
value.addKeyPressHandler(getDelegateHandler());
}
/**
* Getter for property 'listPanel'.
*
* @return Value for property 'listPanel'.
*/
protected ListPopupPanel<T> getListPanel() {
if (listPanel == null) {
listPanel = new ListPopupPanel<T>(this);
}
return listPanel;
}
/**
* Getter for property 'delegateHandler'.
*
* @return Value for property 'delegateHandler'.
*/
protected DelegateHandler getDelegateHandler() {
if (delegateHandler == null) {
delegateHandler = new DelegateHandler();
}
return delegateHandler;
}
/**
* This method gets a keybord manager implementation for the component.
*
* @return an instance of the manager.
*/
protected ComboBoxKeyboardManager getKeyboardManager() {
if (keyboardManager == null) {
keyboardManager = new ComboBoxKeyboardManager();
}
return keyboardManager;
}
/** Universal handler that delegates all events handling to custom handlers. */
protected class DelegateHandler implements FocusHandler, BlurHandler, ClickHandler,
ChangeHandler, KeyUpHandler, KeyDownHandler, KeyPressHandler {
/** a list of focused controls */
private Set<Object> focuses;
/** keyboard manager handler registration */
private HandlerRegistration keyboardManagerRegistration;
@Override
public void onBlur(BlurEvent event) {
if (!isFocus()) {
return;
}
if (keyboardManagerRegistration != null) {
keyboardManagerRegistration.removeHandler();
keyboardManagerRegistration = null;
}
Object sender = event.getSource();
getFocuses().remove(sender);
AutoCompleteTextFieldW value = getSelectedValue();
if (sender == value && !isCustomTextAllowed()) {
value.removeStyleName("selected-row");
}
if (!isFocus()) {
fireEvent(event);
}
}
@Override
public void onFocus(FocusEvent event) {
Object sender = event.getSource();
getFocuses().add(sender);
if (keyboardManagerRegistration == null) {
keyboardManagerRegistration = Event.addNativePreviewHandler(getKeyboardManager());
}
AutoCompleteTextFieldW value = getSelectedValue();
if (sender == value) {
if (!isCustomTextAllowed()) {
value.addStyleName("selected-row");
if (isChoiceButtonVisible()) {
getChoiceButton().setFocus(true);
}
}
} else if (sender == null || sender == getListPanel()) { //on drop down list show
Widget widget = getSelectedWidget();
if (widget != null) {
getListPanel().ensureVisible(widget);
}
}
if (focuses.size() == 1) {
fireEvent(event);
}
}
@Override
public void onChange(ChangeEvent event) {
if (event.getSource() == getListPanel()) {
getSelectedValue().setText(getListItemFactory().convert(getModel().getSelected()));
getListPanel().hide();
getSelectedValue().removeStyleName("selected-row");
getChoiceButton().setDown(false);
}
fireEvent(event);
}
@Override
public void onClick(ClickEvent event) {
int count = getModel().getCount();
Object sender = event.getSource();
if (sender instanceof ToggleButton || !isCustomTextAllowed()) {
if (count > 0 && !getListPanel().isShowing()) {
getListPanel().prepareList();
getListPanel().show();
if (getItemCount() <= 0) {
getListPanel().hide();
}
getChoiceButton().setDown(true);
} else {
getListPanel().hide();
getChoiceButton().setDown(false);
}
}
fireEvent(event);
}
@Override
public void onKeyUp(KeyUpEvent event) {
fireEvent(event);
}
@Override
public void onKeyPress(KeyPressEvent event) {
fireEvent(event);
}
@Override
public void onKeyDown(KeyDownEvent event) {
fireEvent(event);
}
/**
* @return set of focuses
*/
protected Set<Object> getFocuses() {
if (focuses == null) {
focuses = new HashSet<Object>();
}
return focuses;
}
/**
* Getter for property 'focus'.
*
* @return Value for property 'focus'.
*/
protected boolean isFocus() {
return getFocuses().size() > 0;
}
}
/**
* This is a keyboard manager implementation developed for the widget.<p/>
* It prevents default browser event handling for system keys like arrow up / down, escape, enter and tab.
* This manager is activated on widget focus and is used for opening / closing the drop down list and
* switching a cursor position in the list.<p/>
* It also supports Shift+Tab combination but skips other modifiers.
*/
protected class ComboBoxKeyboardManager implements Event.NativePreviewHandler {
/** See class docs */
@Override
public void onPreviewNativeEvent(Event.NativePreviewEvent event) {
NativeEvent nativeEvent = event.getNativeEvent();
EventTarget eventTarget = nativeEvent.getEventTarget();
if (!Element.is(eventTarget)) {
return;
}
Element target = Element.as(eventTarget);
int type = event.getTypeInt();
if (type == Event.ONKEYDOWN) {
setKeyPressed(true);
if (DOM.getCaptureElement() != null) {
return;
}
boolean eventTargetsPopup = (target != null)
&& getElement().isOrHasChild(target);
int button = nativeEvent.getKeyCode();
boolean alt = nativeEvent.getAltKey();
boolean ctrl = nativeEvent.getCtrlKey();
boolean shift = nativeEvent.getShiftKey();
boolean hasModifiers = alt || ctrl || shift;
if (eventTargetsPopup && isListPanelOpened()) {
if (button == KeyCodes.KEY_UP && !hasModifiers) {
moveCursor(-1);
cancelAndPrevent(event);
} else if (button == KeyCodes.KEY_DOWN && !hasModifiers) {
moveCursor(1);
cancelAndPrevent(event);
} else if (button == KeyCodes.KEY_ENTER && !hasModifiers) {
if (getEnterAction() == EnterAction.OPEN_DROP_DOWN) {
select(getHighlightRow());
getChoiceButton().setFocus(false);
ChangeEvent changeEvent = new ComboBoxChangeEvent(
getHighlightRow(), ComboBoxChangeEvent.ChangeEventInputDevice.KEYBOARD
);
fireEvent(changeEvent);
cancelAndPrevent(event);
}
setKeyPressed(false);
} else if (button == KeyCodes.KEY_ESCAPE && !hasModifiers) {
hideList();
setKeyPressed(false);
} else if (button == KeyCodes.KEY_TAB && (!hasModifiers || !alt && !ctrl)) {
hideList();
setKeyPressed(false);
}
} else if (eventTargetsPopup && !hasModifiers
&& button == KeyCodes.KEY_ENTER && getModel().getCount() > 0) {
if (getEnterAction() == EnterAction.OPEN_DROP_DOWN) {
showList(true);
}
}
} else if (type == Event.ONKEYUP) {
setKeyPressed(false);
}
}
/**
* This method cancels and prevents default actions of the specified event.<p/>
* It's useful for stupid browsers like Opera.
*
* @param event is an event to cancel and prevent.
*/
protected void cancelAndPrevent(Event.NativePreviewEvent event) {
event.getNativeEvent().preventDefault();
event.cancel();
}
}
}