// -*- mode: java; c-basic-offset: 2; -*- // Copyright 2009-2011 Google, All Rights reserved // Copyright 2011-2017 MIT, All rights reserved // Released under the Apache License, Version 2.0 // http://www.apache.org/licenses/LICENSE-2.0 package com.google.appinventor.client.editor.simple.palette; import com.google.appinventor.client.Images; import com.google.appinventor.client.Ode; import com.google.appinventor.client.editor.simple.SimpleComponentDatabase; import com.google.appinventor.client.editor.simple.SimpleEditor; import com.google.appinventor.client.editor.simple.components.MockBall; import com.google.appinventor.client.editor.simple.components.MockButton; import com.google.appinventor.client.editor.simple.components.MockCanvas; import com.google.appinventor.client.editor.simple.components.MockCheckBox; import com.google.appinventor.client.editor.simple.components.MockComponent; import com.google.appinventor.client.editor.simple.components.MockContactPicker; import com.google.appinventor.client.editor.simple.components.MockDatePicker; import com.google.appinventor.client.editor.simple.components.MockEmailPicker; import com.google.appinventor.client.editor.simple.components.MockFirebaseDB; import com.google.appinventor.client.editor.simple.components.MockHorizontalArrangement; import com.google.appinventor.client.editor.simple.components.MockImage; import com.google.appinventor.client.editor.simple.components.MockImagePicker; import com.google.appinventor.client.editor.simple.components.MockImageSprite; import com.google.appinventor.client.editor.simple.components.MockLabel; import com.google.appinventor.client.editor.simple.components.MockListPicker; import com.google.appinventor.client.editor.simple.components.MockListView; import com.google.appinventor.client.editor.simple.components.MockNonVisibleComponent; import com.google.appinventor.client.editor.simple.components.MockPasswordTextBox; import com.google.appinventor.client.editor.simple.components.MockPhoneNumberPicker; import com.google.appinventor.client.editor.simple.components.MockRadioButton; import com.google.appinventor.client.editor.simple.components.MockScrollHorizontalArrangement; import com.google.appinventor.client.editor.simple.components.MockScrollVerticalArrangement; import com.google.appinventor.client.editor.simple.components.MockSlider; import com.google.appinventor.client.editor.simple.components.MockSpinner; import com.google.appinventor.client.editor.simple.components.MockTableArrangement; import com.google.appinventor.client.editor.simple.components.MockTextBox; import com.google.appinventor.client.editor.simple.components.MockTimePicker; import com.google.appinventor.client.editor.simple.components.MockVerticalArrangement; import com.google.appinventor.client.editor.simple.components.MockVideoPlayer; import com.google.appinventor.client.editor.simple.components.MockWebViewer; import com.google.appinventor.shared.storage.StorageUtil; import com.google.common.collect.Maps; import com.google.gwt.resources.client.ImageResource; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.Widget; import java.util.Map; /** * 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; // Whether External Component private final boolean external; // Goto documentation category URL piece private final String categoryDocUrlString; // Link to external documentation private final String helpUrl; // 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 final SimpleComponentDatabase COMPONENT_DATABASE; /* 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/gyroscopesensor.png", images.gyroscopesensor()); bundledImages.put("images/nearfield.png", images.nearfield()); 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/legoMindstormsEv3.png", images.legoMindstormsEv3()); bundledImages.put("images/orientationsensor.png", images.orientationsensor()); bundledImages.put("images/pedometer.png", images.pedometerComponent()); bundledImages.put("images/phoneip.png", images.phonestatusComponent()); 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/datePicker.png", images.datePickerComponent()); bundledImages.put("images/timePicker.png", images.timePickerComponent()); bundledImages.put("images/tinyDB.png", images.tinyDB()); bundledImages.put("images/file.png", images.file()); bundledImages.put("images/tinyWebDB.png", images.tinyWebDB()); bundledImages.put("images/firebaseDB.png", images.firebaseDB()); bundledImages.put("images/twitter.png", images.twitterComponent()); bundledImages.put("images/voting.png", images.voting()); bundledImages.put("images/web.png", images.web()); bundledImages.put("images/mediastore.png", images.mediastore()); bundledImages.put("images/sharing.png", images.sharingComponent()); bundledImages.put("images/spinner.png", images.spinner()); bundledImages.put("images/listView.png", images.listview()); bundledImages.put("images/yandex.png", images.yandex()); bundledImages.put("images/proximitysensor.png", images.proximitysensor()); bundledImages.put("images/extension.png", images.extension()); imagesInitialized = true; } /** * Creates a new component descriptor. * * @param name component display name */ public SimpleComponentDescriptor(String name, SimpleEditor editor, String helpString, String helpUrl, String categoryDocUrlString, boolean showOnPalette, boolean nonVisible, boolean external) { this.name = name; this.editor = editor; this.helpString = helpString; this.helpUrl = helpUrl; this.categoryDocUrlString = categoryDocUrlString; this.showOnPalette = showOnPalette; this.nonVisible = nonVisible; this.external = external; COMPONENT_DATABASE = SimpleComponentDatabase.getInstance(editor.getProjectId()); } /** * 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 help URL for the component. For more detail, see javadoc for * {@link com.google.appinventor.client.editor.simple.ComponentDatabase#getHelpUrl(String)}. * * @return URL to external documentation provided for an extension */ public String getHelpUrl() { return helpUrl; } /** * Returns the origin of the component * @return true if component is external */ public boolean getExternal() { return external; } /** * 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) { String type = COMPONENT_DATABASE.getComponentType(name); return getImageFromPath(COMPONENT_DATABASE.getIconName(name), type.substring(0, type.lastIndexOf('.')), editor.getProjectId()); } 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, COMPONENT_DATABASE.getComponentType(name), editor); } /** * Instantiates the corresponding mock component. * * @return mock component */ public MockComponent createMockComponentFromPalette() { MockComponent mockComponent = createMockComponent(name, COMPONENT_DATABASE.getComponentType(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, COMPONENT_DATABASE.getComponentType(name), editor); } return cachedMockComponent; } public static Image getImageFromPath(String iconPath, String packageName, long projectId) { if (!imagesInitialized) { initBundledImages(); } if (iconPath.startsWith("aiwebres/") && packageName != null) { // icon for extension Image image = new Image(StorageUtil.getFileUrl(projectId, "assets/external_comps/" + packageName + "/" + iconPath)); image.setWidth("16px"); image.setHeight("16px"); return image; } 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, String type, SimpleEditor editor) { if (SimpleComponentDatabase.getInstance(editor.getProjectId()).getNonVisible(name)) { if(name.equals(MockFirebaseDB.TYPE)) { return new MockFirebaseDB(editor, name, getImageFromPath(SimpleComponentDatabase.getInstance(editor.getProjectId()).getIconName(name), null, editor.getProjectId())); } else { String pkgName = type.contains(".") ? type.substring(0, type.lastIndexOf('.')) : null; return new MockNonVisibleComponent(editor, name, getImageFromPath(SimpleComponentDatabase.getInstance(editor.getProjectId()).getIconName(name), pkgName, editor.getProjectId())); } } 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(MockListView.TYPE)) { return new MockListView(editor); } else if (name.equals(MockSlider.TYPE)) { return new MockSlider(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(MockDatePicker.TYPE)) { return new MockDatePicker(editor); } else if (name.equals(MockTimePicker.TYPE)) { return new MockTimePicker(editor); } else if (name.equals(MockHorizontalArrangement.TYPE)) { return new MockHorizontalArrangement(editor); } else if (name.equals(MockScrollHorizontalArrangement.TYPE)) { return new MockScrollHorizontalArrangement(editor); } else if (name.equals(MockVerticalArrangement.TYPE)) { return new MockVerticalArrangement(editor); } else if (name.equals(MockScrollVerticalArrangement.TYPE)) { return new MockScrollVerticalArrangement(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 if (name.equals(MockSpinner.TYPE)) { return new MockSpinner(editor); } else { // TODO(user): add 3rd party mock component proxy here throw new UnsupportedOperationException("unknown component: " + name); } } }