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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With