GWT Cell Tree - leaf nodes - gwt

I'm using a cell tree and I have this problem:
I get the data via RPC calls. I decide if a node is a leaf or not - based on the data that I get for its children. For example - if a node has a son called "foo" - then this node should be a leaf.
I don't know how to make this node to be a leaf and not to show its children on the tree. (instead, I want to show them somewhere else, when clicking on the node)
Is it possible? Does anyone have an idea?
Please help me, I'm stuck with it for 2 days...
Thanks!

You can override isLeaf() method to return true or false.
There will be a problem, however, from the UI perspective. Before a user clicks on a node, you don't know if this should be a node or a leaf. This is a little confusing, although I saw such implementations more than once. If your tree is not very large, consider loading all data at once, and then building it the way you want - creating nodes or leafs as necessary.

If each node has a type, could you create some list or map of types that aren't expected to have children in your TreeViewModel impl?
In an impl I did I used a meta-model for all types, but it's not a requirement.
E.g.,
#Override
public boolean isLeaf(Object value) {
boolean result = true;
if (value == null) {
result = false; // assumes all root nodes have children
} else if (value instanceof NavNode) {
final NavNode currentNode = (NavNode) value;
final NodeType currentNodeType = NodeType.fromValue(currentNode.getType());
if (currentNode.hasChildren() || NodeHelper.couldHaveChildren(currentNodeType)) {
result = false;
}
}
return result;
}
// Create a data provider for root nodes
protected ListDataProvider<NavNode> getDataProvider(Collection<NavNode> rootNodes) {
return new ListDataProvider<NavNode>(new LinkedList<NavNode>(rootNodes));
}
// Create a data provider that contains the immediate descendants.
protected AsyncDataProvider<NavNode> getDataProvider(final NavNode node) {
return new AsyncDataProvider<NavNode>() {
#Override
protected void onRangeChanged(final HasData<NavNode> display) {
final Set<NavNode> clientNodes = util.getAncestorNodes(node);
clientNodes.add(node);
final NavigationInfo clientInfo = new NavigationInfo(clientNodes);
navigationService.getNavInfo(clientInfo, node, resources, qualifications, new SafeOperationCallback<NavigationInfo>(eventBus, false) {
#Override
public void onFailureImpl(Throwable caught) {
GWT.log("Something went wrong retreiving children for " + node.getName(), caught);
updateRowCount(0, false);
}
#Override
public void onSuccessImpl(OperationResult<NavigationInfo> or) {
util.mergeNavInfo(or.getResult());
final NavNode nodeFromServer = util.getNode(node.getId());
final Range range = display.getVisibleRange();
final int start = range.getStart();
final Set<NavNode> nodes = util.getNodes(nodeFromServer.getChildren());
updateRowData(display, start, new LinkedList<NavNode>(nodes));
}
});
}
};
}
private static class NodeHelper {
private static final Set<NodeType> PARENTAL_NODE_TYPES;
static {
PARENTAL_NODE_TYPES = new HashSet<NodeType>();
PARENTAL_NODE_TYPES.add(NodeType.ASSET_OWNER);
PARENTAL_NODE_TYPES.add(NodeType.OPERATING_DAY);
PARENTAL_NODE_TYPES.add(NodeType.RESOURCES);
PARENTAL_NODE_TYPES.add(NodeType.RESOURCE);
PARENTAL_NODE_TYPES.add(NodeType.ENERGY);
PARENTAL_NODE_TYPES.add(NodeType.RESERVE);
PARENTAL_NODE_TYPES.add(NodeType.DAY_AHEAD_CLEARED_OFFERS);
PARENTAL_NODE_TYPES.add(NodeType.DRR_LOAD_FORCAST);
PARENTAL_NODE_TYPES.add(NodeType.RESERVE_DISPATCH);
PARENTAL_NODE_TYPES.add(NodeType.RESERVE_RAMP_RATE);
}
public static boolean couldHaveChildren(NodeType nodeType) {
boolean result = false;
if (PARENTAL_NODE_TYPES.contains(nodeType)) {
result = true;
}
return result;
}
}
}

Related

Californium CoAP path parameters

I'm working on a CoAP application using Eclipse Californium and I need to pass parameters using the URL as we do in restful web services. Is it possible to do it in californium coap implementation, and if so please let me know how to do it.
ex:
coap://localhost:5683/foo/{fooID}
The short answer is yes you can do it.
As stated in JavaDocs
When a request arrives at the server, the {#link
ServerMessageDeliverer} searches in the resource tree for the
destination resource. It travels down the resource tree by looking
for one element of the destination URI after another and by calling
the method {#link #getChild(String)} on each element. It is allowed
to override this method and to return an arbitrary resource. This
allows for instance to serve URIs with wildcards or delegate requests
to any sub-URI to the same resource.
So basically you have to override deliverRequest and maybe findResource methods in org.eclipse.californium.core.server.ServerMessageDeliverer in order to return appropriate resource which will handle the request. Also it will be required to analyse Exchange Request UriPath as a part of resource handleGET/PUT/POST/etc to fetch path variable (this can be done by using CoapExchange.advanced().getRequest().getOptions().getUriPath())
Based on the source code of Californium it should be pretty easy to override the default behaviour of a request deliverer.
Good luck with that!
From what I have seen so far, creating a custom ServerMessageDeliverer seems to be the more complicated solution. Actually it looks like the correct solution is to override CoapResource#getChild(String) so it returns the resource you want to be associated with that name. The ServerMessageDeliverer looks to me more like the way to implement some sort of controller that delivers or distribute requests in a more complicated environment.
For the question where the last part of the URI is the parameter, the solution could look like this:
public class UriParameterResource extends CoapResource {
public UriParameterResource() {
super("foo");
}
#Override
public void handleGET(CoapExchange exchange) {
List<String> uriPath = exchange.getRequestOptions().getUriPath();
// check if there is a sub-resource given, and if so use it for processing
if (uriPath.size() > 1) {
exchange.respond("Process " + uriPath.get(1));
} else {
exchange.respond(ResponseCode.NOT_IMPLEMENTED);
}
}
#Override
public Resource getChild(String name) {
// even sub-resources will land in the GET of this resource
return this;
}
}
Regarding the the answer from #Copernic, I personally think it does not match the idea of REST. Each part of the URI path should return its own resource related to its parent, which makes it a tree structure per definition and not a flat list that simply inspects parts of the path as some sort of parameter.
IMHO even the sensors example could be resolved by using CoapResource implementations where the variable child resource could be dynamically resolved. The snippet below is just an example, of course this would need to be dependent on the real situation where a house and its rooms would need to register somehow.
public class HousesResource extends CoapResource {
public HousesResource() {
super("houses");
}
#Override
public void handleGET(CoapExchange exchange) {
// could return a list of available houses
exchange.respond(ResponseCode.NOT_IMPLEMENTED);
}
#Override
public Resource getChild(String name) {
Resource child = super.getChild(name);
if (child == null) {
child = new HouseResource(name);
add(child);
}
return child;
}
class HouseResource extends CoapResource {
public HouseResource(String name) {
super(name);
add(new RoomsResource());
}
#Override
public void handleGET(CoapExchange exchange) {
exchange.respond(ResponseCode.NOT_IMPLEMENTED);
}
}
class RoomsResource extends CoapResource {
public RoomsResource() {
super("rooms");
}
#Override
public void handleGET(CoapExchange exchange) {
// could return a list of available rooms
exchange.respond(ResponseCode.NOT_IMPLEMENTED);
}
#Override
public Resource getChild(String name) {
Resource child = super.getChild(name);
if (child == null) {
child = new RoomResource(name);
add(child);
}
return child;
}
}
class RoomResource extends CoapResource {
public RoomResource(String roomName) {
super(roomName);
add(new SensorsResource());
}
#Override
public void handleGET(CoapExchange exchange) {
// could return a summary board about the room
exchange.respond(ResponseCode.NOT_IMPLEMENTED);
}
}
class SensorsResource extends CoapResource {
public SensorsResource() {
super("sensors");
add(new TemperatureResource());
}
#Override
public void handleGET(CoapExchange exchange) {
// this could return a list of registered sensors
exchange.respond(ResponseCode.NOT_IMPLEMENTED);
}
}
class TemperatureResource extends CoapResource {
public TemperatureResource() {
super("temperature");
}
#Override
public void handleGET(CoapExchange exchange) {
// as the structure is fixed we know that two levels up
// there is the room, and four levels up there is the house
String room = getParent().getParent().getName();
String house = getParent().getParent().getParent().getParent().getName();
exchange.respond("The temperature of the " + house + " in the " + room + " is : 25 degree");
}
}
}
In that example the resources are dynamically created if they did not exist before. This could be also exchanged with some lookup or register mechanism (e.g. a house is registered via PUT or PUSH).
Don't misunderstand me here. The solution by #Copernic seems to work and is probably a suitable solution for some scenarios (e.g. each house has its own server and the requests need to be redirected), but for a rather simple scenario it looks to me that it is not the correct way to go.
You can override deliverRequest as stated by Alex, However my approach is that I don't pre-register the resources tree, I register resource by resource without maintaining a hierarchy.
public DynamicMessageDeliverer (List<ProxyRes> resources) {
this.resources = resources;
}
public void deliverRequest (final Exchange exchange) {
Request request = exchange.getRequest ();
List<String> path = request.getOptions ().getUriPath ();
final Resource resource = registerResources (path);
if (resource != null) {
executeResource (exchange, resource);
} else {
exchange.sendResponse (new Response (ResponseCode.NOT_FOUND));
throw new RuntimeException ("Did not find resource " + path.toString() + " requested by " + request.getSource()+":"+request.getSourcePort());
}
}
private void executeResource (final Exchange exchange, final Resource resource) {
// Get the executor and let it process the request
Executor executor = resource.getExecutor ();
if (executor != null) {
exchange.setCustomExecutor ();
executor.execute (new Runnable () {
public void run () {
resource.handleRequest (exchange);
}
});
} else {
resource.handleRequest (exchange);
}
}
private Resource registerResources (List<String> list) {
LinkedList<String> path = new LinkedList<String> (list);
String flatRequestedEndpoint = Arrays.toString (path.toArray ());
LinkedList<String> wildcards = new LinkedList <String> ();
ProxyRes retainedResource = null;
for (ProxyRes proxyRes : resources) {
String[] res = proxyRes.getPath ().replaceFirst ("/", "").split ("/");
int length = res.length;
if (length != path.size ()) {
continue;
}
String flatResEndpoint = Arrays.toString (res);
if (flatResEndpoint.equals (flatRequestedEndpoint)) {
retainedResource = proxyRes;
break;
}
boolean match = true;
for (int i = 0; i < length; i ++) {
String str = res[i];
if (str.equals ("*")) {
wildcards.add (path.get (i));
continue;
}
if (!str.equals (path.get (i))) {
match = false;
break;
}
}
if (!match) {
wildcards.clear ();
continue;
}
retainedResource = proxyRes;
break;
}
if (retainedResource == null) {
return null;
}
((AbstractResource)retainedResource.getCoapRes ()).setWildcard (wildcards);
return retainedResource.getCoapRes ();
}
Full answer code with steps is here : Eclipse Californium CoAP wildcard as url path

How to remove "no data" labels from empty nodes in GWT?

I have a widget that inherits from CellTree. If the node not have the child elements, this node can be opened and shows "no data" label.
I'd like to see nodes without child's displayed as empty.
That's how I fill the tree. My DictionaryTreeDataProvider class (relevant part):
public class DictionaryTreeDataProvider extends ListDataProvider<MValue> {
private final DictionariesServiceAsync service = GWT.create(DictionariesService.class);
...
#Override
public void onRangeChanged(HasData<MValue> result) {
service.queryDictionaryValues(range, query, new AsyncCallback<SubsetResult<MValue>>() {
#Override
public void onFailure(Throwable t) {
}
#Override
public void onSuccess(SubsetResult<MValue> result) {
getList().clear();
for (MValue value : result.items) {
getList().add(value);
}
}
});
}
}
On the server side I make EJB call which fills SubsetResult.
I found that this problem fixed in version of GWT-2.5.0-rc2 (see https://groups.google.com/forum/#!topic/google-web-toolkit/d-rFUmyHTT4).
Now everything is OK, thanks to #moutellou.
I did as he suggested:
...
#Override
public void onSuccess(SubsetResult<MValue> result) {
if (result.length == 0) {
updateRowCount(-1, true);
return;
} else {
for (MValue value : result.items) {
// some checks here
getList().add(value);
}
}
}
...
Some alternative solution. Can be defined interface that extends the interface CellTree.Resources.
In this interface must specify the path to the CSS, which override the desired style.
Interface CellTree.Resources:
public class CellTree extends AbstractCellTree implements HasAnimation,
Focusable {
...
/**
* A ClientBundle that provides images for this widget.
*/
public interface Resources extends ClientBundle {
/**
* An image indicating a closed branch.
*/
#ImageOptions(flipRtl = true)
#Source("cellTreeClosedArrow.png")
ImageResource cellTreeClosedItem();
/**
* An image indicating that a node is loading.
*/
#ImageOptions(flipRtl = true)
ImageResource cellTreeLoading();
/**
* An image indicating an open branch.
*/
#ImageOptions(flipRtl = true)
#Source("cellTreeOpenArrow.png")
ImageResource cellTreeOpenItem();
/**
* The background used for selected items.
*/
#ImageOptions(repeatStyle = RepeatStyle.Horizontal, flipRtl = true)
ImageResource cellTreeSelectedBackground();
/**
* The styles used in this widget.
*/
#Source(Style.DEFAULT_CSS)
Style cellTreeStyle();
}
...
}
Interface CustomCellTreeResources, based on CellTree.Resources:
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.user.cellview.client.CellTree;
public interface CustomCellTreeResources extends CellTree.Resources {
static final String STYLE_PATH = "components/common/client/static/custom-cell-tree.css";
#Override
#ClientBundle.Source({CellTree.Style.DEFAULT_CSS, STYLE_PATH})
CellTree.Style cellTreeStyle();
}
Overriding rule:
.cellTreeEmptyMessage {
display: none;
}
Create an instance:
private final static CellTree.Resources customCellTreeResources =
GWT.create(CustomCellTreeResources.class);
And next need to explicitly pass customCellTreeResources to the CellTree class constructor.
Message is not displayed more.
Mandatory: before filing the list, ie, before clicking on a node, the list should be cleaned( getList().clear();):
#Override
public void onRangeChanged(HasData<MValue> result) {
service.queryDictionaryValues(range, query,
new AsyncCallback<SubsetResult<MValue>>() {
#Override
public void onFailure(Throwable t) {}
#Override
public void onSuccess(SubsetResult<MValue> result) {
getList().clear();
for (MValue value : result.items) {
getList().add(value);
}
}
});
}
This is how I removed the no data label in my DataProvider
//Fetch children
int size = children.size();
if (size == 0) {
updateRowCount(-1, true); //Method called on AsyncDataProvider
return;
}
In the TreeViewModel, make sure that the isLeaf method returns true if the argument value has no children. Example:
#Override
public boolean isLeaf(Object value) {
if (value instanceof DepartmentDto) {
DepartmentDto department = (DepartmentDto) value;
return department.getEmployees().isEmpty();
} else if (value instanceof EmployeeDto) {
return true;
} else {
return false;
}
}
In this case, a department should declare itself as a leaf only if it has no employees, an employee will declare itself as a leaf, and default to false.
Note that value many also be an internal GWT node. In this example, it might not necessarily be just DepartmentDto and EmployeeDto.

How do I tell a GWT cell widget data has changed via the Event Bus?

I have a GWT Cell Tree that I use to display a file structure from a CMS. I am using a AsyncDataProvider that loads data from a custom RPC class I created. I also have a Web Socket system that will broadcast events (File create, renamed, moved, deleted etc) from other clients also working in the system.
What I am trying to wrap my head around is when I recieve one of these events, how I correctly update my Cell Tree?
I suppose this problem would be analogus to having two instances of my Cell Tree on the page, which are presenting the same server-side data and wanting to ensure that when the user updated one, that the other updated as well, via using the EventBus.
I feel this should be pretty simple but I have spent about 6 hours on it now with no headway. My code is included below:
NOTE: I am not using RequestFactory even though it may look like I am it is my custom RPC framework. Also, FileEntity is just a simple representation of a file which has a name accessible by getName().
private void drawTree() {
// fileService is injected earlier on and is my own custom rpc service
TreeViewModel model = new CustomTreeModel(new FileDataProvider(fileService));
CellTree tree = new CellTree(model, "Root");
tree.setAnimationEnabled(true);
getView().getWorkspace().add(tree);
}
private static class CustomTreeModel implements TreeViewModel {
// I am trying to use a single AsyncDataProvider so I have a single point of loading data which I can manipulate (Not sure if this is the correct way to go)
public CustomTreeModel(FileDataProvider dataProvider) {
this.provider = provider;
}
public <T> NodeInfo<?> getNodeInfo(final T value) {
if (!(value instanceof FileEntity)) {
// I already have the root File loaded in my presenter, if we are at the root of the tree, I just add it via a list here
ListDataProvider<FileEntity> dataProvider = new ListDataProvider<FileEntity>();
dataProvider.getList().add(TreeWorkspacePresenter.rootFolder);
return new DefaultNodeInfo<FileEntity>(dataProvider,
new FileCell());
} else {
// Otherwise I know that we are loading some tree child data, and I invoke the AsyncProvider to load it from the server
provider.setFocusFile(value);
return new DefaultNodeInfo<FileEntity>(provider,
new FileCell());
}
}
public boolean isLeaf(Object value) {
if(value == null || value instanceof Folder)
return false;
return true;
}
}
public class FileDataProvider extends AsyncDataProvider<FileEntity> {
private FileEntity focusFile;
private FileService service;
#Inject
public FileDataProvider(FileService service){
this.service = service;
}
public void setFocusFile(FileEntity focusFile){
this.focusFile = focusFile;
}
#Override
protected void onRangeChanged(HasData<FileEntity> display) {
service.getChildren(((Folder) focusFile),
new Reciever<List<FileEntity>>() {
#Override
public void onSuccess(List<FileEntity> files) {
updateRowData(0, files);
}
#Override
public void onFailure(Throwable error) {
Window.alert(error.toString());
}
});
}
}
/**
* The cell used to render Files.
*/
public static class FileCell extends AbstractCell<FileEntity> {
private FileEntity file;
public FileEntity getFile() {
return file;
}
#Override
public void render(Context context, FileEntity file, SafeHtmlBuilder sb) {
if (file != null) {
this.file = file;
sb.appendEscaped(file.getName());
}
}
}
Currently there is no direct support for individual tree item refresh even in the latest gwt version.
But there is a workaround for this. Each tree item is associated with an value. Using this value you can get the corresponding tree item.
In your case, i assume, you know which item to update/refresh ie you know which File Entity has changed. Use this file entity to search for the corresponding tree item. Once you get the tree item you just need to expand and collapse or collapse and expand its parent item. This makes parent item to re-render its children. Your changed file entity is one among the children. So it get refreshed.
public void refreshFileEntity(FileEntity fileEntity)
{
TreeNode fileEntityNode = getFileEntityNode(fileEntity, cellTree.getRootTreeNode()
// For expnad and collapse run this for loop
for ( int i = 0; i < fileEntityNode.getParent().getChildCount(); i++ )
{
if ( !fileEntityNode.getParent().isChildLeaf( i ) )
{
fileEntityNode.getParent().setChildOpen( i, true );
}
}
}
public TreeNode getFileEntityNode(FileEntity fileEntity, TreeNode treeNode)
{
if(treeNode.getChildren == null)
{
return null;
}
for(TreeNode node : treeNode.getChildren())
{
if(fileEntity.getId().equals( node.getValue.getId() ))
{
return node;
}
getEntityNode(fileEntity, node);
}
}
You can use the dataprovider to update the celltree.
You can update the complete cell tree with:
provider.setList(pList);
provider.refresh();
If you want to update only a special cell you can get the listwrapper from the dataprovider and only set one element.
provider.getList().set(12, element);

On Gwt TreeViewModel getNodeInfo() method

I can't understand that part, neither trying the showcase examples.
I'm using an extension of AsyncDataProvider to bind my tree to RPC service. Here's my method:
public <T> NodeInfo<?> getNodeInfo(T value) {
/*
if (value instanceof Categoria) {
dataProvider.setCurrentParent((Categoria)value);
}
*/
return new DefaultNodeInfo<Categoria>(dataProvider, new CategoriaCell());
}
"currentParent" is my stuff: except for (null => root) values, I set the parent to pass via RPC to my service. Actually, in my widget code:
dataProvider = new CategorieTreeDataProvider() {
#Override
protected void onRangeChanged(HasData<Categoria> display) {
updateTree(getCurrentParent());
}
};
private void updateTree(Categoria categoria) {
rpcService.getCategorie(categoria, new AsyncCallback<Categoria[]>() {
#Override
public void onSuccess(Categoria[] result) {
dataProvider.updateRowCount(result.length, true);
dataProvider.updateRowData(0, Arrays.asList(result));
}
#Override
public void onFailure(Throwable caught) {
Window.alert(caught.toString());
}
});
}
My rpc-server code, however, is working as expected:
#Override
public Categoria[] getCategorie(Categoria parent) {
List<Categoria> categoryList = categorieDao.listByProperty("parent", parent);
for (Categoria c : categoryList) {
if (categorieDao.listByProperty("parent", c).size() == 0) {
c.setLeaf(true);
}
}
return categoryList.toArray(new Categoria[0]);
}
**Then I add some data to my Categories: 'GrandFather', 'Father' and 'Son'.
Unfortunately, after loading my widget, I see:
The grandfather correctly, with his "+" how expected;
Then I click it and...
The grandfather disappear and I see 'Father' with his '+'
same for father -> son
I suspect the bug is in updateRowCount / updateRowData usage.**
Any ideas?
The getNodeInfo is called whenever you open a node so you have to create distinct DataProvider for each of the nodes's childs.
public <T> NodeInfo<?> getNodeInfo(T value) {
if (value == null) {
return new DefaultNodeInfo<Category>(dataProvider, new CategoriaCell());
}
else if (value instanceof Categoria) {
Category category = (Category)value;
return new DefaultNodeInfo<Grandfather>(new ListDataProvider<Grandfather>(category.getGrandFathers()),new GrandFatherCell());
}
else if (value instanceof Grandfather) {
Grandfather grandfather = (Grandfather)value;
return new DefaultNodeInfo<Father>(new ListDataProvider<Father>(granfather.getFathers()),new FatherCell());
}
else if (value instanceof Father) {
//same as above but with fathers.
}
}
The category.getGrandFathers() function can for example do a RPC request to the server or just return the list if you retrieve everything in one RPC request.
UPDATE based on comment:
So in case you have only one class and want to achieve a dynamic CellTree (number of levels are not pre-determined) you could take following approach.
public <T> NodeInfo<?> getNodeInfo(T value) {
if (value == null) {
return new DefaultNodeInfo<Category>(dataProvider, new CategoriaCell());
}
else {
Category category = (Category)value;
return new DefaultNodeInfo<Category>(new ListDataProvider<Category>(category.getSubCategories()),new CategoryCell());
}
}
category.getSubCategories() is either an RPC call which retrieves the subcategories for the current category or if the Category class is a linked list type datastructure it could just return the list of subcategories.
Each data provider updates a given "list" (child nodes of a given parent node), so you have to use a distinct data provider instance for each parent node, or your calls will update some random list.

GWT CEll Browser Real Time Update

has someone been able to correctly to update a cell browser at runtime, i.e. when u remove a node or add a node, the change is reflected immediately in the CEll Browser, because I am using a List and when i am making a change it is not being updated on the spot
You can use ListDataProvider setList(...) method for dynamic updates. Here is an example how I update cell browser via RPC:
private void loadAllData(final ListDataProvider<Data> dataProvider) {
dBservice.getAllData(new AsyncCallback<List<Data>>() {
public void onSuccess(List<Data> result) {
dataProvider.setList(result);
}
public void onFailure(Throwable caught) {
caught.printStackTrace();
}
});
}
to refresh a cellBrowser you have to close all the child on the root node.
anyway something like this
for (int i = 0; i < cellBrowser.getRootTreeNode().getChildCount(); i++) {
cellBrowser.getRootTreeNode().setChildOpen(i, false);
}
the AsyncDataProvider calls refreshes data
private final class Model implements TreeViewModel{
private List<ZonaProxy> zonaList = null;
private List<CategoriaProxy> categoriaList = null;
public void setCategoriaList(List<CategoriaProxy> categoriaList) {
this.categoriaList = categoriaList;
}
public void setListZona(List<ZonaProxy> zonaList) {
this.zonaList = zonaList;
}
#SuppressWarnings({ "unchecked", "rawtypes" })
public <T> NodeInfo<?> getNodeInfo(T value) {
CategoryDataProvider dataProvider1 = new CategoryDataProvider();
return new DefaultNodeInfo(dataProvider1, new CategoriaCell());
}
/**
* Check if the specified value represents a leaf node. Leaf nodes cannot be
* opened.
*/
public boolean isLeaf(Object value) {
if (value instanceof CategoriaProxy){
if (((CategoriaProxy) value).getLivello() == 3) {
return true;
}
}
return false;
}
}
private class CategoryDataProvider extends AsyncDataProvider<CategoriaProxy>
{
#Override
protected void onRangeChanged(HasData<CategoriaProxy> display)
{
requests.categoriaRequest().findAllCategorias(0, 8).with().fire(new Receiver<List<CategoriaProxy>>() {
#Override
public void onSuccess(List<CategoriaProxy> values) {
updateRowCount(values.size(), true);
updateRowData(0, values);
}
});
}
}
it Works.
Apparently it is not enough to change the data provider and refresh it.
You need also to force the affected cell to close and reopen it, as in this example
public void updateCellBrowser(String id) {
TreeNode node = getNode(cellBrowser.getRootTreeNode(),id);
if(node != null && ! node.isDestroyed()) {
TreeNode parent = node.getParent();
int index = node.getIndex();
parent.setChildOpen(index, false,true);
parent.setChildOpen(index, true, true);
}
}
In my particular example the cell ids are pathnames hence the following
implementation of getNode().
private TreeNode getNode(TreeNode node, String id) {
for(int i=0; i < node.getChildCount(); i++)
if(node.isChildOpen(i)) {
Object value = node.getChildValue(i);
if(value instanceof String) {
String nodeId = ((String) value);
if(id.equals(nodeId))
return node.setChildOpen(i, true);
if(id.startsWith(nodeId))
getNode(node.setChildOpen(i, true),id);
}
}
return null;
}