Dear colleagues, I am newbie of GWT, and I am trying to learn by using code already posted on Web.
In this way, I was able to build a virtual phonebook. It is created by a recordset extracted from a mySQL database.
Subsequently, a function create a List<ContattoModel> object, with the list of contacts. I added a Grid to view the contacts, and checkboxes to select one or more contacts at the same time. I successfully added paging and filtering to Grid, but I cannot run the grouping. I would like to group by "azienda", which is a particular field of recordset, and a column within the Grid. Here is the code. Could anyone help me, and indicate why the code doesn't work, please?

Thanks
Matteo

Code:
package com.webgenesys.unicom.client.ui.controls;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.extjs.gxt.ui.client.Style.HorizontalAlignment;
import com.extjs.gxt.ui.client.Style.SortDir;
import com.extjs.gxt.ui.client.data.BaseFilterPagingLoadConfig;
import com.extjs.gxt.ui.client.data.BasePagingLoadConfig;
import com.extjs.gxt.ui.client.data.BasePagingLoader;
import com.extjs.gxt.ui.client.data.FilterPagingLoadConfig;
import com.extjs.gxt.ui.client.data.PagingLoadResult;
import com.extjs.gxt.ui.client.data.PagingLoader;
import com.extjs.gxt.ui.client.data.RpcProxy;
import com.extjs.gxt.ui.client.event.BaseEvent;
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.event.SelectionChangedEvent;
import com.extjs.gxt.ui.client.event.SelectionChangedListener;
import com.extjs.gxt.ui.client.store.GroupingStore;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.store.Store;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.Label;
import com.extjs.gxt.ui.client.widget.form.CheckBox;
import com.extjs.gxt.ui.client.widget.form.ComboBox.TriggerAction;
import com.extjs.gxt.ui.client.widget.form.SimpleComboBox;
import com.extjs.gxt.ui.client.widget.grid.CheckBoxSelectionModel;
import com.extjs.gxt.ui.client.widget.grid.ColumnConfig;
import com.extjs.gxt.ui.client.widget.grid.ColumnModel;
import com.extjs.gxt.ui.client.widget.grid.Grid;
import com.extjs.gxt.ui.client.widget.grid.GridGroupRenderer;
import com.extjs.gxt.ui.client.widget.grid.GroupColumnData;
import com.extjs.gxt.ui.client.widget.grid.GroupingView;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.toolbar.LabelToolItem;
import com.extjs.gxt.ui.client.widget.toolbar.PagingToolBar;
import com.extjs.gxt.ui.client.widget.toolbar.ToolBar;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.webgenesys.unicom.client.resources.Resources;
import com.webgenesys.unicom.client.rpc.Service;
import com.webgenesys.unicom.client.rpc.ServiceAsync;
import com.webgenesys.unicom.shared.model.ContattoModel;

public class ContattiGrid extends ContentPanel {

    // toolbar
    private ToolBar toolbarFiltro = new ToolBar();
    private final SimpleComboBox<String> filterUsing = new SimpleComboBox<String>();
    private Label selezionatiLabel = new Label("Selezionati: 0");
    // paging
    private PagingToolBar toolbar = new PagingToolBar(50);
    private final Boolean isCached;
    private final Boolean showToolBar;
    private final Boolean showRowNumberer;
    private final Boolean showCheckBoxSelection;
    private final Boolean collapsible;
    private CheckBox pagingCheck = new CheckBox();
    private final BaseFilterPagingLoadConfig pagingConfig = new BaseFilterPagingLoadConfig();
    //filter
    private String text = null;
    private String name_property_to_filter = "nome";
    // grid    
    private Grid<ContattoModel> grid = null;
    private boolean beforeRender = true;

    // remote service proxy per gestione della chiamata asincrona
    private final ServiceAsync serviceAsyncCallback = GWT.create(Service.class);

    public ContattiGrid() {
        super();
        this.isCached = false;
        this.showToolBar = true;
        this.showRowNumberer = false;
        this.showCheckBoxSelection = true;
        this.collapsible = true;
        this.pagingConfig.setOffset(0);
        this.pagingConfig.setLimit(50);
        setCollapsible(collapsible);
        setLayout(new FitLayout());
        setIcon(Resources.ICONS.contatti());
        setHeading("Elenco Contatti");
        setSize(200, 300);
        renderGrid(beforeRender, "azienda");
    }

    public ContattiGrid(Boolean isCached, Boolean showToolBar, Boolean  showRowNumberer, Boolean showCheckBoxSelection,  BaseFilterPagingLoadConfig pagingConfig, Boolean collapsible,
            int width, int height) {
        super();
        this.isCached = isCached;
        this.showToolBar = showToolBar;
        this.showRowNumberer = showRowNumberer;
        this.showCheckBoxSelection = showCheckBoxSelection;
        this.collapsible = collapsible;
        this.pagingConfig.setLimit(pagingConfig.getLimit());
        this.pagingConfig.setOffset(pagingConfig.getOffset());
        setCollapsible(collapsible);
        setLayout(new FitLayout());
        setIcon(Resources.ICONS.contatti());
        setHeading("Elenco Contatti");
        setSize(width, height);
        renderGrid(beforeRender, "azienda");
    }

    private void renderGrid(Boolean beforeRender, String groupBy) {
        //proxy
        final RpcProxy<PagingLoadResult<ContattoModel>>  proxy = new RpcProxy<PagingLoadResult<ContattoModel>>() {
            @Override
            protected void load(Object loadConfig, AsyncCallback<PagingLoadResult<ContattoModel>> callback) {
                 serviceAsyncCallback.getContattiPaging((FilterPagingLoadConfig)  loadConfig, text, name_property_to_filter, callback);
            }
        };        
        //loader
        final  BasePagingLoader<PagingLoadResult<ContattoModel>> loader =  new BasePagingLoader<PagingLoadResult<ContattoModel>>(proxy)  {
            @Override
            protected Object newLoadConfig() {
                BasePagingLoadConfig config = new BaseFilterPagingLoadConfig();
                return config;
            }
        };
        loader.setRemoteSort(true);
        ListStore<ContattoModel> store = null;
        if ( groupBy!=null ) {
            GroupingStore<ContattoModel> groupingStore = new GroupingStore<ContattoModel>(loader); 
            groupingStore.groupBy(groupBy);
            groupingStore.setGroupOnSort(true);
            groupingStore.setRemoteGroup(true);
            store = groupingStore;
        } else {
            store = new ListStore<ContattoModel>(loader);
        }        
        //grid
        List<ColumnConfig> configs = new ArrayList<ColumnConfig>();
        PagingRowNumbered numberer = null;
        if (showRowNumberer) {
            numberer = new PagingRowNumbered(25);
            numberer.setHeader("Lp");
            configs.add(numberer);
        }
        final CheckBoxSelectionModel<ContattoModel> checkBoxSelection = new CheckBoxSelectionModel<ContattoModel>();
        if (showCheckBoxSelection) {            
            //checkBoxSelection.setSelectionMode(SelectionMode.MULTI);//SIMPLE
            configs.add(checkBoxSelection.getColumn());
        }
        ColumnConfig column = new ColumnConfig();
        column = new ColumnConfig("cognome", "Cognome", 150);
        column.setAlignment(HorizontalAlignment.LEFT);
        configs.add(column);
        column = new ColumnConfig("nome", "Nome", 150);
        column.setAlignment(HorizontalAlignment.LEFT);
        configs.add(column);
        column = new ColumnConfig("ragsociale", "RagSociale", 150);
        column.setAlignment(HorizontalAlignment.LEFT);
        configs.add(column);
        column = new ColumnConfig("azienda", "Azienda", 150);
        column.setAlignment(HorizontalAlignment.LEFT);
        configs.add(column);
        column = new ColumnConfig("posizione", "Ruolo", 150);
        column.setAlignment(HorizontalAlignment.LEFT);
        configs.add(column);
        column = new ColumnConfig("mobile", "Mobile", 150);
        column.setAlignment(HorizontalAlignment.LEFT);
        configs.add(column);
        column = new ColumnConfig("email", "Email", 150);
        column.setAlignment(HorizontalAlignment.LEFT);
        configs.add(column);
        column = new ColumnConfig("fax", "Fax", 150);
        column.setAlignment(HorizontalAlignment.LEFT);
        configs.add(column);
        column = new ColumnConfig("indirizzo", "Indirizzo", 150);
        column.setAlignment(HorizontalAlignment.LEFT);
        configs.add(column);
        column = new ColumnConfig("citta", "Citta", 150);
        column.setAlignment(HorizontalAlignment.LEFT);
        configs.add(column);
        column = new ColumnConfig("provincia", "Provincia", 150);
        column.setAlignment(HorizontalAlignment.LEFT);
        configs.add(column);
        column = new ColumnConfig("assegnato", "Assegnato a", 150);
        column.setAlignment(HorizontalAlignment.LEFT);
        configs.add(column);
        ColumnModel columnsModel = new ColumnModel(configs);
        grid = new Grid<ContattoModel>(store, columnsModel);
        grid.setStateId("pagingGridContatti");
        grid.setStateful(true);
        if (groupBy != null) {
            grid.setView(createGroupingView(columnsModel));
        }
        if (showCheckBoxSelection) {
            grid.setSelectionModel(checkBoxSelection);
        }
        if (showCheckBoxSelection && beforeRender) {
            grid.addPlugin(checkBoxSelection);
        }
        grid.addListener(Events.Attach, new Listener<GridEvent<ContattoModel>>() {
            public void handleEvent(GridEvent<ContattoModel> be) {
                Map<String, Object> state = grid.getState();
                if (state.containsKey("offset")) {
                    int offset = (Integer) state.get("offset");
                    int limit = (Integer) state.get("limit");
                    pagingConfig.setOffset(offset);
                    pagingConfig.setLimit(limit);
                }
                if (state.containsKey("sortField")) {
                    pagingConfig.setSortField((String) state.get("sortField"));
                    pagingConfig.setSortDir(SortDir.valueOf((String) state.get("sortDir")));
                }
                loader.load(pagingConfig);
            }
        });
        grid.getSelectionModel().addSelectionChangedListener(new SelectionChangedListener<ContattoModel>() {
            @Override
            public void selectionChanged(SelectionChangedEvent<ContattoModel> se) {
                selezionatiLabel.setText("Selezionati: "+se.getSelection().size());
            }
        });
        grid.setColumnLines(true);
        grid.setLoadMask(true);
        // grid.setAutoExpandColumn("cognome");
        // grid.setStripeRows(true);
        grid.getView().setEmptyText("Contatti...");
        // aggiunge grid al panel
        add(grid);
        // aggiunge filtro
        addFilter(store);
        // aggiunge toolbar paging
        addToolbar(beforeRender, loader);
    }

    private void addFilter(ListStore<ContattoModel> store) {
        final RemoteStoreFilterField<ContattoModel> filterField = new RemoteStoreFilterField<ContattoModel>() {
            @Override
            protected void handleOnFilter(String filter) {
                if (filter == null || filter.equals(""))
                    text = null;
                else
                    text = filter.toLowerCase();
                if(filterUsing.getSelectedIndex()>-1) {
                    name_property_to_filter = filterUsing.getSimpleValue();
                }                
                // Call to the RPC
                grid.getStore().getLoader().load(); // loader.load();
            }
            @Override
            protected boolean doSelect(Store<ContattoModel> store,  ContattoModel parent, ContattoModel record, String property, String  filter) {                
                switch (filterUsing.getSelectedIndex()) {
                case 0:
                    if (record.getNome() != null) {
                        String nome = record.getNome().toLowerCase();
                        if (nome.startsWith(filter.toLowerCase())) {
                            return true;
                        }
                    }
                    if (record.getCognome() != null) {
                        String cognome = record.getCognome().toLowerCase();
                        if (cognome.startsWith(filter.toLowerCase())) {
                            return true;
                        }
                    }
                    break;
                case 1:
                    if (record.getCap() != null) {
                        String cap = record.getCap().toLowerCase();
                        if (cap.startsWith(filter.toLowerCase())) {
                            return true;
                        }
                    }
                    break;
                case 2:
                    if (record.getProvincia() != null) {
                        String provincia = record.getProvincia().toLowerCase();
                        if (provincia.startsWith(filter.toLowerCase())) {
                            return true;
                        }
                    }
                    break;
                case 3:
                    if (record.getCitta() != null) {
                        String citta = record.getCitta().toLowerCase();
                        if (citta.startsWith(filter.toLowerCase())) {
                            return true;
                        }
                    }
                    break;
                case 4:
                    if (record.getRagsociale() != null) {
                        String rag = record.getRagsociale().toLowerCase();
                        if (rag.startsWith(filter.toLowerCase())) {
                            return true;
                        }
                    }
                    break;
                case 5:
                    if (record.getAzienda() != null) {
                        String azienda = record.getAzienda().toLowerCase();
                        if (azienda.startsWith(filter.toLowerCase())) {
                            return true;
                        }
                    }
                    break;
                case 6:
                    if (record.getEmail() != null) {
                        String email = record.getEmail().toLowerCase();
                        if (email.indexOf(filter.toLowerCase()) != -1) {
                            return true;
                        }
                    }
                    break;
                case 7:
                    if (record.getIndirizzo() != null) {
                        String addr = record.getIndirizzo().toLowerCase();
                        if (addr.indexOf(filter.toLowerCase()) != -1) {
                            return true;
                        }
                    }
                    break;
                case 8:
                    if (record.getMobile() != null) {
                        String mobile = record.getMobile().toLowerCase();
                        if (mobile.startsWith(filter.toLowerCase())) {
                            return true;
                        }
                    }
                    break;                
                }
                return false;
            }
        };
        filterField.setWidth(200);
        filterField.bind(store);
        // toolbar
        filterUsing.setEditable(false);
        filterUsing.setWidth(100);
        filterUsing.add("Nome/Cognome");
        filterUsing.add("CAP");
        filterUsing.add("Provincia");
        filterUsing.add("Citta");
        filterUsing.add("RagSociale");
        filterUsing.add("Azienda");
        filterUsing.add("Email");
        filterUsing.add("Indirizzo");
        filterUsing.add("Mobile");
        filterUsing.setTriggerAction(TriggerAction.ALL);
        //filterUsing.setSimpleValue("Nome");
        toolbarFiltro.add(new LabelToolItem("Cerca:"));
        toolbarFiltro.add(filterField);
        toolbarFiltro.add(new LabelToolItem("Filtro:"));
        toolbarFiltro.add(filterUsing);
        toolbarFiltro.add(selezionatiLabel);
        setTopComponent(toolbarFiltro);
    }
    
    private void addToolbar(boolean beforeRender, PagingLoader<PagingLoadResult<ContattoModel>> loader) {
        if (showToolBar) {
            toolbar.bind(loader);
            toolbar.refresh();
        }
        if (showToolBar && beforeRender) {
            setBottomComponent(toolbar);
        }
        toolbar.setEnabled(true);
        pagingCheck.setBoxLabel("Paging");
        pagingCheck.setValue(true);
        pagingCheck.addListener(Events.OnClick, new Listener<BaseEvent>() {
            @Override
            public void handleEvent(BaseEvent be) {
                if(pagingCheck.getValue()==true) {
                    toolbar.setPageSize(50);
                    pagingConfig.setOffset(0);
                    pagingConfig.setLimit(50);
                    grid.getStore().getLoader().load(pagingConfig); // loader.load(pagingConfig);                    
                }
                else {
                    toolbar.setPageSize(300000);
                    pagingConfig.setOffset(0);
                    pagingConfig.setLimit(300000);
                    grid.getStore().getLoader().load(pagingConfig); // loader.load(pagingConfig);
                }
            }
        });
        toolbar.add(pagingCheck);
        setBottomComponent(toolbar);
    }
        
    private GroupingView createGroupingView(final ColumnModel cm) {
        GroupingView groupingView = new GroupingView();
        groupingView.setShowGroupedColumn(false);
        groupingView.setForceFit(true);
        groupingView.setGroupRenderer(new GridGroupRenderer() {
            public String render(GroupColumnData data) {
                String f = cm.getColumnById(data.field).getHeader();
                String l = data.models.size() == 1 ? "Item" : "Items";
                return f + ": " + data.group + " (" + data.models.size() + " " + l + ")";
                }
        });
        return groupingView;
    }

    public Grid<ContattoModel> getGrid() {
        return grid;
    }

}