public ComponentHelpWidget(final SimpleComponentDescriptor scd) { if (imageResource == null) { Images images = Ode.getImageBundle(); imageResource = images.help(); } AbstractImagePrototype.create(imageResource).applyTo(this); addClickListener( new ClickListener() { @Override public void onClick(Widget sender) { final long MINIMUM_MS_BETWEEN_SHOWS = 250; // .25 seconds if (System.currentTimeMillis() - lastClosureTime >= MINIMUM_MS_BETWEEN_SHOWS) { new ComponentHelpPopup(scd, sender); } } }); }
/** Descriptor for components on the component palette panel. This class is immutable. */ public final class SimpleComponentDescriptor { // Component display name private final String name; private final SimpleEditor editor; // Help information to display for component private final String helpString; // Goro documentation category URL piece private final String categoryDocUrlString; // Whether to show the component on the palette private final boolean showOnPalette; // Whether the component has a visual representation in the app's UI private final boolean nonVisible; // an instantiated mockcomponent is currently necessary in order to // to get the image, category, and description private MockComponent cachedMockComponent = null; // Component database: information about components (including their properties and events) private static final SimpleComponentDatabase COMPONENT_DATABASE = SimpleComponentDatabase.getInstance(); /* We keep a static map of image names to images in the image bundle so * that we can avoid making individual calls to the server for static image * that are already in the bundle. This is purely an efficiency optimization * for mock non-visible components. */ private static final Images images = Ode.getImageBundle(); private static final Map<String, ImageResource> bundledImages = Maps.newHashMap(); private static boolean imagesInitialized = false; private static void initBundledImages() { bundledImages.put("images/accelerometersensor.png", images.accelerometersensor()); bundledImages.put("images/activityStarter.png", images.activitystarter()); bundledImages.put("images/barcodeScanner.png", images.barcodeScanner()); bundledImages.put("images/bluetooth.png", images.bluetooth()); bundledImages.put("images/camera.png", images.camera()); bundledImages.put("images/camcorder.png", images.camcorder()); bundledImages.put("images/clock.png", images.clock()); bundledImages.put("images/fusiontables.png", images.fusiontables()); bundledImages.put("images/gameClient.png", images.gameclient()); bundledImages.put("images/locationSensor.png", images.locationSensor()); bundledImages.put("images/notifier.png", images.notifier()); bundledImages.put("images/legoMindstormsNxt.png", images.legoMindstormsNxt()); bundledImages.put("images/orientationsensor.png", images.orientationsensor()); bundledImages.put("images/pedometer.png", images.pedometerComponent()); bundledImages.put("images/phoneCall.png", images.phonecall()); bundledImages.put("images/player.png", images.player()); bundledImages.put("images/soundEffect.png", images.soundeffect()); bundledImages.put("images/soundRecorder.png", images.soundRecorder()); bundledImages.put("images/speechRecognizer.png", images.speechRecognizer()); bundledImages.put("images/textToSpeech.png", images.textToSpeech()); bundledImages.put("images/texting.png", images.texting()); bundledImages.put("images/tinyDB.png", images.tinyDB()); bundledImages.put("images/tinyWebDB.png", images.tinyWebDB()); bundledImages.put("images/twitter.png", images.twitterComponent()); bundledImages.put("images/voting.png", images.voting()); bundledImages.put("images/web.png", images.web()); imagesInitialized = true; } /** * Creates a new component descriptor. * * @param name component display name */ public SimpleComponentDescriptor( String name, SimpleEditor editor, String helpString, String categoryDocUrlString, boolean showOnPalette, boolean nonVisible) { this.name = name; this.editor = editor; this.helpString = helpString; this.categoryDocUrlString = categoryDocUrlString; this.showOnPalette = showOnPalette; this.nonVisible = nonVisible; } /** * Returns the display name of the component. * * @return component display name */ public String getName() { return name; } /** * Returns the help string for the component. For more detail, see javadoc for {@link * com.google.appinventor.client.editor.simple.ComponentDatabase#getHelpString(String)}. * * @return helpful message about the component */ public String getHelpString() { return helpString; } /** * Returns the categoryDocUrl string for the component. For more detail, see javadoc for {@link * com.google.appinventor.client.editor.simple.ComponentDatabase#getCategoryDocUrlString(String)}. * * @return helpful message about the component */ public String getCategoryDocUrlString() { return categoryDocUrlString; } /** * Returns whether this component should be shown on the palette. For more detail, see javadoc for * {@link com.google.appinventor.client.editor.simple.ComponentDatabase#getHelpString(String)}. * * @return whether the component should be shown on the palette */ public boolean getShowOnPalette() { return showOnPalette; } /** * Returns whether this component is visible in the app's UI. For more detail, see javadoc for * {@link com.google.appinventor.client.editor.simple.ComponentDatabase#getHelpString(String)}. * * @return whether the component is non-visible */ public boolean getNonVisible() { return nonVisible; } /** * Returns an image for display on the component palette. * * @return image for component */ public Image getImage() { if (nonVisible) { return getImageFromPath(COMPONENT_DATABASE.getIconName(name)); } else { return getCachedMockComponent(name, editor).getIconImage(); } } /** * Returns a draggable image for the component. Used when dragging a component from the palette * onto the form. * * @return draggable widget for component */ public Widget getDragWidget() { return createMockComponent(name, editor); } /** * Instantiates the corresponding mock component. * * @return mock component */ public MockComponent createMockComponentFromPalette() { MockComponent mockComponent = createMockComponent(name, editor); mockComponent.onCreateFromPalette(); return mockComponent; } /** Gets cached mock component; creates if necessary. */ private MockComponent getCachedMockComponent(String name, SimpleEditor editor) { if (cachedMockComponent == null) { cachedMockComponent = createMockComponent(name, editor); } return cachedMockComponent; } public static Image getImageFromPath(String iconPath) { if (!imagesInitialized) { initBundledImages(); } if (bundledImages.containsKey(iconPath)) { return new Image(bundledImages.get(iconPath)); } else { return new Image(iconPath); } } /** Instantiates mock component by name. */ public static MockComponent createMockComponent(String name, SimpleEditor editor) { if (COMPONENT_DATABASE.getNonVisible(name)) { return new MockNonVisibleComponent( editor, name, getImageFromPath(COMPONENT_DATABASE.getIconName(name))); } else if (name.equals(MockButton.TYPE)) { return new MockButton(editor); } else if (name.equals(MockCanvas.TYPE)) { return new MockCanvas(editor); } else if (name.equals(MockCheckBox.TYPE)) { return new MockCheckBox(editor); } else if (name.equals(MockImage.TYPE)) { return new MockImage(editor); } else if (name.equals(MockLabel.TYPE)) { return new MockLabel(editor); } else if (name.equals(MockPasswordTextBox.TYPE)) { return new MockPasswordTextBox(editor); } else if (name.equals(MockRadioButton.TYPE)) { return new MockRadioButton(editor); } else if (name.equals(MockTextBox.TYPE)) { return new MockTextBox(editor); } else if (name.equals(MockContactPicker.TYPE)) { return new MockContactPicker(editor); } else if (name.equals(MockPhoneNumberPicker.TYPE)) { return new MockPhoneNumberPicker(editor); } else if (name.equals(MockEmailPicker.TYPE)) { return new MockEmailPicker(editor); } else if (name.equals(MockListPicker.TYPE)) { return new MockListPicker(editor); } else if (name.equals(MockHorizontalArrangement.TYPE)) { return new MockHorizontalArrangement(editor); } else if (name.equals(MockVerticalArrangement.TYPE)) { return new MockVerticalArrangement(editor); } else if (name.equals(MockTableArrangement.TYPE)) { return new MockTableArrangement(editor); } else if (name.equals(MockImageSprite.TYPE)) { return new MockImageSprite(editor); } else if (name.equals(MockBall.TYPE)) { return new MockBall(editor); } else if (name.equals(MockImagePicker.TYPE)) { return new MockImagePicker(editor); } else if (name.equals(MockVideoPlayer.TYPE)) { return new MockVideoPlayer(editor); } else if (name.equals(MockWebViewer.TYPE)) { return new MockWebViewer(editor); } else { // TODO(user): add 3rd party mock component proxy here throw new UnsupportedOperationException("unknown component: " + name); } } }
/** * 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 [email protected] (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() + TranslationDesignerPallete.getCorrespondingString(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); } } }