Created
November 16, 2018 17:10
-
-
Save branflake2267/6351bdba8b0944675b96da088fa79433 to your computer and use it in GitHub Desktop.
GXT 4.0.3 Load subtrees on expand, using custom loading logic.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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; | |
| } | |
| } | |
| } |
Author
branflake2267
commented
Nov 16, 2018

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