com.extjs.gxt.ui.client.widget.grid.GridSelectionModel.java Source code

Java tutorial

Introduction

Here is the source code for com.extjs.gxt.ui.client.widget.grid.GridSelectionModel.java

Source

/*
 * Sencha GXT 2.3.1 - Sencha for GWT
 * Copyright(c) 2007-2013, Sencha, Inc.
 * licensing@sencha.com
 * 
 * http://www.sencha.com/products/gxt/license/
 */
package com.extjs.gxt.ui.client.widget.grid;

import java.util.Arrays;

import com.extjs.gxt.ui.client.GXT;
import com.extjs.gxt.ui.client.Style.SelectionMode;
import com.extjs.gxt.ui.client.aria.FocusFrame;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.event.BaseEvent;
import com.extjs.gxt.ui.client.event.ColumnModelEvent;
import com.extjs.gxt.ui.client.event.DomEvent;
import com.extjs.gxt.ui.client.event.EventType;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.GridEvent;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.store.Store;
import com.extjs.gxt.ui.client.util.KeyNav;
import com.extjs.gxt.ui.client.widget.grid.ColumnHeader.Head;
import com.extjs.gxt.ui.client.widget.selection.AbstractStoreSelectionModel;
import com.google.gwt.dom.client.NodeList;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.user.client.Element;

/**
 * Grid selection model.
 * 
 * <dl>
 * <dt>Inherited Events:</dt>
 * <dd>AbstractStoreSelectionModel BeforeSelect</dd>
 * <dd>AbstractStoreSelectionModel SelectionChange</dd>
 * </dl>
 */
@SuppressWarnings("rawtypes")
public class GridSelectionModel<M extends ModelData> extends AbstractStoreSelectionModel<M>
        implements Listener<BaseEvent> {

    public static class Callback {

        private GridSelectionModel sm;

        public Callback(GridSelectionModel sm) {
            this.sm = sm;
        }

        public boolean isSelectable(int row, int cell, boolean acceptsNav) {
            return sm.isSelectable(row, cell, acceptsNav);
        }
    }

    public static class Cell {
        public int cell;
        public int row;

        public Cell(int row, int cell) {
            this.row = row;
            this.cell = cell;
        }

    }

    protected boolean enableNavKeys = true;
    protected Grid<M> grid;
    protected boolean grouped = false;
    protected GroupingView groupingView;
    protected KeyNav<GridEvent<M>> keyNav = new KeyNav<GridEvent<M>>() {

        @Override
        public void onDown(GridEvent<M> e) {
            onKeyDown(e);
        }

        @Override
        public void onKeyPress(GridEvent<M> ce) {
            GridSelectionModel.this.onKeyPress(ce);
        }

        @Override
        public void onLeft(GridEvent<M> ce) {
            onKeyLeft(ce);
        }

        @Override
        public void onRight(GridEvent<M> ce) {
            onKeyRight(ce);
        }

        @Override
        public void onUp(GridEvent<M> e) {
            onKeyUp(e);
        }

    };
    protected ListStore<M> listStore;
    protected Element selectedGroup;
    protected Head selectedHeader;

    private Callback callback = new Callback(this);
    private boolean moveEditorOnEnter;

    @SuppressWarnings("unchecked")
    @Override
    public void bind(Store store) {
        super.bind(store);
        if (store instanceof ListStore) {
            listStore = (ListStore<M>) store;
        } else {
            listStore = null;
        }
    }

    @SuppressWarnings("unchecked")
    public void bindGrid(Grid grid) {
        if (this.grid != null) {
            this.grid.removeListener(Events.RowMouseDown, this);
            this.grid.removeListener(Events.RowClick, this);
            this.grid.removeListener(Events.ContextMenu, this);
            this.grid.removeListener(Events.ViewReady, this);
            this.grid.getView().removeListener(Events.RowUpdated, this);
            this.grid.getView().removeListener(Events.Refresh, this);
            this.grid.getColumnModel().removeListener(Events.HiddenChange, this);
            keyNav.bind(null);
            bind(null);
        }
        this.grid = grid;
        if (grid != null) {
            grid.addListener(Events.RowMouseDown, this);
            grid.addListener(Events.RowClick, this);
            grid.addListener(Events.ContextMenu, this);
            grid.addListener(Events.ViewReady, this);
            grid.getView().addListener(Events.RowUpdated, this);
            grid.getView().addListener(Events.Refresh, this);
            grid.getColumnModel().addListener(Events.HiddenChange, this);
            keyNav.bind(grid);
            bind(grid.getStore());
            grouped = grid.getView() instanceof GroupingView;
            if (grouped)
                groupingView = (GroupingView) grid.getView();
        }
    }

    @SuppressWarnings("unchecked")
    public void handleEvent(BaseEvent e) {
        EventType type = e.getType();
        if (type == Events.RowMouseDown) {
            handleMouseDown((GridEvent) e);
        } else if (type == Events.RowClick) {
            handleMouseClick((GridEvent) e);
        } else if (type == Events.RowUpdated) {
            onRowUpdated((GridEvent) e);
        } else if (type == Events.Refresh || type == Events.ViewReady) {
            refresh();
            if (getLastFocused() != null) {
                grid.getView().onHighlightRow(listStore.indexOf(getLastFocused()), true);
            }
        } else if (type == Events.HiddenChange) {
            handleColumnHidden((ColumnModelEvent) e);
        }
    }

    /**
     * Returns true of the editor moves on enter.
     * 
     * @return true if editor moves on enter
     */
    public boolean isMoveEditorOnEnter() {
        return moveEditorOnEnter;
    }

    public void onEditorKey(DomEvent e) {
        int k = e.getKeyCode();
        Cell newCell = null;
        CellEditor editor = grid.editSupport.getActiveEditor();
        switch (k) {
        case KeyCodes.KEY_ENTER:
        case KeyCodes.KEY_TAB:
            e.stopEvent();
            if (editor != null) {
                editor.completeEdit();
            }
            if ((k == KeyCodes.KEY_ENTER && moveEditorOnEnter) || k == KeyCodes.KEY_TAB) {
                if (e.isShiftKey()) {
                    newCell = grid.walkCells(editor.row, editor.col - 1, -1, callback, true);
                } else {
                    newCell = grid.walkCells(editor.row, editor.col + 1, 1, callback, true);
                }
            }
            break;
        case KeyCodes.KEY_ESCAPE:
            if (editor != null) {
                editor.cancelEdit();
            }
            break;
        }
        if (newCell != null) {
            grid.editSupport.startEditing(newCell.row, newCell.cell);
        } else {
            if ((k == KeyCodes.KEY_ENTER || k == KeyCodes.KEY_TAB || k == KeyCodes.KEY_ESCAPE) && editor != null) {
                grid.getView().focusCell(editor.row, editor.col, false);
            }
        }
    }

    /**
     * Selects the next row.
     * 
     * @param keepexisting true to keep existing selections
     */
    public void selectNext(boolean keepexisting) {
        if (hasNext()) {
            int idx = listStore.indexOf(lastSelected) + 1;
            select(idx, keepexisting);
            grid.getView().focusRow(idx);
        }
    }

    /**
     * Selects the previous row.
     * 
     * @param keepexisting true to keep existing selections
     */
    public void selectPrevious(boolean keepexisting) {
        if (hasPrevious()) {
            int idx = listStore.indexOf(lastSelected) - 1;
            select(idx, keepexisting);
            grid.getView().focusRow(idx);
        }
    }

    /**
     * Set this to true to move the editor to the next editable cell on pressing
     * enter.
     * 
     * @param moveEditorOnEnter true to move the editor on pressing enter.
     */
    public void setMoveEditorOnEnter(boolean moveEditorOnEnter) {
        this.moveEditorOnEnter = moveEditorOnEnter;
    }

    protected void handleColumnHidden(ColumnModelEvent e) {
        ColumnHeader header = grid.getView().getHeader();
        if (header != null) {
            int col = e.getColIndex();
            Head h = header.getHead(col);
            if (h == selectedHeader) {
                selectedHeader = null;
            }
        }
    }

    @SuppressWarnings("unchecked")
    protected void handleMouseClick(GridEvent<M> e) {
        if (isLocked() || isInput(e.getTarget())) {
            return;
        }
        if (e.getRowIndex() == -1) {
            deselectAll();
            return;
        }
        if (selectionMode == SelectionMode.MULTI) {
            M sel = listStore.getAt(e.getRowIndex());
            if (e.isControlKey() && isSelected(sel)) {
                doDeselect(Arrays.asList(sel), false);
            } else if (e.isControlKey()) {
                doSelect(Arrays.asList(sel), true, false);
                grid.getView().focusCell(e.getRowIndex(), e.getColIndex(), false);
            } else if (isSelected(sel) && !e.isShiftKey() && !e.isControlKey() && selected.size() > 1) {
                doSelect(Arrays.asList(sel), false, false);
                grid.getView().focusCell(e.getRowIndex(), e.getColIndex(), false);
            }
        }

    }

    @SuppressWarnings("unchecked")
    protected void handleMouseDown(GridEvent<M> e) {
        if (e.getRowIndex() == -1 || isLocked() || isInput(e.getTarget())) {
            return;
        }
        if (e.isRightClick()) {
            if (selectionMode != SelectionMode.SINGLE && isSelected(listStore.getAt(e.getRowIndex()))) {
                return;
            }
            select(e.getRowIndex(), false);
            grid.getView().focusCell(e.getRowIndex(), e.getColIndex(), false);
        } else {
            M sel = listStore.getAt(e.getRowIndex());
            if (selectionMode == SelectionMode.SIMPLE) {
                if (!isSelected(sel)) {
                    select(sel, true);
                    grid.getView().focusCell(e.getRowIndex(), e.getColIndex(), false);
                }

            } else if (selectionMode == SelectionMode.SINGLE) {
                if (e.isControlKey() && isSelected(sel)) {
                    deselect(sel);
                } else if (!isSelected(sel)) {
                    select(sel, false);
                    grid.getView().focusCell(e.getRowIndex(), e.getColIndex(), false);
                }
            } else if (!e.isControlKey()) {
                if (e.isShiftKey() && lastSelected != null) {
                    int last = listStore.indexOf(lastSelected);
                    int index = e.getRowIndex();
                    select(last, index, e.isControlKey());
                    grid.getView().focusCell(index, e.getColIndex(), false);
                } else if (!isSelected(sel)) {
                    doSelect(Arrays.asList(sel), false, false);
                    grid.getView().focusCell(e.getRowIndex(), e.getColIndex(), false);
                }
            }
        }
    }

    protected boolean hasNext() {
        return lastSelected != null && listStore.indexOf(lastSelected) < (listStore.getCount() - 1);
    }

    protected boolean hasPrevious() {
        return lastSelected != null && listStore.indexOf(lastSelected) > 0;
    }

    protected boolean isInput(Element target) {
        String tag = target.getTagName();
        return "input".equalsIgnoreCase(tag) || "textarea".equalsIgnoreCase(tag);
    }

    protected boolean isSelectable(int row, int cell, boolean acceptsNav) {
        if (acceptsNav) {
            return !grid.getColumnModel().isHidden(cell) && grid.getColumnModel().isCellEditable(cell);
        } else {
            return !grid.getColumnModel().isHidden(cell);
        }
    }

    protected void onKeyDown(GridEvent<M> e) {
        if (GXT.isFocusManagerEnabled()) {
            if (selectedGroup == null && (selectedHeader != null || selected.size() == 0)) {
                e.cancelBubble();
                if (e.isAltKey()) {
                    grid.getView().getHeader().showColumnMenu(selectedHeader.column);
                    return;
                }
                if (selectedHeader != null) {
                    selectedHeader.deactivate();
                }
                select(0, false);
                return;
            }
            if (grouped) {
                GroupingView view = (GroupingView) grid.getView();
                NodeList<Element> groups = view.getGroups().cast();
                int gc = view.getGroups().getLength();

                if (selectedGroup != null) {
                    int gindex = indexOf(groups, selectedGroup);
                    if (!view.isExpanded(selectedGroup)) {
                        if (gindex < gc - 1) {
                            view.onGroupSelect(selectedGroup, false);
                            selectedGroup = groups.getItem(gindex + 1);
                            view.onGroupSelect(selectedGroup, true);
                        }
                        return;
                    }
                    view.onGroupSelect(selectedGroup, false);
                    Element r = view.getGroupRow(selectedGroup, 0).cast();

                    selectedGroup = null;

                    if (r != null) {
                        int idx = view.findRowIndex(r);
                        select(idx, false);
                        view.focusRow(idx);
                        return;
                    }
                }
                if (lastSelected != null) {
                    Element row = view.getRow(lastSelected).cast();
                    Element group = view.findGroup(row).cast();

                    int totalGroups = groups.getLength();
                    int groupIndex = indexOf(groups, group);

                    NodeList<Element> groupRows = group.getChildNodes().getItem(1).getChildNodes().cast();

                    int rowsInGroup = group.getChildNodes().getItem(1).getChildNodes().getLength();
                    int rowInGroupIndex = indexOf(groupRows, row);
                    if (rowInGroupIndex == rowsInGroup - 1) {
                        if (groupIndex < totalGroups - 1) {
                            deselectAll();
                            selectedGroup = groups.getItem(groupIndex + 1);
                            view.onGroupSelect(selectedGroup, true);
                            return;

                        }
                    }
                }
            }
        }
        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);
                        grid.getView().focusCell(idx + 1, 0, false);
                    }

                } else {
                    if (e.isShiftKey() && lastSelected != getLastFocused()) {
                        select(listStore.indexOf(lastSelected), idx + 1, true);
                        grid.getView().focusCell(idx + 1, 0, false);
                    } else {
                        if (idx + 1 < listStore.getCount()) {
                            selectNext(e.isShiftKey());
                            grid.getView().focusCell(idx + 1, 0, false);
                        }
                    }
                }
            }
        }

        e.preventDefault();
    }

    protected void onKeyLeft(GridEvent<M> ce) {
        if (GXT.isFocusManagerEnabled() && selectedHeader != null) {
            ColumnHeader ch = grid.getView().getHeader();
            int idx = ch.indexOf(selectedHeader) - 1;
            ColumnConfig config = grid.getColumnModel().getColumn(idx);
            while (config != null) {
                if (!config.isHidden()) {
                    Head h = getHead(idx, false);
                    selectedHeader = h;
                    grid.getView().getHeader().selectHeader(idx);
                    break;
                } else {
                    idx--;
                    config = grid.getColumnModel().getColumn(idx);
                }
            }
        }
        if (GXT.isFocusManagerEnabled() && selectedGroup != null) {
            groupingView.toggleGroup(selectedGroup, false);
        }
    }

    @SuppressWarnings("unchecked")
    protected void onKeyPress(GridEvent<M> e) {
        int kc = e.getKeyCode();
        if (GXT.isFocusManagerEnabled()) {
            if (selectedHeader != null) {
                if (kc == KeyCodes.KEY_ENTER) {
                    grid.getView().onHeaderClick((Grid) grid, grid.getColumnModel().indexOf(selectedHeader.config));
                    return;
                } else if (kc == 32) {
                    ColumnHeader ch = grid.getView().getHeader();
                    int idx = ch.indexOf(selectedHeader);
                    String id = grid.getColumnModel().getColumnId(idx);
                    if (id == null || !id.equals("checker")) {
                        grid.getView().getHeader().showColumnMenu(idx);
                    }
                    return;
                }
            }
        }
        if (lastSelected != null && enableNavKeys) {
            if (kc == KeyCodes.KEY_PAGEUP) {
                e.stopEvent();
                select(0, false);
                grid.getView().focusRow(0);
            } else if (kc == KeyCodes.KEY_PAGEDOWN) {
                e.stopEvent();
                int idx = listStore.indexOf(listStore.getAt(listStore.getCount() - 1));
                select(idx, false);
                grid.getView().focusRow(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());
                    grid.getView().focusCell(i, 0, false);
                } else {
                    if (isSelected(getLastFocused())) {
                        deselect(getLastFocused());
                    } else {
                        select(getLastFocused(), true);
                        grid.getView().focusCell(listStore.indexOf(getLastFocused()), 0, false);
                    }
                }
            }
        }
    }

    protected void onKeyRight(GridEvent<M> ce) {
        if (GXT.isFocusManagerEnabled() && selectedHeader != null) {
            ColumnHeader ch = grid.getView().getHeader();
            int idx = ch.indexOf(selectedHeader) + 1;
            ColumnConfig config = grid.getColumnModel().getColumn(idx);
            while (config != null) {
                if (!config.isHidden()) {
                    Head h = getHead(idx, false);
                    selectedHeader = h;
                    grid.getView().getHeader().selectHeader(idx);
                    break;
                } else {
                    idx++;
                    config = grid.getColumnModel().getColumn(idx);
                }
            }
        }
        if (GXT.isAriaEnabled() && selectedGroup != null) {
            groupingView.toggleGroup(selectedGroup, true);
        }
    }

    protected void onKeyUp(GridEvent<M> e) {
        if (GXT.isFocusManagerEnabled()) {
            if (selectedHeader != null) {
                return;
            }
            if (listStore.indexOf(lastSelected) == 0 && !grouped) {
                deselectAll();
                ColumnHeader header = grid.getView().getHeader();
                Head h = getHead(0, false);
                if (h != null) {
                    selectedHeader = h;
                    header.selectHeader(header.indexOf(h));
                }
            }
            if (grouped) {
                GroupingView view = (GroupingView) grid.getView();
                NodeList<Element> groups = view.getGroups().cast();
                if (selectedGroup != null) {
                    int gindex = indexOf(groups, selectedGroup);

                    if (gindex == 0) {
                        deselectAll();
                        ColumnHeader header = grid.getView().getHeader();
                        Head h = getHead(0, false);
                        if (h != null) {
                            selectedHeader = h;
                            header.selectHeader(header.indexOf(h));
                        }
                    }

                    view.onGroupSelect(selectedGroup, false);
                    selectedGroup = null;

                    if (gindex > 0) {
                        selectedGroup = groups.getItem(gindex - 1);
                        if (view.isExpanded(selectedGroup)) {
                            int grows = view.getGroupRowCount(selectedGroup);
                            Element r = view.getGroupRow(selectedGroup, grows - 1).cast();
                            selectedGroup = null;
                            select(view.findRowIndex(r), false);
                            view.focusRow(view.findRowIndex(r));

                        } else {
                            view.onGroupSelect(selectedGroup, true);
                        }
                        return;
                    }
                }
                if (lastSelected != null) {
                    Element row = view.getRow(lastSelected).cast();
                    Element group = view.findGroup(row).cast();
                    if (row == view.getGroupRow(group, 0)) {
                        deselectAll();
                        selectedGroup = group;
                        view.onGroupSelect(selectedGroup, true);
                        return;
                    }
                }
            }
        }
        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);
                    grid.getView().focusCell(idx - 1, 0, false);
                }

            } else {

                if (e.isShiftKey() && lastSelected != getLastFocused()) {
                    select(listStore.indexOf(lastSelected), idx - 1, true);
                    grid.getView().focusCell(idx - 1, 0, false);
                } else {
                    if (idx > 0) {
                        selectPrevious(e.isShiftKey());
                        grid.getView().focusCell(idx - 1, 0, false);
                    }
                }

            }
        }

        e.preventDefault();
    }

    @Override
    protected void onLastFocusChanged(M oldFocused, M newFocused) {
        int i;
        if (oldFocused != null) {
            i = listStore.indexOf(oldFocused);
            if (i >= 0) {
                grid.getView().onHighlightRow(i, false);
            }
        }
        if (newFocused != null) {
            i = listStore.indexOf(newFocused);
            if (i >= 0) {
                grid.getView().onHighlightRow(i, true);
            }
        }
    }

    protected void onRowUpdated(GridEvent<M> ge) {
        if (isSelected(ge.getModel())) {
            onSelectChange(ge.getModel(), true);
        }
        if (isModelsEqual(getLastFocused(), ge.getModel())) {
            setLastFocused(getLastFocused());
        }
    }

    @Override
    protected void onSelectChange(M model, boolean select) {
        int idx = listStore.indexOf(model);
        if (idx != -1) {
            if (GXT.isFocusManagerEnabled() && selectedHeader != null) {
                selectedHeader = null;
                FocusFrame.get().frame(grid);
            }
            if (select) {
                grid.getView().onRowSelect(idx);
            } else {
                grid.getView().onRowDeselect(idx);
            }
        }
    }

    private Head getHead(int index, boolean back) {
        ColumnHeader header = grid.getView().getHeader();
        int cols = grid.getColumnModel().getColumnCount();

        if (!back) {
            for (int i = index; i < cols; i++) {
                ColumnConfig config = grid.getColumnModel().getColumn(i);
                if (!config.isHidden() && !config.ariaIgnore) {
                    return header.getHead(i);
                }
            }
        } else {
            for (int i = index; i > -1; i--) {
                ColumnConfig config = grid.getColumnModel().getColumn(i);
                if (!config.isHidden() && !config.ariaIgnore) {
                    return header.getHead(i);
                }
            }
        }
        return null;
    }

    private int indexOf(NodeList<Element> elems, Element elem) {
        for (int i = 0; i < elems.getLength(); i++) {
            if (elems.getItem(i) == elem) {
                return i;
            }
        }
        return -1;
    }
}