PDA

View Full Version : TreeGrid with TreeGridSelectionModel causing NullPointerException on select(..)



mrechtien
29 Jul 2010, 2:41 AM
Hi,

I'm just working on programatically selecting nodes within a TreeGrid.
The GXT version we are working with is 2.1.3.

When the TreeGridSelectionModel is created and initialized by TreeGrid
it only sets TreeGridSelectionModel.treeStore member, but in the superclass
the listStore is not set (due to the type of the store).

When the we now call the selection models select(..) methods it ends up
width firing an event that finally causes a nullpointerexception in
com.extjs.gxt.ui.client.widget.grid.GridSelectionModel.onSelectChange(M, boolean)
by accessing the listStore (which is still null).

For me it looks like this is the reason why the final selection of a row/rows fails.
Maybe I am missing something else?

Best regards,
Markus

sven
29 Jul 2010, 4:26 AM
Can you please post some fully working testcode thati mplements EntryPoint and shows exactly your problem?

mrechtien
29 Jul 2010, 11:51 PM
Hi Sven,

it seems like the nullpointer I got was a side effect. Although this is not really representing our use case
I set up a clean GXT test project with the following classes:


/**** ENTRY POINT ****/


package com.gxt.test.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.RootPanel;

/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class GXTTest implements EntryPoint {

/**
* This is the entry point method.
*/
public void onModuleLoad() {
RootPanel.get("content").add(new TreeGridExample());
}

}/**** TEST CLASS ****/


package com.gxt.test.client;

import java.util.Arrays;

import com.extjs.gxt.ui.client.Style.HorizontalAlignment;
import com.extjs.gxt.ui.client.data.BaseTreeModel;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.FieldEvent;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.store.TreeStore;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
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.ColumnConfig;
import com.extjs.gxt.ui.client.widget.grid.ColumnModel;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.layout.FlowLayout;
import com.extjs.gxt.ui.client.widget.toolbar.LabelToolItem;
import com.extjs.gxt.ui.client.widget.toolbar.ToolBar;
import com.extjs.gxt.ui.client.widget.treegrid.CellTreeGridSelectionModel;
import com.extjs.gxt.ui.client.widget.treegrid.TreeGrid;
import com.extjs.gxt.ui.client.widget.treegrid.TreeGridCellRenderer;
import com.extjs.gxt.ui.client.widget.treegrid.TreeGridSelectionModel;
import com.google.gwt.user.client.Element;

public class TreeGridExample extends LayoutContainer {

TreeStore<ModelData> store = new TreeStore<ModelData>();
TreeGrid<ModelData> tree = null;

private class Data extends BaseTreeModel
{
public Data(String name, String value) {
set("name", name);
set("value", value);
}
}

String[] data = new String[] {"eins", "zwei", "drei"};
Data parent = null;
Data child = null;

public TreeGridExample() {

ColumnConfig name = new ColumnConfig("name", "Name", 100);
name.setRenderer(new TreeGridCellRenderer<ModelData>());
ColumnConfig value = new ColumnConfig("value", "Value", 100);
ColumnModel cm = new ColumnModel(Arrays.asList(name, value));

tree = new TreeGrid<ModelData>(store, cm);

for (int i = 0; i < data.length; i++) {
parent = new Data(data[i], "#" + i);
store.add(parent, false);
for (int j = 0; j < data.length; j++) {
child = new Data(data[j], "#" + j);
store.add(parent, child, false);
}
}

tree.setBorders(true);
tree.setAutoExpandColumn("name");
tree.setTrackMouseOver(false);
}

@Override
protected void onRender(Element parent, int index) {
super.onRender(parent, index);
setLayout(new FlowLayout(10));
getAriaSupport().setIgnore(true);


ContentPanel cp = new ContentPanel();
cp.setBodyBorder(false);
cp.setHeading("TreeGrid");
cp.setButtonAlign(HorizontalAlignment.CENTER);
cp.setLayout(new FitLayout());
cp.setFrame(true);
cp.setSize(600, 300);


cp.add(tree);

ToolBar toolBar = new ToolBar();
toolBar.setBorders(true);
toolBar.add(new LabelToolItem("Selection Mode: "));

final SimpleComboBox<String> type = new SimpleComboBox<String>();
type.getAriaSupport().setLabelledBy(toolBar.getItem(0).getId());
type.setTriggerAction(TriggerAction.ALL);
type.setEditable(false);
type.setFireChangeEventOnSetValue(true);
type.setWidth(100);
type.add("Row");
type.add("Cell");
type.setSimpleValue("Row");
type.addListener(Events.Change, new Listener<FieldEvent>() {
public void handleEvent(FieldEvent be) {
boolean cell = type.getSimpleValue().equals("Cell");
tree.getSelectionModel().deselectAll();
if (cell) {
tree.setSelectionModel(new CellTreeGridSelectionModel<ModelData>());
} else {
tree.setSelectionModel(new TreeGridSelectionModel<ModelData>());
}
}
});
toolBar.add(type);
cp.setTopComponent(toolBar);
add(cp);
}

@Override
protected void onLoad() {
super.onLoad();

tree.setExpanded(parent, true);
tree.getSelectionModel().select(parent, true);
tree.getSelectionModel().select(child, true);
}
}
What surprised me is that the setExpanded call does have no effect in my test.
How or where does the setExpanded have to be called then?

Thanks in advance,
Markus

sven
30 Jul 2010, 2:31 AM
I modified your code a little bit. When onLoad runs, the TreeGrid is not fully setup. Instead of this, listen to the ViewReady event of the TreeGrid:


class TreeGridExample extends LayoutContainer {

TreeStore<ModelData> store = new TreeStore<ModelData>();
TreeGrid<ModelData> tree = null;

private class Data extends BaseTreeModel {
public Data(String name, String value) {
set("name", name);
set("value", value);
}
}

String[] data = new String[] {"eins", "zwei", "drei"};
Data parent = null;
Data child = null;

public TreeGridExample() {

ColumnConfig name = new ColumnConfig("name", "Name", 100);
name.setRenderer(new TreeGridCellRenderer<ModelData>());
ColumnConfig value = new ColumnConfig("value", "Value", 100);
ColumnModel cm = new ColumnModel(Arrays.asList(name, value));

tree = new TreeGrid<ModelData>(store, cm);

for (int i = 0; i < data.length; i++) {
parent = new Data(data[i], "#" + i);
store.add(parent, false);
for (int j = 0; j < data.length; j++) {
child = new Data(data[j], "#" + j);
store.add(parent, child, false);
}
}

tree.setBorders(true);
tree.setAutoExpandColumn("name");
tree.setTrackMouseOver(false);
}

@Override
protected void onRender(Element parent, int index) {
super.onRender(parent, index);
setLayout(new FlowLayout(10));
getAriaSupport().setIgnore(true);

ContentPanel cp = new ContentPanel();
cp.setBodyBorder(false);
cp.setHeading("TreeGrid");
cp.setButtonAlign(HorizontalAlignment.CENTER);
cp.setLayout(new FitLayout());
cp.setFrame(true);
cp.setSize(600, 300);

cp.add(tree);

ToolBar toolBar = new ToolBar();
toolBar.setBorders(true);
toolBar.add(new LabelToolItem("Selection Mode: "));

final SimpleComboBox<String> type = new SimpleComboBox<String>();
type.getAriaSupport().setLabelledBy(toolBar.getItem(0).getId());
type.setTriggerAction(TriggerAction.ALL);
type.setEditable(false);
type.setFireChangeEventOnSetValue(true);
type.setWidth(100);
type.add("Row");
type.add("Cell");
type.setSimpleValue("Row");
type.addListener(Events.Change, new Listener<FieldEvent>() {
public void handleEvent(FieldEvent be) {
boolean cell = type.getSimpleValue().equals("Cell");
tree.getSelectionModel().deselectAll();
if (cell) {
tree.setSelectionModel(new CellTreeGridSelectionModel<ModelData>());
} else {
tree.setSelectionModel(new TreeGridSelectionModel<ModelData>());
}
}
});
toolBar.add(type);
cp.setTopComponent(toolBar);
add(cp);

tree.addListener(Events.ViewReady, new Listener<GridEvent<ModelData>>(){

public void handleEvent(GridEvent<ModelData> be) {
tree.setExpanded(TreeGridExample.this.parent, true);
tree.getSelectionModel().select(TreeGridExample.this.parent, true);
tree.getSelectionModel().select(TreeGridExample.this.child, true);

}

});
}
}

mrechtien
30 Jul 2010, 2:59 AM
Thank you for the hint!

In our case there is a complex data binding structure, which tells the tree what items are to be selected. I am using a custom treegridselectionmodel class to be able to add the selected items to the "selected" member without triggering any action (before rendering took place).

I now overwrote the afterRenderView method of our TreeGrid subclass (calling super.afterRenderView of course) and call the selectionmodels refresh now to apply the selection. The expansion is triggered here too.

I guess this is ok, from your point of knowledge?

Thank you and best regards,
Markus

sven
30 Jul 2010, 3:23 AM
Yes should be ok. When you select an item where the parent is not expanded, the TreeGrid will automatically expand all parents to make this node you just selected visible.

Sabhtarsha
16 Dec 2011, 7:36 AM
Thanks sven (http://www.sencha.com/forum/member.php?11570-sven). That helped :)