Note that there are some explanatory texts on larger screens.

plurals
  1. POGWT CellTree with an optional pop-up menu triggered on click of a TreeNode
    primarykey
    data
    text
    <p>I would like to craft a GWT CellTree with an optional pop-up menu triggered on click of a TreeNode.</p> <p>So I've crafted a CustomTreeModel. Here it is:</p> <pre><code>public class CustomTreeModel implements TreeViewModel { /** * Save visited URL. We'll use it later to determine if tree node needs to be opened. * We decode the query string in URL so that token has a chance of matching (e.g., convert %20 to space). */ private final String url = URL.decodeQueryString(Window.Location.getHref()); private final NavNode navNode; private final TokenService&lt;MainEventBus&gt; tokenService; /** * A selection model shared across all nodes in the tree. */ private final SingleSelectionModel&lt;NavNode&gt; selectionModel = new SingleSelectionModel&lt;NavNode&gt;(); public CustomTreeModel(NavNode navNode, TokenService tokenService) { this.navNode = navNode; this.tokenService = tokenService; } @Override public &lt;T&gt; NodeInfo&lt;?&gt; getNodeInfo(T value) { DefaultNodeInfo&lt;NavNode&gt; result = null; if (value == null) { // LEVEL 0. // We passed null as the root value. Return the immediate descendants. result = new DefaultNodeInfo&lt;NavNode&gt;(getDataProvider(navNode), getCell(), selectionModel, null); } else if (value instanceof NavNode) { // all other levels // We pass a node, return its immediate descendants. // select node if URL contains params in node's target or one of node's option's target NavNode currNode = (NavNode) value; if (isSelected(currNode)) { selectionModel.setSelected(currNode, true); } if (currNode.hasOptions()) { // add pop-up menu to this node if it has options result = new DefaultNodeInfo&lt;NavNode&gt;(getDataProvider(currNode), getCell(), selectionModel, new NodeSelectionEventManager(currNode), null); } else { result = new DefaultNodeInfo&lt;NavNode&gt;(getDataProvider(currNode), getCell(), selectionModel, null); } } return result; } @Override public boolean isLeaf(Object value) { boolean result = true; if (value == null) { if (navNode.hasChildren()) { result = false; } } else if (value instanceof NavNode) { NavNode currentNode = (NavNode) value; if (currentNode.hasChildren()) { result = false; } } return result; } // Create a data provider that contains the immediate descendants. private ListDataProvider&lt;NavNode&gt; getDataProvider(NavNode node) { return new ListDataProvider&lt;NavNode&gt;(node.getChildren()); } // Create a cell to display a descendant. private Cell&lt;NavNode&gt; getCell() { Cell&lt;NavNode&gt; cell = new AbstractCell&lt;NavNode&gt;() { @Override public void render(Context context, NavNode value, SafeHtmlBuilder sb) { if (value != null) { sb.appendEscaped(value.getName()); } } }; return cell; } private boolean isSelected(NavNode node) { boolean selected = false; if (node != null) { if (url.contains(tokenService.getToken(node))) { selected = true; } else { for (NavOption option: node.getOptions()) { if (url.contains(tokenService.getToken(option))) { selected = true; break; } } } } return selected; } class NavNodeSelectionHandler implements SelectionChangeEvent.Handler { private final VerticalPanel optionsContainer; private final DecoratedPopupPanel optionsPopup; public NavNodeSelectionHandler() { optionsPopup = new DecoratedPopupPanel(true); optionsContainer = new VerticalPanel(); optionsContainer.setWidth("125px"); // TODO provide a debug id... this will most likely necessitate generation of a unique key optionsPopup.setWidget(optionsContainer); } @Override public void onSelectionChange(SelectionChangeEvent event) { NavNode node = selectionModel.getSelectedObject(); for (NavOption option: node.getOptions()) { optionsContainer.add(new Hyperlink(option.getName(), tokenService.getToken(option))); } // Reposition the popup relative to node UIObject source = (UIObject) event.getSource(); int left = source.getAbsoluteLeft() + 25; int top = source.getAbsoluteTop(); optionsPopup.setPopupPosition(left, top); // Show the popup optionsPopup.show(); } } class NodeSelectionEventManager implements CellPreviewEvent.Handler&lt;NavNode&gt; { private final VerticalPanel optionsContainer; private final DecoratedPopupPanel optionsPopup; public NodeSelectionEventManager(NavNode node) { optionsPopup = new DecoratedPopupPanel(true); optionsContainer = new VerticalPanel(); optionsContainer.setWidth("125px"); for (NavOption option: node.getOptions()) { optionsContainer.add(new Hyperlink(option.getName(), tokenService.getToken(option))); } // TODO provide a debug id... this will most likely necessitate generation of a unique key optionsPopup.setWidget(optionsContainer); } @Override public void onCellPreview(CellPreviewEvent&lt;NavNode&gt; event) { // Reposition the popup relative to node UIObject source = (UIObject) event.getDisplay(); int left = source.getAbsoluteLeft() + 25; int top = source.getAbsoluteTop(); optionsPopup.setPopupPosition(left, top); // Show the popup optionsPopup.show(); } } </code></pre> <p>}</p> <p>I'm using a generic bean (NavNode) to help me determine when I have a leaf and when I have an option (NavOption) or options that contain a target used for Hyperlink construction.</p> <p>I want, when I click on a node (TreeNode) in the CellTree, that a pop-up menu (DecoratedPopupPanel) appears, but only for those nodes that have options.</p> <p>I have tried to employ either of the inner Handler implementations (on construction of a DefaultNodeInfo) to no success. Hopefully from the above code sample you can see what I'm trying to do.</p> <p>Here's a variant that adds a SelectionChangeEvent.Handler to SingleSelectionModel</p> <pre><code>if (currNode.hasOptions()) { // add pop-up menu to this node if it has options selectionModel.addSelectionChangeHandler(new NavNodeSelectionHandler()); result = new DefaultNodeInfo&lt;NavNode&gt;(getDataProvider(currNode), getCell(), selectionModel, null); } </code></pre> <p>What's happening is that the attempt to cast the Event fails with a ClassCastException.<br> I want to get a handle on an UIObject so I can position the popup. I think I need a handle on a TreeNode, but cannot see how to do it.</p> <p>The CellTree, TreeViewModel, SelectionModel and friends are some of the most obtuse API I've come across. </p> <p>Would really appreciate some help from a GWT expert!</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload