/* * Ext GWT 2.2.4 - Ext for GWT * Copyright(c) 2007-2010, Ext JS, LLC. * licensing@extjs.com * * http://extjs.com/license */ package com.extjs.gxt.ui.client.widget; import java.util.Arrays; import com.extjs.gxt.ui.client.Style.SelectionMode; import com.extjs.gxt.ui.client.data.ModelData; import com.extjs.gxt.ui.client.event.ComponentEvent; import com.extjs.gxt.ui.client.event.EventType; import com.extjs.gxt.ui.client.event.Events; import com.extjs.gxt.ui.client.event.ListViewEvent; import com.extjs.gxt.ui.client.event.Listener; import com.extjs.gxt.ui.client.store.ListStore; import com.extjs.gxt.ui.client.util.KeyNav; import com.extjs.gxt.ui.client.widget.selection.AbstractStoreSelectionModel; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.user.client.Element; /** * ListView selection model. */ public class ListViewSelectionModel<M extends ModelData> extends AbstractStoreSelectionModel<M> implements Listener<ListViewEvent<M>> { protected boolean enableNavKeys = true; protected KeyNav<ComponentEvent> keyNav = new KeyNav<ComponentEvent>() { @Override public void onDown(ComponentEvent e) { if (isVertical) { onKeyDown(e); } } @Override public void onKeyPress(ComponentEvent ce) { ListViewSelectionModel.this.onKeyPress(ce); } @Override public void onLeft(ComponentEvent e) { if (!isVertical) { onKeyUp(e); } } @Override public void onRight(ComponentEvent e) { if (!isVertical) { onKeyDown(e); } } @Override public void onUp(ComponentEvent e) { if (isVertical) { onKeyUp(e); } } }; protected ListStore<M> listStore; protected ListView<M> listView; private boolean isVertical = true; /** * Binds the list view to the selection model. * * @param listView the list view */ public void bindList(ListView<M> listView) { if (this.listView != null) { this.listView.removeListener(Events.OnMouseDown, this); this.listView.removeListener(Events.OnClick, this); this.listView.removeListener(Events.RowUpdated, this); this.listView.removeListener(Events.Refresh, this); this.listView.removeListener(Events.Render, this); keyNav.bind(null); this.listStore = null; bind(null); } this.listView = listView; if (listView != null) { listView.addListener(Events.OnMouseDown, this); listView.addListener(Events.OnClick, this); listView.addListener(Events.Refresh, this); listView.addListener(Events.RowUpdated, this); listView.addListener(Events.Render, this); keyNav.bind(listView); bind(listView.getStore()); this.listStore = listView.getStore(); } } public void handleEvent(ListViewEvent<M> e) { EventType type = e.getType(); if (type == Events.OnMouseDown) { handleMouseDown(e); } else if (type == Events.OnClick) { handleMouseClick(e); } else if (type == Events.RowUpdated) { onRowUpdated(e); } else if (type == Events.Refresh || type == Events.Render) { refresh(); if (getLastFocused() != null) { listView.onHighlightRow(listStore.indexOf(getLastFocused()), true); } } } /** * Returns true if up and down arrow keys are used for navigation. Else left * and right arrow keys are used. * * @return the isVertical */ public boolean isVertical() { return isVertical; } /** * Sets if up and down arrow keys or left and right arrow keys should be used * (defaults to true). * * @param isVertical the isVertical to set */ public void setVertical(boolean isVertical) { this.isVertical = isVertical; } @SuppressWarnings("unchecked") protected void handleMouseClick(ListViewEvent<M> e) { if (isLocked() || isInput(e.getTarget())) { return; } if (e.getIndex() == -1) { deselectAll(); return; } if (selectionMode == SelectionMode.MULTI) { M sel = listStore.getAt(e.getIndex()); if (e.isControlKey() && isSelected(sel)) { doDeselect(Arrays.asList(sel), false); } else if (e.isControlKey()) { doSelect(Arrays.asList(sel), true, false); listView.focusItem(e.getIndex()); } else if (isSelected(sel) && !e.isShiftKey() && !e.isControlKey() && selected.size() > 1) { doSelect(Arrays.asList(sel), false, false); listView.focusItem(e.getIndex()); } } } @SuppressWarnings("unchecked") protected void handleMouseDown(ListViewEvent<M> e) { if (e.getIndex() == -1 || isLocked() || isInput(e.getTarget())) { return; } if (e.isRightClick()) { if (selectionMode != SelectionMode.SINGLE && isSelected(listStore.getAt(e.getIndex()))) { return; } select(e.getIndex(), false); listView.focusItem(e.getIndex()); } else { M sel = listStore.getAt(e.getIndex()); if (selectionMode == SelectionMode.SIMPLE) { if (!isSelected(sel)) { select(sel, true); listView.focusItem(e.getIndex()); } } else if (selectionMode == SelectionMode.SINGLE) { if (e.isControlKey() && isSelected(sel)) { deselect(sel); } else if (!isSelected(sel)) { select(sel, false); listView.focusItem(e.getIndex()); } } else if (!e.isControlKey()) { if (e.isShiftKey() && lastSelected != null) { int last = listStore.indexOf(lastSelected); int index = e.getIndex(); select(last, index, e.isControlKey()); listView.focusItem(last); } else if (!isSelected(sel)) { doSelect(Arrays.asList(sel), false, false); listView.focusItem(e.getIndex()); } } } } protected boolean isInput(Element target) { String tag = target.getTagName(); return "INPUT".equals(tag) || "TEXTAREA".equals(tag); } protected void onKeyDown(ComponentEvent e) { if (!e.isControlKey() && selected.size() == 0 && getLastFocused() == null) { select(0, false); } else { int idx = listStore.indexOf(getLastFocused()); if (idx >= 0) { if (e.isControlKey() || (e.isShiftKey() && isSelected(listStore.getAt(idx + 1)))) { if (!e.isControlKey()) { deselect(idx); } M lF = listStore.getAt(idx + 1); if (lF != null) { setLastFocused(lF); listView.focusItem(idx + 1); } } else { if (e.isShiftKey() && lastSelected != getLastFocused()) { select(listStore.indexOf(lastSelected), idx + 1, true); listView.focusItem(idx + 1); } else { if (idx + 1 < listStore.getCount()) { select(idx + 1, e.isShiftKey()); listView.focusItem(idx + 1); } } } } } e.preventDefault(); } protected void onKeyPress(ComponentEvent e) { if (lastSelected != null && enableNavKeys) { int kc = e.getKeyCode(); if (kc == KeyCodes.KEY_PAGEUP || kc == KeyCodes.KEY_HOME) { e.stopEvent(); select(0, false); listView.focusItem(0); } else if (kc == KeyCodes.KEY_PAGEDOWN || kc == KeyCodes.KEY_END) { e.stopEvent(); int idx = listStore.indexOf(listStore.getAt(listStore.getCount() - 1)); select(idx, false); listView.focusItem(idx); } } // if space bar is pressed if (e.getKeyCode() == 32) { if (getLastFocused() != null) { if (e.isShiftKey() && lastSelected != null) { int last = listStore.indexOf(lastSelected); int i = listStore.indexOf(getLastFocused()); select(last, i, e.isControlKey()); listView.focusItem(i); } else { if (isSelected(getLastFocused())) { deselect(getLastFocused()); } else { select(getLastFocused(), true); listView.focusItem(listStore.indexOf(getLastFocused())); } } } } } protected void onKeyUp(ComponentEvent e) { int idx = listStore.indexOf(getLastFocused()); if (idx >= 0) { if (e.isControlKey() || (e.isShiftKey() && isSelected(listStore.getAt(idx - 1)))) { if (!e.isControlKey()) { deselect(idx); } M lF = listStore.getAt(idx - 1); if (lF != null) { setLastFocused(lF); listView.focusItem(idx - 1); } } else { if (e.isShiftKey() && lastSelected != getLastFocused()) { select(listStore.indexOf(lastSelected), idx - 1, true); listView.focusItem(idx - 1); } else { if (idx > 0) { select(idx - 1, e.isShiftKey()); listView.focusItem(idx - 1); } } } } e.preventDefault(); } @Override protected void onLastFocusChanged(M oldFocused, M newFocused) { int i; if (oldFocused != null) { i = listStore.indexOf(oldFocused); if (i >= 0) { listView.onHighlightRow(i, false); } } if (newFocused != null) { i = listStore.indexOf(newFocused); if (i >= 0) { listView.onHighlightRow(i, true); } } } protected void onRowUpdated(ListViewEvent<M> ge) { if (isSelected(ge.getModel())) { onSelectChange(ge.getModel(), true); } if (getLastFocused() == ge.getModel()) { setLastFocused(getLastFocused()); } } @Override protected void onSelectChange(M model, boolean select) { listView.onSelectChange(model, select); } }