// Copyright 2012 Massachusetts Institute of Technology. All Rights Reserved.
package com.google.appinventor.client.boxes;
import com.google.appinventor.client.ComponentsTranslation;
import com.google.appinventor.client.Images;
import com.google.appinventor.client.Ode;
import com.google.appinventor.client.editor.simple.components.MockForm;
import com.google.appinventor.client.editor.youngandroid.BlockDrawerSelectionListener;
import com.google.appinventor.client.explorer.SourceStructureExplorer;
import com.google.appinventor.client.explorer.SourceStructureExplorerItem;
import com.google.appinventor.client.output.OdeLog;
import com.google.appinventor.client.widgets.boxes.Box;
import com.google.common.collect.Maps;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.TreeItem;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static com.google.appinventor.client.Ode.MESSAGES;
/**
* Box implementation for block selector. Shows a tree containing the built-in
* blocks as well as the components for the current form. Clicking on an item
* opens the blocks drawer for the item (or closes it if it was already open).
* This box shares screen real estate with the SourceStructureBox. It uses a
* SourceStructureExplorer to handle the components part of the tree.
*
* @author sharon@google.com (Sharon Perl)
*
*/
public final class BlockSelectorBox extends Box {
private static class BlockSelectorItem implements SourceStructureExplorerItem {
BlockSelectorItem() {
}
@Override
public void onSelected() {
}
@Override
public void onStateChange(boolean open) {
}
@Override
public boolean canRename() {
return false;
}
@Override
public void rename() {
}
@Override
public boolean canDelete() {
return false;
}
@Override
public void delete() {
}
}
// Singleton block selector box instance
// Starts out not visible. call setVisible(true) to make it visible
private static final BlockSelectorBox INSTANCE = new BlockSelectorBox();
private static final String BUILTIN_DRAWER_NAMES[] = { "Control", "Logic", "Math", "Text",
"Lists", "Colors", "Variables", "Procedures" };
private static final Images images = Ode.getImageBundle();
private static final Map<String, ImageResource> bundledImages = Maps.newHashMap();
// Source structure explorer (for components and built-in blocks)
private final SourceStructureExplorer sourceStructureExplorer;
private List<BlockDrawerSelectionListener> drawerListeners;
/**
* Return the singleton BlockSelectorBox box.
*
* @return block selector box
*/
public static BlockSelectorBox getBlockSelectorBox() {
return INSTANCE;
}
/**
* Creates new block selector box.
*/
private BlockSelectorBox() {
super(MESSAGES.blockSelectorBoxCaption(), 300, // height
false, // minimizable
false); // removable
sourceStructureExplorer = new SourceStructureExplorer();
setContent(sourceStructureExplorer);
setVisible(false);
drawerListeners = new ArrayList<BlockDrawerSelectionListener>();
}
private static void initBundledImages() {
bundledImages.put("Control", images.control());
bundledImages.put("Logic", images.logic());
bundledImages.put("Math", images.math());
bundledImages.put("Text", images.text());
bundledImages.put("Lists", images.lists());
bundledImages.put("Colors", images.colors());
bundledImages.put("Variables", images.variables());
bundledImages.put("Procedures", images.procedures());
}
/**
* Returns source structure explorer associated with box.
*
* @return source structure explorer
*/
public SourceStructureExplorer getSourceStructureExplorer() {
return sourceStructureExplorer;
}
/**
* Constructs a tree item for built-in blocks.
*
* @return tree item
*/
public TreeItem getBuiltInBlocksTree() {
initBundledImages();
TreeItem builtinNode = new TreeItem(new HTML("<span>" + MESSAGES.builtinBlocksLabel()
+ "</span>"));
for (final String drawerName : BUILTIN_DRAWER_NAMES) {
Image drawerImage = new Image(bundledImages.get(drawerName));
TreeItem itemNode = new TreeItem(new HTML("<span>" + drawerImage
+ getBuiltinDrawerNames(drawerName) + "</span>"));
SourceStructureExplorerItem sourceItem = new BlockSelectorItem() {
@Override
public void onSelected() {
fireBuiltinDrawerSelected(drawerName);
}
};
itemNode.setUserObject(sourceItem);
builtinNode.addItem(itemNode);
}
builtinNode.setState(true);
return builtinNode;
}
/**
* Given the drawerName, return the name in current language setting
*/
private String getBuiltinDrawerNames(String drawerName) {
String name;
OdeLog.wlog("getBuiltinDrawerNames: drawerName = " + drawerName);
if (drawerName.equals("Control")) {
name = MESSAGES.builtinControlLabel();
} else if (drawerName.equals("Logic")) {
name = MESSAGES.builtinLogicLabel();
} else if (drawerName.equals("Math")) {
name = MESSAGES.builtinMathLabel();
} else if (drawerName.equals("Text")) {
name = MESSAGES.builtinTextLabel();
} else if (drawerName.equals("Lists")) {
name = MESSAGES.builtinListsLabel();
} else if (drawerName.equals("Colors")) {
name = MESSAGES.builtinColorsLabel();
} else if (drawerName.equals("Variables")) {
name = MESSAGES.builtinVariablesLabel();
} else if (drawerName.equals("Procedures")) {
name = MESSAGES.builtinProceduresLabel();
} else {
name = drawerName;
}
return name;
}
/**
* Constructs a tree item for generic ("Advanced") component blocks for
* component types that appear in form.
*
* @param form
* only component types that appear in this Form will be included
* @return tree item for this form
*/
public TreeItem getGenericComponentsTree(MockForm form) {
Map<String, String> typesAndIcons = Maps.newHashMap();
form.collectTypesAndIcons(typesAndIcons);
TreeItem advanced = new TreeItem(new HTML("<span>" + MESSAGES.anyComponentLabel() + "</span>"));
List<String> typeList = new ArrayList<String>(typesAndIcons.keySet());
Collections.sort(typeList);
for (final String typeName : typeList) {
TreeItem itemNode = new TreeItem(new HTML("<span>" + typesAndIcons.get(typeName)
+ MESSAGES.textAnyComponentLabel()
+ ComponentsTranslation.getComponentName(typeName) + "</span>"));
SourceStructureExplorerItem sourceItem = new BlockSelectorItem() {
@Override
public void onSelected() {
fireGenericDrawerSelected(typeName);
}
};
itemNode.setUserObject(sourceItem);
advanced.addItem(itemNode);
}
return advanced;
}
public void addBlockDrawerSelectionListener(BlockDrawerSelectionListener listener) {
drawerListeners.add(listener);
}
public void removeBlockDrawerSelectionListener(BlockDrawerSelectionListener listener) {
drawerListeners.remove(listener);
}
private void fireBuiltinDrawerSelected(String drawerName) {
for (BlockDrawerSelectionListener listener : drawerListeners) {
listener.onBuiltinDrawerSelected(drawerName);
}
}
private void fireGenericDrawerSelected(String drawerName) {
for (BlockDrawerSelectionListener listener : drawerListeners) {
listener.onGenericDrawerSelected(drawerName);
}
}
}