Tree Menu in GWT

103 views
Skip to first unread message

Alex

unread,
Feb 22, 2007, 4:35:49 PM2/22/07
to Google Web Toolkit
Hi,

Has anyone ever done a tree menu based on a database table in GWT.
I've been trying all morning and afternoon and have NOT been
successful.

[b] If you have can you post your code/samples online please? [/b]

I've tried the DynaTable sample by modifying it to query the names
from my table. That does not work. It somehow does not read the source
code I'm writing. Whatever changes I make to the serverside class
(SchoolCalendarServiceImpl.java) does not reflect when I run the
application using either DynaTable-compile.cmd or DynaTable-
shell.cmd.

After that I tried the sample on otn.oracle.com (http://www.oracle.com/
technology/pub/articles/dubois-gwt.html). That doesnt work either. I
keep getting this error:

[ERROR] Unable to load module entry point class
otn.todo.client.TodoApp
java.lang.NullPointerException: null
at otn.todo.client.TodoApp.onModuleLoad(TodoApp.java:61)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:
39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:
25)
at java.lang.reflect.Method.invoke(Method.java:585)
at com.google.gwt.dev.shell.ModuleSpace.onLoad(ModuleSpace.java:138)
at
com.google.gwt.dev.shell.BrowserWidget.attachModuleSpace(BrowserWidget.java:
313)
at com.google.gwt.dev.shell.ie.BrowserWidgetIE6.access
$100(BrowserWidgetIE6.java:34)
at
com.google.gwt.dev.shell.ie.BrowserWidgetIE6$External.gwtOnLoad(BrowserWidgetIE6.java:
61)
at
com.google.gwt.dev.shell.ie.BrowserWidgetIE6$External.invoke(BrowserWidgetIE6.java:
106)
at
com.google.gwt.dev.shell.ie.IDispatchImpl.Invoke(IDispatchImpl.java:
274)

Working with GWT has been the most frustrating thing for me today!

Any help is greatly appreciated,
Alex

Chad Bourque

unread,
Feb 22, 2007, 5:06:34 PM2/22/07
to Google-We...@googlegroups.com
Alex,
 
WARNING: Long post follows (with code).
 
It's not a menu, but a treeview that is completely data driven. It should show you it can (and how it can) be done. I have it broken into a few different classes. First, my EntryPoint class is very basic as in all it does is create the tree and add it to the RootPanel:
 

package com.tuesdaymorning.datawarehouse.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.RootPanel;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class Analysis implements EntryPoint {
 private final AnalysisTree tree = new AnalysisTree();

 /**
  * This is the entry point method.
  */
 public void onModuleLoad() {
  RootPanel.get().add(tree);
 }
}

 
 
Next, is the tree class itself. It extends Tree to implement some RPC to get to the database:
 

package com.tuesdaymorning.datawarehouse.client;

import com.google.gwt.user.client.Cookies;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Tree;
import com.google.gwt.user.client.ui.TreeItem ;
import com.google.gwt.user.client.ui.TreeListener;

public class AnalysisTree extends Tree implements TreeListener {
 public AnalysisTree() {
  addTreeListener(this);
  buildTree();
 }

 public void buildTree() {
  AnalysisService.RPC.getInstance().getReports(0,
    Cookies.getCookie("userName"), new AsyncCallback() {
   public void onFailure(Throwable caught) {
    Window.alert (caught.getMessage());
   }

   public void onSuccess(Object result) {
    AnalysisTO[] rto = (AnalysisTO[])result;

    for (int i = 0; i < rto.length; i++) {
     addItem(new AnalysisNode(rto[i]));
    }
   }
  });
 }

 public void onTreeItemSelected(TreeItem item) {
  ((AnalysisNode)item).onSelect();
 }

 public void onTreeItemStateChanged(TreeItem item) {
  if (item.getState()) {
   ((AnalysisNode)item).expand(false);
  }
 }
}

 
Next, is the node subclass of TreeItem and more of the work is done here because I use delayed instantiation on the tree. The child nodes are only loaded when the parent node is expanded, but once loaded, they don't reload. It looks like this:
 

package com.tuesdaymorning.datawarehouse.client;

import com.google.gwt.user.client.Cookies;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.TreeItem;

public class AnalysisNode extends TreeItem {
 private String stub = "Loading...";
 AnalysisTO data = null;

 public AnalysisNode() {
  super();
  setHTML(stub);
 }

 public AnalysisNode(AnalysisTO to) {
  super(to.getDisplay());
  data = to;
  addStub();
 }

 private void addStub() {
  if (hasChildren()) {
   addItem(new AnalysisNode());
  }
 }

 public boolean hasChildren() {
  return (hasData() && data.hasChildren());
 }

 public boolean hasData() {
  return (data != null);
 }

 public boolean hasStub() {
  return (hasData() && !((AnalysisNode)getChild(0)).hasData());
 }

 public String getStub() {
  return stub;
 }

 public void setStub(String html) {
  stub = html;
 }

 public int getID() {
  return (hasData() ? data.getId() : 0);
 }

 public void expand(boolean reload) {
  if (hasStub() || reload) {
   AnalysisService.RPC.getInstance().getReports(getID(),
     Cookies.getCookie("userName"), new AsyncCallback() {
    public void onFailure(Throwable caught) {
     Window.alert(caught.getMessage());
    }

    public void onSuccess(Object result) {
     AnalysisTO[] rto = (AnalysisTO[])result;

     removeItems();

     for (int i = 0; i < rto.length; i++) {
      addItem(new AnalysisNode(rto[i]));
     }
    }
   });
  }
 }

 public void onSelect() {
  if (hasData()) {
   if (data.getUrl() != null) {
    Window.open(data.getUrl(), "reportPreview", "");
   }
  }
 }
}

 
I also have a transfer object used as the transport for the RPC calls:
 

package com.tuesdaymorning.datawarehouse.client;

import com.google.gwt.user.client.rpc.IsSerializable;

public class AnalysisTO implements IsSerializable {
 private int id;
 private String display;
 private int parent;
 private String url;
 private int children;

 public AnalysisTO() {}

 public AnalysisTO(int id, String display, int parent, String url, int children) {
  load(id, display, parent, url, children);
 }

 public void load(int id, String display, int parent, String url, int children) {
  this.id = id;
  this.display = display;
  this.parent = parent;
  this.url = url;
  this.children = children;
 }

 public String getDisplay() {
  return display;
 }

 public int getId() {
  return id;
 }

 public int getParent() {
  return parent;
 }

 public String getUrl() {
  return url;
 }

 public int getChildren() {
  return children;
 }

 public boolean hasChildren() {
  return (children > 0);
 }
}

 
Then, there is the RPC piece itself. It, of course, consists of 3 classes. The first RPC class is the main interface:
 

package com.tuesdaymorning.datawarehouse.client;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.SerializableException;
import com.google.gwt.user.client.rpc.ServiceDefTarget;

public interface AnalysisService extends RemoteService {
 public AnalysisTO[] getReports(int id, String alias)
   throws SerializableException;

 /**
  * Utility class used to access a static instance of <code>
  * AnalysisServiceAsync</code> which is called like this:
  * <br /><br />&nbsp;&nbsp;&nbsp;&nbsp;
  * <code>AnalysisServiceAsync rpc = AnalysisService.RPC.getInstance();</code>
  */
 public static class RPC {
  private static AnalysisServiceAsync rpc;

  public static AnalysisServiceAsync getInstance() {
   if (rpc == null) {
    rpc = (AnalysisServiceAsync) GWT.create(AnalysisService.class);
    ((ServiceDefTarget)rpc).setServiceEntryPoint(
      GWT.getModuleBaseURL () + "/Analysis");
   }

   return rpc;
  }
 }
}

Then, there is the asyncronous interface:
 

package com.tuesdaymorning.datawarehouse.client;

import com.google.gwt.user.client.rpc.AsyncCallback;

public interface AnalysisServiceAsync {
 public void getReports(int id, String alias, AsyncCallback callback);
}

 
And finally, there is the implementation class for the server package:
 

package com.tuesdaymorning.datawarehouse.server;

import java.sql.ResultSet;
import java.util.ArrayList;

import com.google.gwt.user.client.rpc.SerializableException;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.tuesdaymorning.data.QueryList;
import com.tuesdaymorning.data.SqlList;
import com.tuesdaymorning.datawarehouse.client.AnalysisService;
import com.tuesdaymorning.datawarehouse.client.AnalysisTO;

public class AnalysisServiceImpl extends RemoteServiceServlet
  implements AnalysisService {
 private static final long serialVersionUID = 200610131130L;

 public AnalysisTO[] getReports(int id, String alias)
   throws SerializableException {
  String[] p = {String.valueOf(id), alias};

  ResultSet rs = SqlList.DEFAULT.getResultSet(QueryList.ANALYSIS_GET, p);

  ArrayList<AnalysisTO> list = new ArrayList<AnalysisTO>();

  try {
   while (rs.next()) {
    list.add(new AnalysisTO(rs.getInt("portal_analysis_id"),
      rs.getString("display"),
      rs.getInt("parent_id"),
      rs.getString("url"),
      rs.getInt("children")));
   }

   return list.toArray(new AnalysisTO[0]);
  } catch (Throwable caught) {
   throw new SerializableException(caught.getMessage());
  }
 }
}

 
That's all there is to it. If you have any questions, please feel free to ask.
 
HTH,
Chad
at com.google.gwt.dev.shell.ModuleSpace.onLoad (ModuleSpace.java:138)
Reply all
Reply to author
Forward
0 new messages