Success! Looks like we've fixed this one. According to our records the fix was applied for EXTGWT-2914 in a recent build.
  1. #1
    Sencha Premium Member
    Join Date
    Jun 2012
    Posts
    21
    Vote Rating
    0
    joseph.j.valerio@gmail.com is on a distinguished road

      0  

    Default GridSelectionModel Bug?

    GridSelectionModel Bug?


    Guys,

    We have grids, both multi and single select where we highlight a row or rows, and then the user hits the Delete key on the keyboard and the row(s) are deleted. The current GridSelectionModel has a bug where if you click a single row more than once, in either mode (not a double click), the focus is not assigned correctly after the second click, therefore the KeyDownEvent does not fire.

    Below is an example with two grids, one with the stock GridSelectionModel, the other with the fixed GridSelectionModel

    Thanks,

    - Joe

    The EntryPoint Example
    Code:
    package com.sencha.gxt.explorer.client.grid;
    
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    
    import com.google.gwt.cell.client.AbstractCell;
    import com.google.gwt.cell.client.DateCell;
    import com.google.gwt.core.client.EntryPoint;
    import com.google.gwt.core.client.GWT;
    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.i18n.client.DateTimeFormat;
    import com.google.gwt.i18n.client.NumberFormat;
    import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
    import com.google.gwt.safehtml.shared.SafeHtmlUtils;
    import com.google.gwt.user.client.ui.IsWidget;
    import com.google.gwt.user.client.ui.RootPanel;
    import com.google.gwt.user.client.ui.Widget;
    import com.sencha.gxt.core.client.GXT;
    import com.sencha.gxt.core.client.Style.SelectionMode;
    import com.sencha.gxt.data.shared.ListStore;
    import com.sencha.gxt.examples.resources.client.TestData;
    import com.sencha.gxt.examples.resources.client.images.ExampleImages;
    import com.sencha.gxt.examples.resources.client.model.Stock;
    import com.sencha.gxt.examples.resources.client.model.StockProperties;
    import com.sencha.gxt.explorer.client.model.Example.Detail;
    import com.sencha.gxt.state.client.CookieProvider;
    import com.sencha.gxt.state.client.GridStateHandler;
    import com.sencha.gxt.state.client.StateManager;
    import com.sencha.gxt.widget.core.client.ContentPanel;
    import com.sencha.gxt.widget.core.client.Dialog;
    import com.sencha.gxt.widget.core.client.box.ConfirmMessageBox;
    import com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer;
    import com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer.VerticalLayoutData;
    import com.sencha.gxt.widget.core.client.event.HideEvent;
    import com.sencha.gxt.widget.core.client.event.HideEvent.HideHandler;
    import com.sencha.gxt.widget.core.client.grid.ColumnConfig;
    import com.sencha.gxt.widget.core.client.grid.ColumnModel;
    import com.sencha.gxt.widget.core.client.grid.Grid;
    import com.sencha.gxt.widget.core.client.grid.GridSelectionModel;
    
    @Detail(name = "SelectionModel Bug Grid Example ", icon = "basicgrid", category = "Grid", classes = {Stock.class, StockProperties.class})
    public class SelectionModelBugGridExample implements IsWidget, EntryPoint {
    
      private static final StockProperties props = GWT.create(StockProperties.class);
    
      private ContentPanel root;
    
      @Override
      public Widget asWidget() {
        if (root == null) {
    
            root = new ContentPanel();
    
            VerticalLayoutContainer vlc = new VerticalLayoutContainer();
            
            GridSelectionModel<Stock> sm1 = new GridSelectionModel<Stock>();
            sm1.setSelectionMode(SelectionMode.MULTI);
            vlc.add(makeGrid("3.0.4 SelectionModel", sm1));
            
            GridSelectionModel<Stock> sm2 = new FixedGridSelectionModel<Stock>();
            sm2.setSelectionMode(SelectionMode.MULTI);
            vlc.add(makeGrid("Modified SelectionModel", sm2));
            
            root.add(vlc);
    
        }
        return root;
      }
      
      public ContentPanel makeGrid(String title, GridSelectionModel<Stock> gridSelectionModel){
          
          ContentPanel panel = new ContentPanel();
          
          final NumberFormat number = NumberFormat.getFormat("0.00");
    
          ColumnConfig<Stock, String> nameCol = new ColumnConfig<Stock, String>(props.name(), 50, SafeHtmlUtils.fromTrustedString("<b>Company</b>"));
          
          ColumnConfig<Stock, String> symbolCol = new ColumnConfig<Stock, String>(props.symbol(), 100, "Symbol");
          ColumnConfig<Stock, Double> lastCol = new ColumnConfig<Stock, Double>(props.last(), 75, "Last");
    
          ColumnConfig<Stock, Double> changeCol = new ColumnConfig<Stock, Double>(props.change(), 100, "Change");
          changeCol.setCell(new AbstractCell<Double>() {
    
            @Override
            public void render(Context context, Double value, SafeHtmlBuilder sb) {
              String style = "style='color: " + (value < 0 ? "red" : "green") + "'";
              String v = number.format(value);
              sb.appendHtmlConstant("<span " + style + " qtitle='Change' qtip='" + v + "'>" + v + "</span>");
            }
          });
    
          ColumnConfig<Stock, Date> lastTransCol = new ColumnConfig<Stock, Date>(props.lastTrans(), 100, "Last Updated");
          lastTransCol.setCell(new DateCell(DateTimeFormat.getFormat("MM/dd/yyyy")));
    
          List<ColumnConfig<Stock, ?>> l = new ArrayList<ColumnConfig<Stock, ?>>();
          l.add(nameCol);
          l.add(symbolCol);
          l.add(lastCol);
          l.add(changeCol);
          l.add(lastTransCol);
          ColumnModel<Stock> cm = new ColumnModel<Stock>(l);
    
          ListStore<Stock> store = new ListStore<Stock>(props.key());
          store.addAll(TestData.getStocks());
    
          panel = new ContentPanel();
          panel.setHeadingText(title);
          panel.getHeader().setIcon(ExampleImages.INSTANCE.table());
          panel.setPixelSize(600, 300);
          panel.addStyleName("margin-10");
          
          final Grid<Stock> grid = new Grid<Stock>(store, cm);
          grid.getView().setAutoExpandColumn(nameCol);
          grid.getView().setStripeRows(true);
          grid.getView().setColumnLines(true);
          grid.setBorders(false);
    
          grid.setColumnReordering(true);
          grid.setStateful(true);
          grid.setStateId(title);
          
          grid.setSelectionModel(gridSelectionModel);
    
          GridStateHandler<Stock> state = new GridStateHandler<Stock>(grid);
          state.loadState();
    
          VerticalLayoutContainer con = new VerticalLayoutContainer();
          panel.setWidget(con);
    
          con.add(grid, new VerticalLayoutData(1, 1));
          
          KeyDownHandler deleteHandler = new KeyDownHandler() {
              public void onKeyDown(KeyDownEvent event) {
                  if(event.getNativeKeyCode() == KeyCodes.KEY_DELETE) {
                      ConfirmMessageBox box = new ConfirmMessageBox("Confirm", "Are you sure you want to delete the selected items?");
                      box.addHideHandler(new HideHandler(){
                            @Override
                            public void onHide(HideEvent event) {
                                Dialog dlg = (Dialog) event.getSource();
                                if(dlg.getHideButton().getText().equalsIgnoreCase("yes")){
                                    for(Stock item : grid.getSelectionModel().getSelectedItems()){
                                        grid.getStore().remove(item);
                                    }
                                }
                            }
                         });
                      box.show();
                  }
              }
          };
          grid.addHandler(deleteHandler, KeyDownEvent.getType());
    
    
          return panel;
          
      }
    
      @Override
      public void onModuleLoad() {
        StateManager.get().setProvider(new CookieProvider("/", null, null, GXT.isSecure()));
        RootPanel.get().add(asWidget());
      }
      
    }
    The Extended SelectionModel
    Code:
    package com.sencha.gxt.explorer.client.grid;
    
    import java.util.Collections;
    
    import com.google.gwt.dom.client.Element;
    import com.sencha.gxt.core.client.Style.SelectionMode;
    import com.sencha.gxt.widget.core.client.event.RowClickEvent;
    import com.sencha.gxt.widget.core.client.event.XEvent;
    import com.sencha.gxt.widget.core.client.grid.GridSelectionModel;
    
    public class FixedGridSelectionModel<M> extends GridSelectionModel<M> {
    
        /**
         * Handles a row click event. The row click event is responsible for adding
         * to a selection in multiple selection mode.
         * 
         * @param event
         *            the row click event
         */
        protected void handleRowClick(RowClickEvent event) {
            if (Element.is(event.getEvent().getEventTarget())
                    && !grid.getView().isSelectableTarget(
                            Element.as(event.getEvent().getEventTarget()))) {
                return;
            }
            if (isLocked()) {
                return;
            }
    
            if (fireSelectionChangeOnClick) {
                fireSelectionChange();
                fireSelectionChangeOnClick = false;
            }
    
            XEvent xe = event.getEvent().<XEvent> cast();
    
            int rowIndex = event.getRowIndex();
            int colIndex = event.getColumnIndex();
            if (rowIndex == -1) {
                deselectAll();
                return;
            }
            
            M sel = listStore.get(rowIndex);
            if (selectionMode == SelectionMode.MULTI) {
                if (xe.getCtrlOrMetaKey() && isSelected(sel)) {
                    doDeselect(Collections.singletonList(sel), false);
                } else if (xe.getCtrlOrMetaKey()) {
                    grid.getView().focusCell(rowIndex, colIndex, false);
                    doSelect(Collections.singletonList(sel), true, false);
                } else if (isSelected(sel) && !event.getEvent().getShiftKey()
                        && !xe.getCtrlOrMetaKey() && selected.size() > 1) {
                    grid.getView().focusCell(rowIndex, colIndex, false);
                    doSelect(Collections.singletonList(sel), false, false);
                } else if (isSelected(sel)) {
                    grid.getView().focusCell(rowIndex, colIndex, false);
                }
            } else {
                if (isSelected(sel)) {
                    grid.getView().focusCell(rowIndex, colIndex, false);
                }
            }
    
        }
    
    }

  2. #2
    Sencha User
    Join Date
    Sep 2007
    Posts
    13,971
    Vote Rating
    132
    sven is a glorious beacon of light sven is a glorious beacon of light sven is a glorious beacon of light sven is a glorious beacon of light sven is a glorious beacon of light sven is a glorious beacon of light

      0  

    Default


    Thanks for the report. I will move this thread to the proper location and push it into the tracking system for further investigation.

  3. #3
    Sencha - GXT Dev Team
    Join Date
    Jan 2012
    Location
    Arlington, WA
    Posts
    492
    Vote Rating
    15
    branflake2267 will become famous soon enough

      0  

    Default


    This issue has been fixed and the fixed source is available in SVN. It will be released in the 3.0.5 release shortly.

    Brandon

Thread Participants: 2