Reputation: 1138
I'm using GWT CellTree
complex example as discribed in javadoc. But to open tree node I must click on little arrow on the left of the node. I want to open tree by clicking on text. I searched some help and found out that I can use ClickableTextCell
. Truly said, I don't understand where to start. Can you help me or provide another solutions? I want that node look like an anchor: when I mouse on the text, cursor become pointer and text is underline.
public <T> NodeInfo<?> getNodeInfo(T value) {
if (value == null) {
ListDataProvider<Composer> dataProvider = new ListDataProvider<CellTreeExample2.Composer>(
composers);
Cell<Composer> cell = new AbstractCell<Composer>() {
@Override
public void render(Context context, Composer value, SafeHtmlBuilder sb) {
if (value != null) {
sb.appendEscaped(value.getName());
}
}
};
return new DefaultNodeInfo<Composer>(dataProvider, cell);
} else if (value instanceof Composer) {
ListDataProvider<Playlist> dataProvider = new ListDataProvider<Playlist>(
((Composer) value).getPlaylists());
Cell<Playlist> cell = new AbstractCell<Playlist>() {
@Override
public void render(Context context, Playlist value, SafeHtmlBuilder sb) {
if (value != null) {
sb.appendEscaped(value.getName());
}
}
};
return new DefaultNodeInfo<Playlist>(dataProvider, cell);
} else if (value instanceof Playlist) {
ListDataProvider<String> dataProvider = new ListDataProvider<String>(
((Playlist) value).getSongs());
return new DefaultNodeInfo<String>(dataProvider, new TextCell(),
selectionModel, null);
}
return null;
}
public boolean isLeaf(Object value) {
if (value instanceof String) {
return true;
}
return false;
}
Upvotes: 1
Views: 612
Reputation: 472
Use a SingleSelectionModel
and pass it into your DefaultNodeInfo
. Add an onSelectionChanged
handler, such that when it is called:
ListDataProvider
, this will be used to open the associated child indexCellTree
root TreeNode
to open the associated child indexonSelectionChanged
event will be fire again. This will emulate toggling.addSelectionChangeHandler
Add selection change handler.
composerSingleSelectionModel = new SingleSelectionModel<Composer>(COMPOSER_KEY_PROVIDER);
// ...
composerSingleSelectionModel.addSelectionChangeHandler(
new SelectionChangeEvent.Handler() {
@Override
public void onSelectionChange(SelectionChangeEvent event) {
final TreeNode rootTreeNode = cellTree.getRootTreeNode();
final Composer selectedComposer = composerSingleSelectionModel.getSelectedObject();
if (selectedComposer == null) return;
final int index = composerListDataProvider.getList().indexOf(selectedComposer);
if (index < 0) return;
final boolean isOpen = rootTreeNode.isChildOpen(index);
rootTreeNode.setChildOpen(index, !isOpen);
/* Clear what is currently selected, so that
* onSelectionChange is fired again when the same item is
* selected consecutively.
*/
composerSingleSelectionModel.clear();
}
});
TreeViewModel
Pass in composer selection model to custom TreeViewModel
.
public class MusicTreeViewModel implements TreeViewModel {
// Define constructor to pass in properties ...
@Override
public <T> NodeInfo<?> getNodeInfo(T value) {
if (value == null) {
return new DefaultNodeInfo<Composer>(composerListDataProvider, composerCell, composerSelectionModel, null);
} else if (value instanceof Composer) {
final Composer composer = (Composer) value;
final Object composerKey = composerListDataProvider.getKey(composer);
final ListDataProvider<Playlist> playlistListDataProvider = getPlaylistListDataProvider(composerKey);
return new DefaultNodeInfo<Playlist>(playlistListDataProvider, playlistCell, playlistSelectionModel, null);
} else {
throw new IllegalArgumentException(
"Unsupported object type: " + value.getClass().getName());
}
}
@Override
public boolean isLeaf(Object value) {
if (value instanceof Composer) {
return ((Composer) value).getPlaylists().isEmpty();
} else if (value instanceof Playlist) {
return true;
}
return false;
}
}
Upvotes: 1
Reputation: 743
You must use a Cell for catch the click on the cell (like ClickableTextCell). In my project, I implemented this sytem for just first levels of an Tree :
Cell<String> nodeCell = new AbstractCell<String>("click", "keydown") {
@Override
public void onBrowserEvent(Context context, Element parent, String value, NativeEvent event, ValueUpdater<String> valueUpdater) {
String eventType = event.getType();
// Special case the ENTER key for a unified user experience.
if ("click".equals(eventType) || ("keydown".equals(eventType) && event.getKeyCode() == KeyCodes.KEY_ENTER)) {
tree.getRootTreeNode().setChildOpen(context.getIndex(), !tree.getRootTreeNode().isChildOpen(context.getIndex()));
}
}
@Override
public void render(Cell.Context context, String value, SafeHtmlBuilder sb) {
if (value != null) {
sb.appendEscaped(value);
}
}
};
For open more levels, you must use setChildOpen in cascade :
tree.getRootTreeNode().setChildOpen(1, true).setChildOpen(1, true).setChildOpen(1, true);
Upvotes: 1
Reputation: 64541
Because you probably don't want those nodes to also be selectable, I'd use a NoSelectionModel
.
Whenever you click on those nodes, call setChildOpen()
on the parent TreeNode
to toggle its state. To get the parent TreeNode
, use setChildOpen(index, true)
on the grandparent TreeNode
(recursively up to getRootTreeNode()
: because you know the node has already been loaded and is open (you're responding to an event on a child node), you can be sure that setChildOpen
will return the TreeNode
rather than null
.
Finally, to get the index
to pass to the setChildOpen
methods, just use an indexOf()
on the parent "domain object"'s list of children (i.e. composers.indexOf(composer)
, composer.getPlaylists().indexOf(playlist)
, etc.). This assumes that you can easily get the parent of a given object (the composer of a given playlist), either by maintaining bidirectional relations (playlist.getComposer().getPlaylists().indexOf(playlist)
), or by building a map of the child→parent relations.
Below are some building-blocks that you'd call from the NoSelectionModel
's SelectionHandler
:
void toggleComposerOpen(Composer composer) {
int index = composers.indexOf(composer);
TreeNode rootTreeNode = tree.getRootTreeNode();
rootTreeNode.setChildOpen(index, !rootTreeNode.isChildOpen(index));
}
void togglePlaylistOpen(Playlist playlist) {
Composer composer = playlist.getComposer();
TreeNode composerTreeNode = getTreeNode(composer);
int index = composer.getPlaylist().indexOf(playlist);
composer.setChildOpen(index, !composer.isChildOpen(index));
}
private void TreeNode getTreeNode(Composer composer) {
int index = composers.indexOf(composer);
return tree.getRootTreeNode().setChildOpen(index, true);
}
Upvotes: 1