Skip to content

Instantly share code, notes, and snippets.

@branflake2267
Created November 16, 2018 17:10
Show Gist options
  • Save branflake2267/6351bdba8b0944675b96da088fa79433 to your computer and use it in GitHub Desktop.
Save branflake2267/6351bdba8b0944675b96da088fa79433 to your computer and use it in GitHub Desktop.
GXT 4.0.3 Load subtrees on expand, using custom loading logic.
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
import com.sencha.gxt.core.client.IdentityValueProvider;
import com.sencha.gxt.core.client.ValueProvider;
import com.sencha.gxt.data.shared.ModelKeyProvider;
import com.sencha.gxt.data.shared.Store;
import com.sencha.gxt.data.shared.TreeStore;
import com.sencha.gxt.data.shared.loader.FilterConfig;
import com.sencha.gxt.widget.core.client.button.ButtonBar;
import com.sencha.gxt.widget.core.client.container.FlowLayoutContainer;
import com.sencha.gxt.widget.core.client.container.Viewport;
import com.sencha.gxt.widget.core.client.event.ExpandItemEvent;
import com.sencha.gxt.widget.core.client.event.ExpandItemEvent.ExpandItemHandler;
import com.sencha.gxt.widget.core.client.event.TriggerClickEvent;
import com.sencha.gxt.widget.core.client.event.TriggerClickEvent.TriggerClickHandler;
import com.sencha.gxt.widget.core.client.form.StoreFilterField;
import com.sencha.gxt.widget.core.client.tree.Tree;
import com.sencha.gxt.widget.core.client.tree.Tree.TreeNode;
import com.sencha.gxt.widget.core.client.tree.TreeView;
public class TreeWithSimulatedLoadingExample implements EntryPoint {
// ---- add loading to tree grid
public class TreeViewExt<M> extends TreeView<M> {
/**
* Display the loading icon
*/
// ------ Turn on/off loading
public void setLoading(M m, boolean turnon) {
TreeNode<M> node = findNode(m);
if (turnon) {
onIconStyleChange(node, treeExt.getAppearance().loadingIcon());
} else {
// ----- Added a cast for TreeGrid method
onIconStyleChange(node, treeExt.calculateIconStyle((Data) m));
}
}
}
public class TreeExt<M, C> extends Tree<M, C> {
public TreeExt(TreeStore<M> store, ValueProvider<? super M, C> valueProvider) {
super(store, valueProvider);
}
// ----- Change visibility to public
@Override
public ImageResource calculateIconStyle(M model) {
return super.calculateIconStyle(model);
}
}
/**
* Mark which parents have been loaded. This will determine if the data has already been loaded.
*/
private Set<Data> hasBeenLoadedList = new HashSet<Data>();
private TreeStore<Data> treeStore;
private TreeExt<Data, Data> treeExt;
private TreeViewExt<Data> treeView;
private KeyProvider keyProvider;
private FlowLayoutContainer flowContainer;
public Widget asWidget() {
if (flowContainer == null) {
keyProvider = new KeyProvider();
treeStore = new TreeStore<Data>(keyProvider);
final StoreFilterField<Data> filterField = new StoreFilterField<Data>() {
@Override
protected boolean doSelect(Store<Data> store, Data parent, Data item, String filter) {
GWT.log("filter=" + filter.toLowerCase() + " name=" + item.getName().toLowerCase());
return item.getName().toLowerCase().contains(filter);
}
};
filterField.bind(treeStore);
filterField.addTriggerClickHandler(new TriggerClickHandler() {
@Override
public void onTriggerClick(TriggerClickEvent event) {
GWT.log("trigger click");
// ~~~ workaround
treeExt.getTreeStore().setEnableFilters(false);
}
});
filterField.addValueChangeHandler(new ValueChangeHandler<Data>() {
@Override
public void onValueChange(ValueChangeEvent<Data> event) {
GWT.log("value change");
}
});
treeView = new TreeViewExt<Data>();
// identity value provider to pass the model to the cell renderer
treeExt = new TreeExt<Data, Data>(treeStore, new IdentityValueProvider<Data>("name")) {
@Override
protected boolean hasChildren(Data model) {
// 2. ~~~~~~~ Determine if the node has children, and if so, means its a
// folder with children
// Note: this could be a boolean value to signify the node is a folder
// with children
return model.getChildCount() > 0;
}
};
treeExt.setView(treeView);
treeExt.setWidth(300);
treeExt.setBorders(true);
treeExt.setExpandOnFilter(false);
treeExt.addExpandHandler(new ExpandItemHandler<Data>() {
@Override
public void onExpand(ExpandItemEvent<Data> event) {
// ~~~~~~ 3. load more children on expansion
Data parent = event.getItem();
rpcRequestToGetChildNodes(parent);
}
});
// ~~~~ single selection handler -----
treeExt.getSelectionModel().addSelectionHandler(new SelectionHandler<Data>() {
@Override
public void onSelection(SelectionEvent<Data> event) {
Data item = event.getSelectedItem();
GWT.log("\t item selected name=" + item.getName());
}
});
ButtonBar buttonBar = new ButtonBar();
buttonBar.add(filterField);
flowContainer = new FlowLayoutContainer();
flowContainer.add(buttonBar);
flowContainer.add(treeExt);
// ~~~~~ 1. initial load - load the root nodes
rpcRequestToGetRootNodes();
}
return flowContainer;
}
@Override
public void onModuleLoad() {
Viewport viewport = new Viewport();
viewport.add(asWidget());
RootPanel.get().add(viewport);
}
/**
* Suggestion: Go fetch all the nodes form the server that match the server, include their parents and on return add
* them to the tree store.
*/
protected void rpcRequestToGetFilteredNodes(List<FilterConfig> filterConfig) {
FilterConfig filter = filterConfig.get(0);
String filterValue = filter.getValue();
System.out.println("filterValue=" + filterValue);
}
/**
* Pretend RPC call to get data from server
*/
private void rpcRequestToGetRootNodes() {
// Pretend this is an RPC call for initial load.
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
public void execute() {
// RPC call to get root nodes
List<Data> rootNodes = getRpcRequestWithDatas(null);
// On RPC return add to treestore
treeStore.add(rootNodes);
}
});
}
/**
* Pretend RPC call to get data server and add it to treestore.
*
* Note: this won't replace child if it's already loaded.
*
* @param parent
*/
private void rpcRequestToGetChildNodes(final Data parent) {
if (hasBeenLoadedList.contains(parent)) {
// only load the data once
System.out.println("Skipping loading data for parent=" + parent);
return;
}
// display the loading icon
// ---- Turn on loading
treeView.setLoading(parent, true);
// Pretend this is an RPC call for initial load.
Timer timerLikeRpc = new Timer() {
@Override
public void run() {
// ---- Turn off loading
treeView.setLoading(parent, false);
// RPC call to get root nodes
List<Data> childNodes = getRpcRequestWithDatas(parent);
// On RPC return, add the nodes to the treestore
// Since expanding can happen more than once, check to see if the node
// exists already
for (Data child : childNodes) {
// check to see if the model has been already been loaded
// (TODO if node changes to different branch, then it needs to removed and added)
Data dataExists = treeStore.findModelWithKey(keyProvider.getKey(child));
if (dataExists == null) {
treeStore.add(parent, child);
hasBeenLoadedList.add(parent);
}
}
}
};
timerLikeRpc.schedule(1000);
}
/**
* Server request goes to this
*/
private List<Data> getRpcRequestWithDatas(Data parent) {
List<Data> list = new ArrayList<Data>();
if (parent == null) {
Data a = new Data("0", "A", 0);
a.setChildCount(5);
Data b = new Data("1", "B", 1);
b.setChildCount(4);
Data c = new Data("2", "C", 2);
c.setChildCount(3);
list.add(a);
list.add(b);
list.add(c);
} else {
String k = parent.getName();
int c = 0;
if (k.contains("A")) {
c = 5;
} else if (k.contains("B")) {
c = 4;
} else {
c = 3;
}
for (int i = 0; i < c; i++) {
String id = parent.getId() + " : " + i;
Data d = new Data(id, k + "+" + i, 3);
d.setChildCount(0);
list.add(d);
System.out.println("id=" + id + " name=" + d.getName());
// first child has some children
if (i == 0 && d.getName().equals("A+0")) {
d.setChildCount(5);
}
}
}
return list;
}
class KeyProvider implements ModelKeyProvider<Data> {
@Override
public String getKey(Data item) {
return item.getId().toString();
}
}
public class Data implements Serializable {
private String id;
private String name;
private int value;
/**
* Record if this is a folder node and it has children it could load This could be a boolean value too. See
* TreeGrid.hasChildren.
*/
private int childCount;
protected Data() {
}
public Data(String id, String name, int value) {
this.id = id;
this.name = name;
this.value = value;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getValue() {
return value;
}
public void setId(int value) {
this.value = value;
}
@Override
public String toString() {
return name;
}
public void setChildCount(int childCount) {
this.childCount = childCount;
}
public int getChildCount() {
return childCount;
}
}
}
@branflake2267
Copy link
Author

screen shot 2018-11-16 at 9 10 30 am

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment