package org.yaac.client.ui;
import static com.google.common.base.Strings.isNullOrEmpty;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
import org.yaac.client.YaacConstants;
import org.yaac.client.place.BlobPlace;
import org.yaac.client.place.BrowserPlace;
import org.yaac.client.place.EGQLPlace;
import org.yaac.client.place.EditorPlace;
import org.yaac.client.place.OverviewPlace;
import org.yaac.client.place.StatisticsPlace;
import com.google.gwt.cell.client.AbstractCell;
import com.google.gwt.cell.client.Cell;
import com.google.gwt.i18n.client.Constants;
import com.google.gwt.place.shared.Place;
import com.google.gwt.place.shared.PlaceController;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SingleSelectionModel;
import com.google.gwt.view.client.TreeViewModel;
/**
*
* @author Max Zhu (thebbsky@gmail.com)
*
*/
public class MenuTreeViewModel implements TreeViewModel {
/**
* The constants used in the menu.
*/
public static interface MenuConstants extends Constants {
// category capability
String categoryCapability();
String capabilityOverview();
// category datastore
String categoryDatastore();
String datastoreStatistics();
String categoryBlobstore();
String categoryMemcache();
String categoryTaskQueue();
}
/**
* @author Max Zhu (thebbsky@gmail.com)
*
*/
private class MenuItem {
/**
* url token to append
*
* if url token is NOT null, then history event will be fired
*/
private final Place place;
/**
* i18n display name
*/
private final String displayName;
/**
* children items, if it's not empty, then user can expand this item
*/
private final ListDataProvider<MenuItem> children;
/**
* @param urlToken
* @param displayName
*/
public MenuItem(Place place, String displayName) {
super();
this.place = place;
this.displayName = displayName;
this.children = new ListDataProvider<MenuItem>();
}
public boolean hasChild() {
return !this.children.getList().isEmpty();
}
}
/**
* @author Max Zhu (thebbsky@gmail.com)
*
*/
private class MenuCell extends AbstractCell<MenuItem> {
@Override
public void render(Cell.Context context, MenuItem value, SafeHtmlBuilder sb) {
if (value != null) {
sb.appendEscaped(value.displayName);
}
}
}
/**
* map used for main menu to re-select menu item on url change
*/
private final Map<String, MenuItem> urlTokenItemMap = new HashMap<String, MenuItem>();
/**
* The top level categories
*/
private final ListDataProvider<MenuItem> categories;
/**
* selection model handler for leaf categories
*/
private final SingleSelectionModel<MenuItem> selectionModel = new SingleSelectionModel<MenuItem>();
/**
*
*/
@Inject
MenuTreeViewModel(YaacConstants constants, final PlaceController placeController) {
categories = new ListDataProvider<MenuItem>();
initializeTree(constants);
// setup a listener of selection module to trigger place controller to switch places
selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
@Override
public void onSelectionChange(SelectionChangeEvent event) {
MenuItem selected = selectionModel.getSelectedObject();
if (selected != null && selected.place !=null) {
placeController.goTo(selected.place);
}
}
});
}
/**
* init main menu
*
* @param constants
*/
private void initializeTree(YaacConstants constants) {
{
// overview
MenuItem c = new MenuItem(null, constants.categoryCapability());
addChild(c, new OverviewPlace(), constants.capabilityOverview(), OverviewPlace.URL_TOKEN); //TODO : i18n
categories.getList().add(c);
}
{
// datastore
MenuItem c = new MenuItem(null, constants.categoryDatastore());
addChild(c, new StatisticsPlace(), constants.datastoreStatistics(), StatisticsPlace.URL_TOKEN); //TODO : i18n
addChild(c, new BrowserPlace(), "Browser", BrowserPlace.URL_TOKEN); //TODO : i18n
// FIXME : this will override URL with empty token everytime there is a change on MenuItem
addChild(c, new EditorPlace(""), "Editor", EditorPlace.URL_TOKEN); //TODO : i18n
addChild(c, new EGQLPlace(), "Extended GQL", EGQLPlace.URL_TOKEN); //TODO : i18n
categories.getList().add(c);
}
{
// blobstore
MenuItem c = new MenuItem(null, constants.categoryBlobstore());
addChild(c, new BlobPlace(), "Viewer", BlobPlace.URL_TOKEN); //TODO : i18n
categories.getList().add(c);
}
{
// memcache
MenuItem c = new MenuItem(null, constants.categoryMemcache());
categories.getList().add(c);
}
{
// task queue
MenuItem c = new MenuItem(null, constants.categoryTaskQueue());
categories.getList().add(c);
}
}
private void addChild(MenuItem parent, Place place,
String displayName, String urlToken) {
MenuItem child = new MenuItem(place, displayName);
parent.children.getList().add(child);
urlTokenItemMap.put(urlToken, child);
}
@Override
public <T> NodeInfo<?> getNodeInfo(T value) {
if (value == null) {
// top level
return new DefaultNodeInfo<MenuItem>(categories, new MenuCell());
} else if (value instanceof MenuItem) {
// on each category expand items
return ((MenuItem) value).hasChild() ?
new DefaultNodeInfo<MenuItem>(((MenuItem) value).children, new MenuCell(), selectionModel, null) : null;
}
return null;
}
@Override
public boolean isLeaf(Object value) {
if (value == null) {
return false;
} else if (value instanceof MenuItem) {
return !((MenuItem)value).hasChild();
} else {
return false;
}
}
public void updateSelection(String urlTokenPrefix) {
if (isNullOrEmpty(urlTokenPrefix)) {
return;
}
MenuItem item = urlTokenItemMap.get(urlTokenPrefix);
selectionModel.setSelected(item, true);
}
}