On Monday, July 30, 2012 10:02:03 PM UTC+2, Thad wrote:I have a CellTree in which I want to represent something similar to a directory listing (actually represented in database records):public class DirectoryObject implements Serializable {public String name;public String type; // 'file' or 'folder'public int group;...}This listing comes from a server application which the user must log into. Naturally I can't call the RPC to populate the tree until the login takes place.My wish is to draw the UI and upon login (or upon pressing a 'List' or 'Refresh' button to return an ArrayList<DirectoryObject>. From this I populate the previously empty tree. Objects of type 'folder' will be the branch nodes and will require a new RPC call with the name as a parameter to find the children (null gets me the highest level).My question is how, once the empty tree is present, to trigger that call and start my listing. So far I've got what you see below, but I'm not sure if it's right and I'm stumped on the UiHandler for my list button (at the very bottom). I'm trying to follow the CellTree examples, but they use static data or don't start empty.public class DirectoryPanel extends Composite {private static DirectoryPanelUiBinder uiBinder = GWT.create(DirectoryPanelUiBinder.class); interface DirectoryPanelUiBinder extendsUiBinder<Widget, DirectoryPanel> {}private static class MyDataProvider extends AsyncDataProvider<DirectoryObject> { private String folderName;public MyDataProvider(DirectoryObject directory) {if (directory != null)folderName = directory.name;}@Overrideprotected void onRangeChanged(HasData<DirectoryObject> display) { final Range range = display.getVisibleRange();AsyncCallback<ArrayList<DirectoryObject>> callback = new AsyncCallback<ArrayList<DirectoryObject>>() { @Overridepublic void onFailure(Throwable caught) {Window.alert((new GwtOptixException(caught)).getMessage()); }@Overridepublic void onSuccess(ArrayList<DirectoryObject> result) { int start = range.getStart();GWT.log("onRangeChanged, start: "+start);updateRowData(start, result);}};Cold.getRpcService().getDirectoryListing( folderName, callback); }}private static class DirectoryTreeModel implements TreeViewModel {private SingleSelectionModel<DirectoryObject> selectionModel = new SingleSelectionModel<DirectoryObject>(); public DirectoryTreeModel() {selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() { public void onSelectionChange(SelectionChangeEvent event){ /* Huh?but there's no getSelectedObject() in SelectionChangeEvent*///DirectoryObject rec = (DirectoryObject)event.getSelectedObject();
It's actually selectionModel.getSelectedObject() that returns your real DirectoryObject.
}});}@Overridepublic <T> NodeInfo<?> getNodeInfo(T arg0) {if (arg0 instanceof DirectoryObject) {Cell<DirectoryObject> cell = new AbstractCell<DirectoryObject>() { @Overridepublic void render(Context context, DirectoryObject value,SafeHtmlBuilder sb) {if (value != null) {sb.appendEscaped(value.name);}}};MyDataProvider provider = new MyDataProvider((DirectoryObject)arg0); return new DefaultNodeInfo<DirectoryObject>(provider, cell, selectionModel, null); // or return new DefaultNodeInfo<DirectoryObject>(provider, cell); ??
The first line: generally you should provide a selection model for all your nodes if you want to do something when they are selected (the actual expansion, if not a leaf, is a provider's job).}return null;}@Overridepublic boolean isLeaf(Object arg0) {return arg0 != null && ((DirectoryObject)arg0).name != null &&((DirectoryObject)arg0).type.equals('file'); }}@UiField(provided = true)CellTree tree;@UiFieldButton list;DirectoryTreeModel treeModel;public DirectoryPanel() {treeModel = new DirectoryTreeModel();tree = new CellTree(treeModel, null);initWidget(uiBinder.createAndBindUi(this)); }@UiHandler("list")void onList(ClickEvent event) {// What here??}}I'd:
- create the cell tree only if the user has logged in (and show something like an empty message);
- create a root null node (as you did) but refuse the expansion/selection until the user has logged in (probably an async provider's job, i.e., the inner RPC is used in an authentication mechanism and refuses requests from unauthenticated clients);
- create a default root node that does nothing at all, backed by a no-op (null) selection model and when the used logs in, replace it with the real selection model (I think the only way is re-instantiate the cell tree).
I think the best way to programmatically select a node is by using the selection model, although I don't remember if it also expand inner nodes.
Hope that helps.
Thanks, Andrea.
I think (hope?) I'm getting closer. I can trigger my RPC call and get back a List of my objects, but I'm not seeing the magic that converts that list to a visible tree in my browser.
I've modified my data provider's instantiation to
public MyDataProvider(DirectoryObject directory) {
GWT.log("new data provider");
if (directory != null)
folderName = directory.name;
AsyncCallback<ArrayList<DirectoryObject>> callback =
new AsyncCallback<ArrayList<DirectoryObject>>() {
@Override
public void onFailure(Throwable caught) {
Window.alert((new MyGwtException(caught)).getMessage());
}
@Override
public void onSuccess(ArrayList<DirectoryObject> result) {{
GWT.log("got "+result.size()+" rows");
updateRowCount(result.size(), true);
updateRowData(0, result);
}
};
MyApp.getRpcService().getDirectoryListing(folderName, callback);
}
I'm wondering, though, about the calls to updateRowCount() and updateRowData() and the onRangeChanged() (which is still the same). These calls are shown in the only CellTree AsyncDataProvider example I can find--https://groups.google.com/forum/?start&hl=en#!searchin/google-web-toolkit/CellTree$20asyncdataprovider/google-web-toolkit/jdQLj_oZTek/fuKmFMrbghsJ
Is this right? It looks like CellTable stuff. There's no HasData<T> for CellTree. What fills in the CellTree?
The tree is declared in UiBinder with a null root. But since a null is also the condition for the server to start at the root of my directory tree, I test for login in my model:
@Override
public <T> NodeInfo<?> getNodeInfo(T value) {
GWT.log("getNodeInfo()");
if (value == null) {
GWT.log("value is null");
if (MyApp.isLoggedIn()) {
GWT.log("user is logged in");
// Create a cell to display a folder.
Cell<DirectoryObject> cell = new AbstractCell<DirectoryObject>() {
@Override
public void render(Context context, DirectoryObject value,
SafeHtmlBuilder sb) {
if (value != null) {
sb.appendEscaped(value.name);
}
}
};
// Return a node info that pairs the data provider and the cell.
MyDataProvider provider = new MyDataProvider(null);
return new DefaultNodeInfo<DirectoryObject>(provider, cell);
}
else
return null;
}
else if (value instanceof DirectoryObject) {
DirectoryObject rec = (DirectoryObject) value;
if (rec.type.equals("folder")) {
Cell<DirectoryObject> cell = new AbstractCell<DirectoryObject>() {
@Override
public void render(Context context, DirectoryObject value,
SafeHtmlBuilder sb) {
if (value != null) {
sb.appendEscaped(value.name);
}
}
};
// Return a node info that pairs the data provider and the cell.
MyDataProvider provider = new MyDataProvider(rec);
return new DefaultNodeInfo<DirectoryObject>(provider, cell);
}
else { // it's a file
Cell<DirectoryObject> cell = new AbstractCell<DirectoryObject>() {
@Override
public void render(Context context, DirectoryObject value,
SafeHtmlBuilder sb) {
if (value != null) {
sb.appendEscaped(value.name);
}
}
};
// Return a node info that pairs the data provider and the cell.
MyDataProvider provider = new MyDataProvider(rec);
return new DefaultNodeInfo<DirectoryObject>(provider, cell, selectionModel, null);
}
}
return null;
}
I'm assuming this code creates a cell with the name from my DirectoryObject (later I want to expand this to add a folder icon).
My button's action is now
@UiHandler("list")
void onList(ClickEvent event) {
treeModel.getNodeInfo(null);
}
When I click the button I can see the log results I expect:
00:00:42.800 [INFO] getNodeInfo()
00:00:42.800 [INFO] value is null
00:00:42.800 [INFO] user is logged in
00:00:42.801 [INFO] new data provider
00:00:49.376 [INFO] got 31 rows
However I see nothing in the browser. Firebug shows an empty <div> where the CellTree belongs:
<div style="overflow: auto; position: relative; height: 200px; width: 100px;">
<div style="position: relative;">
<div class="GPBYFDEAG GPBYFDEKK" __gwtcellbasedwidgetimpldispatchingfocus="true" __gwtcellbasedwidgetimpldispatchingblur="true"></div>
</div>
</div>
What magic am I missing that turns my ArrayList<DirectoryObject> into the cells of a CellTree?
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To view this discussion on the web visit https://groups.google.com/d/msg/google-web-toolkit/-/ZzdC6NJej9UJ.
To post to this group, send email to google-web-toolkit@googlegroups.com.
To unsubscribe from this group, send email to google-web-toolkit+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.
No comments:
Post a Comment