Programmatically refresh a Gwt CellTree
Asked Answered
T

2

6

I want to fire the "open root node" event on my current working CellTree, which now has the following behaviour:

@Override
    public <T> NodeInfo<?> getNodeInfo(final T value) {
        return new DefaultNodeInfo<Categoria>(
                (value instanceof Categoria) ? 
                        createBranchDataProvider((Categoria)value) :
                        rootDataProvider, 
                new CategoriaCell()
        );
    }

private AsyncDataProvider<Categoria> createRootDataProvider() {
        AsyncDataProvider<Categoria> dataProvider = new AsyncDataProvider<Categoria>() {
            @Override
            protected void onRangeChanged(HasData<Categoria> display) {
                AsyncCallback<Categoria[]> cb = new AsyncCallback<Categoria[]>() {
                    @Override
                    public void onSuccess(Categoria[] result) {
                        updateRowCount(result.length, true);
                        updateRowData(0, Arrays.asList(result));
                    }
                    @Override
                    public void onFailure(Throwable caught) {
                        Window.alert(caught.toString());
                    }
                };  
                rpcService.getCategorie(cb);
            }
        };
        return dataProvider;
    }

How can I fire that "onRangeChanged" event, to refresh my level-1 nodes?

What is my convenience method missing?

private void updateTree() {     
        TreeNode rootTreeNode = cellTree.getRootTreeNode();
        for (int i = 0; i < rootTreeNode.getChildCount(); i++) {
            rootTreeNode.setChildOpen(i, false);
        }
        // HOW TO REFRESH LEVEL-1 NODES?
    }
Tandie answered 30/8, 2011 at 7:29 Comment(0)
C
2

The Level-1 nodes (I suppose you the mean below the root node) can not be refreshed the way you are doing it.

You have to store the instance of your dataProvider for the level-1 nodes somewhere. Later when you refresh your list you have to update your stored dataProvider for your level-1 nodes.
The nodes below the level-1 can be refreshed the way you are doing it. Because as soon as you close the level 1 nodes (that is what you are doing in the updateTree method) and the next time you open it getNodeInfo will be called and the updated Subcategories will be retrieved and displayed in the CellTree.

UPDATE

For refreshing the CellWidgets which is attached to AsyncDataProvider you will probably have to extend the AsyncDataProvider and either extract the RPC call to a getData() method which is called in the onRangeChanged() method or create an interface with a refresh method and implement it in your custom AsyncDataProvider which calls the protected onRangeChanged() method.

Cassaundra answered 31/8, 2011 at 7:38 Comment(1)
<<Later when you refresh your list you have to update your stored dataProvider for your level-1 nodes.>> Good! ^___^ but... HOW?!? -.-' I mean, the only method available on the provider is updateRowData(), do I have to duplicate the rpc code present in onRangeChanged(), or can I simply trigger the "range changed" event in some way?? thanksTandie
H
4

Working example. Add reference to DataProvider (and parent Node) (MyMenuItem and MyCell with DataProvider in my code). After adding element refresh parent.

public class MyMenuItem {
    private String name;
    private String action; //some data
    private int level; //if needed
    private ArrayList<MyMenuItem> list; //nodes childrens
    private MyMenuItem parent; //track internal parent
    private MyCell cell; //for refresh - reference to visual component

    public void setCell(MyCell cell) {
        this.cell = cell;
    }
    public void refresh() {
      if(parent!=null) {
          parent.refresh();
      }
      if (cell!=null) {
          cell.refresh(); //refresh tree
      }
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAction() {
        return action;
    }
    public void setAction(String action) {
        this.action = action;
    }
    public MyMenuItem(String name, String action) {
        super();
        parent = null;
        level = 0;
        this.name = name;
        this.action = action;
        list = new ArrayList<MyMenuItem>();
    }
    public MyMenuItem(String name) {
        this(name, "");
    }
    public void addSubMenu(MyMenuItem m) {
        m.level = this.level+1;
        m.parent = this;
        list.add(m);
    }

    public boolean hasChildrens() {
        return list.size()>0;
    }
    public int getLevel() {
        return level;
    }
    public void setLevel(int level) {
        this.level = level;
    }
    public ArrayList<MyMenuItem> getList() {
        return list;
    }
    public MyMenuItem getParent() {
        return parent;
    }
}

public class MyTreeModel implements TreeViewModel {
    private MyMenuItem officialRoot; //default not dynamic
    private MyMenuItem studentRoot; //default not dynamic
    private MyMenuItem testRoot; //default not dynamic
    private MyMenuItem root;

    public MyMenuItem getRoot() { // to set CellTree root
        return root;
    }

    public MyTreeModel() {
        root = new MyMenuItem("root");
        // Default items
        officialRoot = new MyMenuItem("Official"); //some basic static data
        studentRoot = new MyMenuItem("Student");
        testRoot = new MyMenuItem("Test");
        root.addSubMenu(officialRoot);
        root.addSubMenu(studentRoot);
        root.addSubMenu(testRoot);
    }

    //example of add add logic
    private void addNew(MyMenuItem myparent, String name, String uid) {
        myparent.addSubMenu(new MyMenuItem(name, uid)); 
        myparent.refresh(); //HERE refresh tree
    }   

    @Override
    public <T> NodeInfo<?> getNodeInfo(T value) {
        ListDataProvider<MyMenuItem> dataProvider;
        MyMenuItem myValue = null;
        if (value == null) { // root is not set
            dataProvider = new ListDataProvider<MyMenuItem>(root.getList());
        } else {
            myValue = (MyMenuItem) value;
            dataProvider = new ListDataProvider<MyMenuItem>(myValue.getList());
        }
        MyCell cell = new MyCell(dataProvider); //HERE Add reference
        if (myValue != null)
            myValue.setCell(cell);
        return new DefaultNodeInfo<MyMenuItem>(dataProvider, cell);
    }

    @Override
    public boolean isLeaf(Object value) {
        if (value instanceof MyMenuItem) {
            MyMenuItem t = (MyMenuItem) value;
            if (!t.hasChildrens())
                return true;
            return false;
        }
        return false; 
    }

}

public class MyCell extends AbstractCell<MyMenuItem> {
        ListDataProvider<MyMenuItem> dataProvider; //for refresh
        public MyCell(ListDataProvider<MyMenuItem> dataProvider) {
          super("keydown","dblclick");
          this.dataProvider = dataProvider;
        }
        public void refresh() {
            dataProvider.refresh(); 
        }
        @Override
        public void onBrowserEvent(Context context, Element parent, MyMenuItem value,
            NativeEvent event, ValueUpdater<MyMenuItem> valueUpdater) {
          if (value == null) {
            return;
          }
          super.onBrowserEvent(context, parent, value, event, valueUpdater);
          if ("click".equals(event.getType())) {
            this.onEnterKeyDown(context, parent, value, event, valueUpdater);
          }
          if ("dblclick".equals(event.getType())) {
              this.onEnterKeyDown(context, parent, value, event, valueUpdater);
            }
        }

        @Override
        public void render(Context context, MyMenuItem value, SafeHtmlBuilder sb) {
          if (value == null) {
            return;
          }
          sb.appendEscaped(value.getName());
          //add HERE for better formating
        }


        @Override
        protected void onEnterKeyDown(Context context, Element parent,
                MyMenuItem value, NativeEvent event, ValueUpdater<MyMenuItem> valueUpdater) {
          Window.alert("You clicked "+event.getType()+" " + value.getName());
        }


}

in module add

 treeModel = new MyTreeModel();
 tree = new CellTree(treeModel,treeModel.getRoot());
Hospitality answered 11/11, 2011 at 13:22 Comment(0)
C
2

The Level-1 nodes (I suppose you the mean below the root node) can not be refreshed the way you are doing it.

You have to store the instance of your dataProvider for the level-1 nodes somewhere. Later when you refresh your list you have to update your stored dataProvider for your level-1 nodes.
The nodes below the level-1 can be refreshed the way you are doing it. Because as soon as you close the level 1 nodes (that is what you are doing in the updateTree method) and the next time you open it getNodeInfo will be called and the updated Subcategories will be retrieved and displayed in the CellTree.

UPDATE

For refreshing the CellWidgets which is attached to AsyncDataProvider you will probably have to extend the AsyncDataProvider and either extract the RPC call to a getData() method which is called in the onRangeChanged() method or create an interface with a refresh method and implement it in your custom AsyncDataProvider which calls the protected onRangeChanged() method.

Cassaundra answered 31/8, 2011 at 7:38 Comment(1)
<<Later when you refresh your list you have to update your stored dataProvider for your level-1 nodes.>> Good! ^___^ but... HOW?!? -.-' I mean, the only method available on the provider is updateRowData(), do I have to duplicate the rpc code present in onRangeChanged(), or can I simply trigger the "range changed" event in some way?? thanksTandie

© 2022 - 2024 — McMap. All rights reserved.