Java tutorial
// -*- mode: java; c-basic-offset: 2; -*- // Copyright 2009-2011 Google, All Rights reserved // Copyright 2011-2013 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; import com.google.appinventor.client.boxes.ProjectListBox; import com.google.appinventor.client.boxes.ViewerBox; import com.google.appinventor.client.editor.youngandroid.BlocklyPanel; import com.google.appinventor.client.editor.youngandroid.YaBlocksEditor; import com.google.appinventor.client.explorer.commands.BuildCommand; import com.google.appinventor.client.explorer.commands.ChainableCommand; import com.google.appinventor.client.explorer.commands.CopyYoungAndroidProjectCommand; import com.google.appinventor.client.explorer.commands.DownloadProjectOutputCommand; import com.google.appinventor.client.explorer.commands.GenerateYailCommand; import com.google.appinventor.client.explorer.commands.SaveAllEditorsCommand; import com.google.appinventor.client.explorer.commands.ShowBarcodeCommand; import com.google.appinventor.client.explorer.commands.ShowProgressBarCommand; import com.google.appinventor.client.explorer.commands.WaitForBuildResultCommand; import com.google.appinventor.client.explorer.project.Project; import com.google.appinventor.client.output.OdeLog; import com.google.appinventor.client.tracking.Tracking; import com.google.appinventor.client.utils.Downloader; import com.google.appinventor.client.widgets.DropDownButton; import com.google.appinventor.client.widgets.DropDownButton.DropDownItem; import com.google.appinventor.client.wizards.DownloadUserSourceWizard; import com.google.appinventor.client.wizards.KeystoreUploadWizard; import com.google.appinventor.client.wizards.ProjectUploadWizard; import com.google.appinventor.client.wizards.TemplateUploadWizard; import com.google.appinventor.client.wizards.ComponentImportWizard; import com.google.appinventor.client.wizards.ComponentUploadWizard; import com.google.appinventor.client.wizards.youngandroid.NewYoungAndroidProjectWizard; import com.google.appinventor.common.version.AppInventorFeatures; import com.google.appinventor.common.version.GitBuildId; import com.google.appinventor.components.common.YaVersion; import com.google.appinventor.shared.rpc.ServerLayout; import com.google.appinventor.shared.rpc.project.GallerySettings; import com.google.appinventor.shared.rpc.project.ProjectRootNode; import com.google.appinventor.shared.rpc.project.youngandroid.YoungAndroidProjectNode; import com.google.appinventor.shared.rpc.user.Config; import com.google.appinventor.shared.storage.StorageUtil; import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.Window.Location; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.ClickListener; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.DialogBox; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; import java.util.ArrayList; import java.util.List; import static com.google.appinventor.client.Ode.MESSAGES; /** * TopToolbar lives in the TopPanel, to create functionality in the designer. */ public class TopToolbar extends Composite { private static final String WIDGET_NAME_NEW = "New"; private static final String WIDGET_NAME_DELETE = "Delete"; private static final String WIDGET_NAME_DOWNLOAD_KEYSTORE = "DownloadKeystore"; private static final String WIDGET_NAME_UPLOAD_KEYSTORE = "UploadKeystore"; private static final String WIDGET_NAME_DELETE_KEYSTORE = "DeleteKeystore"; private static final String WIDGET_NAME_SAVE = "Save"; private static final String WIDGET_NAME_SAVE_AS = "SaveAs"; private static final String WIDGET_NAME_CHECKPOINT = "Checkpoint"; private static final String WIDGET_NAME_MY_PROJECTS = "MyProjects"; private static final String WIDGET_NAME_BUILD = "Build"; private static final String WIDGET_NAME_BUILD_BARCODE = "Barcode"; private static final String WIDGET_NAME_BUILD_DOWNLOAD = "Download"; private static final String WIDGET_NAME_BUILD_YAIL = "Yail"; private static final String WIDGET_NAME_CONNECT_TO = "ConnectTo"; private static final String WIDGET_NAME_WIRELESS_BUTTON = "Wireless"; private static final String WIDGET_NAME_EMULATOR_BUTTON = "Emulator"; private static final String WIDGET_NAME_USB_BUTTON = "Usb"; private static final String WIDGET_NAME_RESET_BUTTON = "Reset"; private static final String WIDGET_NAME_HARDRESET_BUTTON = "HardReset"; private static final String WIDGET_NAME_PROJECT = "Project"; private static final String WIDGET_NAME_HELP = "Help"; private static final String WIDGET_NAME_ABOUT = "About"; private static final String WIDGET_NAME_LIBRARY = "Library"; private static final String WIDGET_NAME_GETSTARTED = "GetStarted"; private static final String WIDGET_NAME_TUTORIALS = "Tutorials"; private static final String WIDGET_NAME_EXTENSIONS = "Extensions"; private static final String WIDGET_NAME_SHOWSPLASH = "ShowSplash"; private static final String WIDGET_NAME_TROUBLESHOOTING = "Troubleshooting"; private static final String WIDGET_NAME_FORUMS = "Forums"; private static final String WIDGET_NAME_FEEDBACK = "ReportIssue"; private static final String WIDGET_NAME_COMPANIONINFO = "CompanionInformation"; private static final String WIDGET_NAME_COMPANIONUPDATE = "CompanionUpdate"; private static final String WIDGET_NAME_IMPORTPROJECT = "ImportProject"; private static final String WIDGET_NAME_IMPORTTEMPLATE = "ImportTemplate"; private static final String WIDGET_NAME_EXPORTALLPROJECTS = "ExportAllProjects"; private static final String WIDGET_NAME_EXPORTPROJECT = "ExportProject"; private static final String WIDGET_NAME_COMPONENTS = "Components"; private static final String WIDGET_NAME_MY_COMPONENTS = "MyComponents"; private static final String WIDGET_NAME_START_NEW_COMPONENT = "StartNewComponent"; private static final String WIDGET_NAME_IMPORT_COMPONENT = "ImportComponent"; private static final String WIDGET_NAME_BUILD_COMPONENT = "BuildComponent"; private static final String WIDGET_NAME_UPLOAD_COMPONENT = "UploadComponent"; private static final String WIDGET_NAME_ADMIN = "Admin"; private static final String WIDGET_NAME_USER_ADMIN = "UserAdmin"; private static final String WIDGET_NAME_DOWNLOAD_USER_SOURCE = "DownloadUserSource"; private static final String WIDGET_NAME_SWITCH_TO_DEBUG = "SwitchToDebugPane"; private static final String WINDOW_OPEN_FEATURES = "menubar=yes,location=yes,resizable=yes,scrollbars=yes,status=yes"; private static final String WINDOW_OPEN_LOCATION = "_ai2"; public DropDownButton fileDropDown; public DropDownButton connectDropDown; public DropDownButton buildDropDown; public DropDownButton helpDropDown; public DropDownButton adminDropDown; private boolean isReadOnly; public TopToolbar() { /* * Layout is as follows: * +--------------------------------------------------+ * | Project | Connect | Build | Help | Admin | * +--------------------------------------------------+ */ HorizontalPanel toolbar = new HorizontalPanel(); toolbar.setVerticalAlignment(HorizontalPanel.ALIGN_MIDDLE); List<DropDownItem> fileItems = Lists.newArrayList(); List<DropDownItem> componentItems = Lists.newArrayList(); List<DropDownItem> connectItems = Lists.newArrayList(); List<DropDownItem> buildItems = Lists.newArrayList(); List<DropDownItem> helpItems = Lists.newArrayList(); // Should the UI be in read only mode? isReadOnly = Ode.getInstance().isReadOnly(); // File -> {New Project; Save; Save As; Checkpoint; |; Delete this Project; My Projects;} fileItems.add( new DropDownItem(WIDGET_NAME_MY_PROJECTS, MESSAGES.projectMenuItem(), new SwitchToProjectAction())); fileItems.add(null); if (!isReadOnly) { fileItems.add(new DropDownItem(WIDGET_NAME_NEW, MESSAGES.newProjectMenuItem(), new NewAction())); fileItems.add(new DropDownItem(WIDGET_NAME_IMPORTPROJECT, MESSAGES.importProjectMenuItem(), new ImportProjectAction())); fileItems.add(new DropDownItem(WIDGET_NAME_IMPORTTEMPLATE, MESSAGES.importTemplateButton(), new ImportTemplateAction())); fileItems.add(new DropDownItem(WIDGET_NAME_DELETE, MESSAGES.deleteProjectButton(), new DeleteAction())); fileItems.add(null); fileItems.add(new DropDownItem(WIDGET_NAME_SAVE, MESSAGES.saveMenuItem(), new SaveAction())); fileItems.add(new DropDownItem(WIDGET_NAME_SAVE_AS, MESSAGES.saveAsMenuItem(), new SaveAsAction())); fileItems.add(new DropDownItem(WIDGET_NAME_CHECKPOINT, MESSAGES.checkpointMenuItem(), new CheckpointAction())); fileItems.add(null); } fileItems.add(new DropDownItem(WIDGET_NAME_EXPORTPROJECT, MESSAGES.exportProjectMenuItem(), new ExportProjectAction())); fileItems.add(new DropDownItem(WIDGET_NAME_EXPORTALLPROJECTS, MESSAGES.exportAllProjectsMenuItem(), new ExportAllProjectsAction())); fileItems.add(null); if (!isReadOnly) { fileItems.add(new DropDownItem(WIDGET_NAME_UPLOAD_KEYSTORE, MESSAGES.uploadKeystoreMenuItem(), new UploadKeystoreAction())); } fileItems.add(new DropDownItem(WIDGET_NAME_DOWNLOAD_KEYSTORE, MESSAGES.downloadKeystoreMenuItem(), new DownloadKeystoreAction())); if (!isReadOnly) { fileItems.add(new DropDownItem(WIDGET_NAME_DELETE_KEYSTORE, MESSAGES.deleteKeystoreMenuItem(), new DeleteKeystoreAction())); } // Connect -> {Connect to Companion; Connect to Emulator; Connect to USB; Reset Connections} connectItems.add(new DropDownItem(WIDGET_NAME_WIRELESS_BUTTON, MESSAGES.AICompanionMenuItem(), new WirelessAction())); connectItems.add( new DropDownItem(WIDGET_NAME_EMULATOR_BUTTON, MESSAGES.emulatorMenuItem(), new EmulatorAction())); connectItems.add(new DropDownItem(WIDGET_NAME_USB_BUTTON, MESSAGES.usbMenuItem(), new UsbAction())); connectItems.add(null); connectItems.add( new DropDownItem(WIDGET_NAME_RESET_BUTTON, MESSAGES.resetConnectionsMenuItem(), new ResetAction())); connectItems.add(new DropDownItem(WIDGET_NAME_HARDRESET_BUTTON, MESSAGES.hardResetConnectionsMenuItem(), new HardResetAction())); // Build -> {Show Barcode; Download to Computer; Generate YAIL only when logged in as an admin} buildItems.add( new DropDownItem(WIDGET_NAME_BUILD_BARCODE, MESSAGES.showBarcodeMenuItem(), new BarcodeAction())); buildItems.add(new DropDownItem(WIDGET_NAME_BUILD_DOWNLOAD, MESSAGES.downloadToComputerMenuItem(), new DownloadAction())); if (AppInventorFeatures.hasYailGenerationOption() && Ode.getInstance().getUser().getIsAdmin()) { buildItems.add(null); buildItems.add(new DropDownItem(WIDGET_NAME_BUILD_YAIL, MESSAGES.generateYailMenuItem(), new GenerateYailAction())); } // Help -> {About, Library, Get Started, Tutorials, Troubleshooting, Forums, Report an Issue, // Companion Information, Show Splash Screen} helpItems.add(new DropDownItem(WIDGET_NAME_ABOUT, MESSAGES.aboutMenuItem(), new AboutAction())); helpItems.add(null); Config config = Ode.getInstance().getSystemConfig(); String libraryUrl = config.getLibraryUrl(); if (!Strings.isNullOrEmpty(libraryUrl)) { helpItems.add(new DropDownItem(WIDGET_NAME_LIBRARY, MESSAGES.libraryMenuItem(), new WindowOpenAction(libraryUrl))); } String getStartedUrl = config.getGetStartedUrl(); if (!Strings.isNullOrEmpty(getStartedUrl)) { helpItems.add(new DropDownItem(WIDGET_NAME_GETSTARTED, MESSAGES.getStartedMenuItem(), new WindowOpenAction(getStartedUrl))); } String extensionsUrl = config.getExtensionsUrl(); if (!Strings.isNullOrEmpty(extensionsUrl)) { helpItems.add(new DropDownItem(WIDGET_NAME_EXTENSIONS, MESSAGES.extensionsMenuItem(), new WindowOpenAction(extensionsUrl))); } String tutorialsUrl = config.getTutorialsUrl(); if (!Strings.isNullOrEmpty(tutorialsUrl)) { helpItems.add(new DropDownItem(WIDGET_NAME_TUTORIALS, MESSAGES.tutorialsMenuItem(), new WindowOpenAction(tutorialsUrl))); } String troubleshootingUrl = config.getTroubleshootingUrl(); if (!Strings.isNullOrEmpty(troubleshootingUrl)) { helpItems.add(new DropDownItem(WIDGET_NAME_TROUBLESHOOTING, MESSAGES.troubleshootingMenuItem(), new WindowOpenAction(troubleshootingUrl))); } String forumsUrl = config.getForumsUrl(); if (!Strings.isNullOrEmpty(forumsUrl)) { helpItems.add(new DropDownItem(WIDGET_NAME_FORUMS, MESSAGES.forumsMenuItem(), new WindowOpenAction(forumsUrl))); } helpItems.add(null); String feedbackUrl = config.getFeedbackUrl(); if (!Strings.isNullOrEmpty(feedbackUrl)) { helpItems.add(new DropDownItem(WIDGET_NAME_FEEDBACK, MESSAGES.feedbackMenuItem(), new WindowOpenAction(feedbackUrl))); helpItems.add(null); } helpItems.add(new DropDownItem(WIDGET_NAME_COMPANIONINFO, MESSAGES.companionInformation(), new AboutCompanionAction())); helpItems.add(new DropDownItem(WIDGET_NAME_COMPANIONUPDATE, MESSAGES.companionUpdate(), new CompanionUpdateAction())); helpItems.add( new DropDownItem(WIDGET_NAME_SHOWSPLASH, MESSAGES.showSplashMenuItem(), new ShowSplashAction())); // Create the TopToolbar drop down menus. fileDropDown = new DropDownButton(WIDGET_NAME_PROJECT, MESSAGES.projectsTabName(), fileItems, false); connectDropDown = new DropDownButton(WIDGET_NAME_CONNECT_TO, MESSAGES.connectTabName(), connectItems, false); buildDropDown = new DropDownButton(WIDGET_NAME_BUILD, MESSAGES.buildTabName(), buildItems, false); helpDropDown = new DropDownButton(WIDGET_NAME_HELP, MESSAGES.helpTabName(), helpItems, false); // Set the DropDown Styles fileDropDown.setStyleName("ode-TopPanelButton"); connectDropDown.setStyleName("ode-TopPanelButton"); buildDropDown.setStyleName("ode-TopPanelButton"); helpDropDown.setStyleName("ode-TopPanelButton"); // Add the Buttons to the Toolbar. toolbar.add(fileDropDown); toolbar.add(connectDropDown); toolbar.add(buildDropDown); // Commented out language switching until we have a clean Chinese translation. (AFM) toolbar.add(helpDropDown); //Only if logged in as an admin, add the Admin Button if (Ode.getInstance().getUser().getIsAdmin()) { List<DropDownItem> adminItems = Lists.newArrayList(); adminItems.add(new DropDownItem(WIDGET_NAME_DOWNLOAD_USER_SOURCE, MESSAGES.downloadUserSourceMenuItem(), new DownloadUserSourceAction())); adminItems.add(new DropDownItem(WIDGET_NAME_SWITCH_TO_DEBUG, MESSAGES.switchToDebugMenuItem(), new SwitchToDebugAction())); adminItems.add(new DropDownItem(WIDGET_NAME_USER_ADMIN, "User Admin", new SwitchToUserAdminAction())); adminDropDown = new DropDownButton(WIDGET_NAME_ADMIN, MESSAGES.adminTabName(), adminItems, false); adminDropDown.setStyleName("ode-TopPanelButton"); toolbar.add(adminDropDown); } initWidget(toolbar); } // ----------------------------- // List of Commands for use in Drop-Down Menus // ----------------------------- private static class NewAction implements Command { @Override public void execute() { new NewYoungAndroidProjectWizard(null).center(); // The wizard will switch to the design view when the new // project is created. } } private class SaveAction implements Command { @Override public void execute() { ProjectRootNode projectRootNode = Ode.getInstance().getCurrentYoungAndroidProjectRootNode(); if (projectRootNode != null) { ChainableCommand cmd = new SaveAllEditorsCommand(null); cmd.startExecuteChain(Tracking.PROJECT_ACTION_SAVE_YA, projectRootNode); } } } private class SaveAsAction implements Command { @Override public void execute() { ProjectRootNode projectRootNode = Ode.getInstance().getCurrentYoungAndroidProjectRootNode(); if (projectRootNode != null) { ChainableCommand cmd = new SaveAllEditorsCommand(new CopyYoungAndroidProjectCommand(false)); cmd.startExecuteChain(Tracking.PROJECT_ACTION_SAVE_AS_YA, projectRootNode); } } } private class CheckpointAction implements Command { @Override public void execute() { ProjectRootNode projectRootNode = Ode.getInstance().getCurrentYoungAndroidProjectRootNode(); if (projectRootNode != null) { ChainableCommand cmd = new SaveAllEditorsCommand(new CopyYoungAndroidProjectCommand(true)); cmd.startExecuteChain(Tracking.PROJECT_ACTION_CHECKPOINT_YA, projectRootNode); } } } private static class SwitchToProjectAction implements Command { @Override public void execute() { Ode.getInstance().switchToProjectsView(); Ode.getInstance().getTopToolbar().updateFileMenuButtons(0); } } private class WirelessAction implements Command { @Override public void execute() { if (Ode.getInstance().okToConnect()) { startRepl(true, false, false); // false means we are // *not* the emulator } } } private class EmulatorAction implements Command { @Override public void execute() { if (Ode.getInstance().okToConnect()) { startRepl(true, true, false); // true means we are the // emulator } } } private class UsbAction implements Command { @Override public void execute() { if (Ode.getInstance().okToConnect()) { startRepl(true, false, true); } } } private class ResetAction implements Command { @Override public void execute() { if (Ode.getInstance().okToConnect()) { startRepl(false, false, false); // We are really stopping the repl here } } } private class HardResetAction implements Command { @Override public void execute() { if (Ode.getInstance().okToConnect()) { replHardReset(); } } } private class BarcodeAction implements Command { @Override public void execute() { ProjectRootNode projectRootNode = Ode.getInstance().getCurrentYoungAndroidProjectRootNode(); if (projectRootNode != null) { String target = YoungAndroidProjectNode.YOUNG_ANDROID_TARGET_ANDROID; ChainableCommand cmd = new SaveAllEditorsCommand(new GenerateYailCommand(new BuildCommand(target, new ShowProgressBarCommand(target, new WaitForBuildResultCommand(target, new ShowBarcodeCommand(target)), "BarcodeAction")))); // updateBuildButton(true); cmd.startExecuteChain(Tracking.PROJECT_ACTION_BUILD_BARCODE_YA, projectRootNode, new Command() { @Override public void execute() { // updateBuildButton(false); } }); } } } private class DownloadAction implements Command { @Override public void execute() { ProjectRootNode projectRootNode = Ode.getInstance().getCurrentYoungAndroidProjectRootNode(); if (projectRootNode != null) { String target = YoungAndroidProjectNode.YOUNG_ANDROID_TARGET_ANDROID; ChainableCommand cmd = new SaveAllEditorsCommand(new GenerateYailCommand(new BuildCommand(target, new ShowProgressBarCommand(target, new WaitForBuildResultCommand(target, new DownloadProjectOutputCommand(target)), "DownloadAction")))); // updateBuildButton(true); cmd.startExecuteChain(Tracking.PROJECT_ACTION_BUILD_DOWNLOAD_YA, projectRootNode, new Command() { @Override public void execute() { // updateBuildButton(false); } }); } } } private static class ExportProjectAction implements Command { @Override public void execute() { List<Project> selectedProjects = ProjectListBox.getProjectListBox().getProjectList() .getSelectedProjects(); if (Ode.getInstance().getCurrentView() == Ode.PROJECTS) { //If we are in the projects view if (selectedProjects.size() == 1) { exportProject(selectedProjects.get(0)); } else { // The user needs to select only one project. ErrorReporter.reportInfo(MESSAGES.wrongNumberProjectsSelected()); } } else { //If we are in the designer view. Downloader.getInstance() .download(ServerLayout.DOWNLOAD_SERVLET_BASE + ServerLayout.DOWNLOAD_PROJECT_SOURCE + "/" + Ode.getInstance().getCurrentYoungAndroidProjectId()); } } private void exportProject(Project project) { Tracking.trackEvent(Tracking.PROJECT_EVENT, Tracking.PROJECT_ACTION_DOWNLOAD_PROJECT_SOURCE_YA, project.getProjectName()); Downloader.getInstance().download(ServerLayout.DOWNLOAD_SERVLET_BASE + ServerLayout.DOWNLOAD_PROJECT_SOURCE + "/" + project.getProjectId()); } } private static class ExportAllProjectsAction implements Command { @Override public void execute() { Tracking.trackEvent(Tracking.PROJECT_EVENT, Tracking.PROJECT_ACTION_DOWNLOAD_ALL_PROJECTS_SOURCE_YA); // Is there a way to disable the Download All button until this completes? if (Window.confirm(MESSAGES.downloadAllAlert())) { Downloader.getInstance() .download(ServerLayout.DOWNLOAD_SERVLET_BASE + ServerLayout.DOWNLOAD_ALL_PROJECTS_SOURCE); } } } private static class ImportProjectAction implements Command { @Override public void execute() { new ProjectUploadWizard().center(); } } private static class ImportTemplateAction implements Command { @Override public void execute() { new TemplateUploadWizard().center(); } } private static class DeleteAction implements Command { @Override public void execute() { Ode.getInstance().getEditorManager().saveDirtyEditors(new Command() { @Override public void execute() { if (Ode.getInstance().getCurrentView() == Ode.PROJECTS) { List<Project> selectedProjects = ProjectListBox.getProjectListBox().getProjectList() .getSelectedProjects(); if (selectedProjects.size() > 0) { // Show one confirmation window for selected projects. if (deleteConfirmation(selectedProjects)) { for (Project project : selectedProjects) { deleteProject(project); } } } else { // The user can select a project to resolve the // error. ErrorReporter.reportInfo(MESSAGES.noProjectSelectedForDelete()); } } else { //We are deleting a project in the designer view List<Project> selectedProjects = new ArrayList<Project>(); Project currentProject = Ode.getInstance().getProjectManager() .getProject(Ode.getInstance().getCurrentYoungAndroidProjectId()); selectedProjects.add(currentProject); if (deleteConfirmation(selectedProjects)) { deleteProject(currentProject); //Add the command to stop this current project from saving Ode.getInstance().switchToProjectsView(); } } } }); } private boolean deleteConfirmation(List<Project> projects) { String message; GallerySettings gallerySettings = GalleryClient.getInstance().getGallerySettings(); if (projects.size() == 1) { if (projects.get(0).isPublished()) message = MESSAGES.confirmDeleteSinglePublishedProject(projects.get(0).getProjectName()); else message = MESSAGES.confirmDeleteSingleProject(projects.get(0).getProjectName()); } else { StringBuilder sb = new StringBuilder(); String separator = ""; for (Project project : projects) { sb.append(separator).append(project.getProjectName()); separator = ", "; } String projectNames = sb.toString(); if (!gallerySettings.galleryEnabled()) { message = MESSAGES.confirmDeleteManyProjects(projectNames); } else { message = MESSAGES.confirmDeleteManyProjectsWithGalleryOn(projectNames); } } return Window.confirm(message); } private void deleteProject(Project project) { Tracking.trackEvent(Tracking.PROJECT_EVENT, Tracking.PROJECT_ACTION_DELETE_PROJECT_YA, project.getProjectName()); final long projectId = project.getProjectId(); Ode ode = Ode.getInstance(); boolean isCurrentProject = (projectId == ode.getCurrentYoungAndroidProjectId()); ode.getEditorManager().closeProjectEditor(projectId); if (isCurrentProject) { // If we're deleting the project that is currently open in the Designer we // need to clear the ViewerBox first. ViewerBox.getViewerBox().clear(); } if (project.isPublished()) { doDeleteGalleryApp(project.getGalleryId()); } // Make sure that we delete projects even if they are not open. doDeleteProject(projectId); } private void doDeleteProject(final long projectId) { Ode.getInstance().getProjectService().deleteProject(projectId, new OdeAsyncCallback<Void>( // failure message MESSAGES.deleteProjectError()) { @Override public void onSuccess(Void result) { Ode.getInstance().getProjectManager().removeProject(projectId); // Show a welcome dialog in case there are no // projects saved. if (Ode.getInstance().getProjectManager().getProjects().size() == 0) { Ode.getInstance().createNoProjectsDialog(true); } } }); } private void doDeleteGalleryApp(final long galleryId) { Ode.getInstance().getGalleryService().deleteApp(galleryId, new OdeAsyncCallback<Void>( // failure message MESSAGES.galleryDeleteError()) { @Override public void onSuccess(Void result) { // need to update gallery list GalleryClient gallery = GalleryClient.getInstance(); gallery.appWasChanged(); } }); } } private static class DownloadKeystoreAction implements Command { @Override public void execute() { Ode.getInstance().getUserInfoService().hasUserFile(StorageUtil.ANDROID_KEYSTORE_FILENAME, new OdeAsyncCallback<Boolean>(MESSAGES.downloadKeystoreError()) { @Override public void onSuccess(Boolean keystoreFileExists) { if (keystoreFileExists) { Tracking.trackEvent(Tracking.USER_EVENT, Tracking.USER_ACTION_DOWNLOAD_KEYSTORE); Downloader.getInstance().download( ServerLayout.DOWNLOAD_SERVLET_BASE + ServerLayout.DOWNLOAD_USERFILE + "/" + StorageUtil.ANDROID_KEYSTORE_FILENAME); } else { Window.alert(MESSAGES.noKeystoreToDownload()); } } }); } } private class UploadKeystoreAction implements Command { @Override public void execute() { Ode.getInstance().getUserInfoService().hasUserFile(StorageUtil.ANDROID_KEYSTORE_FILENAME, new OdeAsyncCallback<Boolean>(MESSAGES.uploadKeystoreError()) { @Override public void onSuccess(Boolean keystoreFileExists) { if (!keystoreFileExists || Window.confirm(MESSAGES.confirmOverwriteKeystore())) { KeystoreUploadWizard wizard = new KeystoreUploadWizard(new Command() { @Override public void execute() { Tracking.trackEvent(Tracking.USER_EVENT, Tracking.USER_ACTION_UPLOAD_KEYSTORE); updateKeystoreFileMenuButtons(); } }); wizard.center(); } } }); } } private class DeleteKeystoreAction implements Command { @Override public void execute() { final String errorMessage = MESSAGES.deleteKeystoreError(); Ode.getInstance().getUserInfoService().hasUserFile(StorageUtil.ANDROID_KEYSTORE_FILENAME, new OdeAsyncCallback<Boolean>(errorMessage) { @Override public void onSuccess(Boolean keystoreFileExists) { if (keystoreFileExists && Window.confirm(MESSAGES.confirmDeleteKeystore())) { Tracking.trackEvent(Tracking.USER_EVENT, Tracking.USER_ACTION_DELETE_KEYSTORE); Ode.getInstance().getUserInfoService().deleteUserFile( StorageUtil.ANDROID_KEYSTORE_FILENAME, new OdeAsyncCallback<Void>(errorMessage) { @Override public void onSuccess(Void result) { updateKeystoreFileMenuButtons(); } }); } } }); } } /** * Made changes to the now Projects menu made name changes to the menu items * Implements the action to generate the ".yail" file for each screen in the current project. * It does not build the entire project. The intention is that this will be helpful for * debugging during development, and will most likely be disabled in the production system. */ private class GenerateYailAction implements Command { @Override public void execute() { ProjectRootNode projectRootNode = Ode.getInstance().getCurrentYoungAndroidProjectRootNode(); if (projectRootNode != null) { String target = YoungAndroidProjectNode.YOUNG_ANDROID_TARGET_ANDROID; ChainableCommand cmd = new SaveAllEditorsCommand(new GenerateYailCommand(null)); //updateBuildButton(true); cmd.startExecuteChain(Tracking.PROJECT_ACTION_BUILD_YAIL_YA, projectRootNode, new Command() { @Override public void execute() { //updateBuildButton(false); } }); } } } private static class AboutAction implements Command { @Override public void execute() { final DialogBox db = new DialogBox(false, true); db.setText("About MIT App Inventor"); db.setStyleName("ode-DialogBox"); db.setHeight("200px"); db.setWidth("400px"); db.setGlassEnabled(true); db.setAnimationEnabled(true); db.center(); VerticalPanel DialogBoxContents = new VerticalPanel(); String html = MESSAGES.gitBuildId(GitBuildId.getDate(), GitBuildId.getVersion()) + "<BR/>Use Companion: " + BlocklyPanel.getCompVersion(); Config config = Ode.getInstance().getSystemConfig(); String releaseNotesUrl = config.getReleaseNotesUrl(); if (!Strings.isNullOrEmpty(releaseNotesUrl)) { html += "<BR/><BR/>Please see <a href=\"" + releaseNotesUrl + "\" target=\"_blank\">release notes</a>"; } String tosUrl = config.getTosUrl(); if (!Strings.isNullOrEmpty(tosUrl)) { html += "<BR/><BR/><a href=\"" + tosUrl + "\" target=\"_blank\">" + MESSAGES.privacyTermsLink() + "</a>"; } HTML message = new HTML(html); SimplePanel holder = new SimplePanel(); Button ok = new Button("Close"); ok.addClickListener(new ClickListener() { public void onClick(Widget sender) { db.hide(); } }); holder.add(ok); DialogBoxContents.add(message); DialogBoxContents.add(holder); db.setWidget(DialogBoxContents); db.show(); } } private static class AboutCompanionAction implements Command { @Override public void execute() { final DialogBox db = new DialogBox(false, true); db.setText("About The Companion"); db.setStyleName("ode-DialogBox"); db.setHeight("200px"); db.setWidth("400px"); db.setGlassEnabled(true); db.setAnimationEnabled(true); db.center(); String downloadinfo = ""; if (!YaVersion.COMPANION_UPDATE_URL1.equals("")) { String url = "http://" + Window.Location.getHost() + YaVersion.COMPANION_UPDATE_URL1; downloadinfo = "<br/>\n<a href=" + url + ">Download URL: " + url + "</a><br/>\n"; downloadinfo += BlocklyPanel.getQRCode(url); } VerticalPanel DialogBoxContents = new VerticalPanel(); HTML message = new HTML("Companion Version " + BlocklyPanel.getCompVersion() + downloadinfo); SimplePanel holder = new SimplePanel(); Button ok = new Button("Close"); ok.addClickListener(new ClickListener() { public void onClick(Widget sender) { db.hide(); } }); holder.add(ok); DialogBoxContents.add(message); DialogBoxContents.add(holder); db.setWidget(DialogBoxContents); db.show(); } } private static class CompanionUpdateAction implements Command { @Override public void execute() { DesignToolbar.DesignProject currentProject = Ode.getInstance().getDesignToolbar().getCurrentProject(); if (currentProject == null) { Window.alert(MESSAGES.companionUpdateMustHaveProject()); return; } DesignToolbar.Screen screen = currentProject.screens.get(currentProject.currentScreen); screen.blocksEditor.updateCompanion(); } } private static class ShowSplashAction implements Command { @Override public void execute() { Ode.getInstance().showWelcomeDialog(); } } private static class WindowOpenAction implements Command { private final String url; WindowOpenAction(String url) { this.url = url; } @Override public void execute() { Window.open(url, WINDOW_OPEN_LOCATION, WINDOW_OPEN_FEATURES); } } private static class ImportComponentAction implements Command { @Override public void execute() { new ComponentImportWizard().center(); } } private static class BuildComponentAction implements Command { @Override public void execute() { // to be added } } private static class UploadComponentAction implements Command { @Override public void execute() { new ComponentUploadWizard().show(); } } private void updateConnectToDropDownButton(boolean isEmulatorRunning, boolean isCompanionRunning, boolean isUsbRunning) { if (!isEmulatorRunning && !isCompanionRunning && !isUsbRunning) { connectDropDown.setItemEnabled(MESSAGES.AICompanionMenuItem(), true); connectDropDown.setItemEnabled(MESSAGES.emulatorMenuItem(), true); connectDropDown.setItemEnabled(MESSAGES.usbMenuItem(), true); } else { connectDropDown.setItemEnabled(MESSAGES.AICompanionMenuItem(), false); connectDropDown.setItemEnabled(MESSAGES.emulatorMenuItem(), false); connectDropDown.setItemEnabled(MESSAGES.usbMenuItem(), false); } } /** * Indicate that we are no longer connected to the Companion, adjust * buttons accordingly. Called from BlocklyPanel */ public static void indicateDisconnect() { TopToolbar instance = Ode.getInstance().getTopToolbar(); instance.updateConnectToDropDownButton(false, false, false); } /** * startRepl -- Start/Stop the connection to the companion. * * @param start -- true to start the repl, false to stop it. * @param forEmulator -- true if we are connecting to the emulator. * @param forUsb -- true if this is a USB connection. * * If both forEmulator and forUsb are false, then we are connecting * via Wireless. */ private void startRepl(boolean start, boolean forEmulator, boolean forUsb) { DesignToolbar.DesignProject currentProject = Ode.getInstance().getDesignToolbar().getCurrentProject(); if (currentProject == null) { OdeLog.wlog("DesignToolbar.currentProject is null. " + "Ignoring attempt to start the repl."); return; } DesignToolbar.Screen screen = currentProject.screens.get(currentProject.currentScreen); screen.blocksEditor.startRepl(!start, forEmulator, forUsb); if (start) { if (forEmulator) { // We are starting the emulator... updateConnectToDropDownButton(true, false, false); } else if (forUsb) { // We are starting the usb connection updateConnectToDropDownButton(false, false, true); } else { // We are connecting via wifi to a Companion updateConnectToDropDownButton(false, true, false); } } else { updateConnectToDropDownButton(false, false, false); } } private void replHardReset() { DesignToolbar.DesignProject currentProject = Ode.getInstance().getDesignToolbar().getCurrentProject(); if (currentProject == null) { OdeLog.wlog("DesignToolbar.currentProject is null. " + "Ignoring attempt to do hard reset."); return; } DesignToolbar.Screen screen = currentProject.screens.get(currentProject.currentScreen); ((YaBlocksEditor) screen.blocksEditor).hardReset(); updateConnectToDropDownButton(false, false, false); } /** * Enables and/or disables buttons based on how many projects exist * (in the case of "Download All Projects") or are selected (in the case * of "Delete" and "Download Source"). */ public void updateFileMenuButtons(int view) { if (isReadOnly) { // This may be too simple return; } if (view == 0) { // We are in the Projects view fileDropDown.setItemEnabled(MESSAGES.deleteProjectButton(), false); fileDropDown.setItemEnabled(MESSAGES.deleteProjectMenuItem(), Ode.getInstance().getProjectManager().getProjects() == null); fileDropDown.setItemEnabled(MESSAGES.exportAllProjectsMenuItem(), Ode.getInstance().getProjectManager().getProjects().size() > 0); fileDropDown.setItemEnabled(MESSAGES.exportProjectMenuItem(), false); fileDropDown.setItemEnabled(MESSAGES.saveMenuItem(), false); fileDropDown.setItemEnabled(MESSAGES.saveAsMenuItem(), false); fileDropDown.setItemEnabled(MESSAGES.checkpointMenuItem(), false); buildDropDown.setItemEnabled(MESSAGES.showBarcodeMenuItem(), false); buildDropDown.setItemEnabled(MESSAGES.downloadToComputerMenuItem(), false); } else { // We have to be in the Designer/Blocks view fileDropDown.setItemEnabled(MESSAGES.deleteProjectButton(), true); fileDropDown.setItemEnabled(MESSAGES.exportAllProjectsMenuItem(), Ode.getInstance().getProjectManager().getProjects().size() > 0); fileDropDown.setItemEnabled(MESSAGES.exportProjectMenuItem(), true); fileDropDown.setItemEnabled(MESSAGES.saveMenuItem(), true); fileDropDown.setItemEnabled(MESSAGES.saveAsMenuItem(), true); fileDropDown.setItemEnabled(MESSAGES.checkpointMenuItem(), true); buildDropDown.setItemEnabled(MESSAGES.showBarcodeMenuItem(), true); buildDropDown.setItemEnabled(MESSAGES.downloadToComputerMenuItem(), true); } updateKeystoreFileMenuButtons(); } /** * Enables or disables buttons based on whether the user has an android.keystore file. */ public void updateKeystoreFileMenuButtons() { Ode.getInstance().getUserInfoService().hasUserFile(StorageUtil.ANDROID_KEYSTORE_FILENAME, new AsyncCallback<Boolean>() { @Override public void onSuccess(Boolean keystoreFileExists) { fileDropDown.setItemEnabled(MESSAGES.deleteKeystoreMenuItem(), keystoreFileExists); fileDropDown.setItemEnabled(MESSAGES.downloadKeystoreMenuItem(), keystoreFileExists); } @Override public void onFailure(Throwable caught) { // Enable the MenuItems. If they are clicked, we'll check again if the keystore exists. fileDropDown.setItemEnabled(MESSAGES.deleteKeystoreMenuItem(), true); fileDropDown.setItemEnabled(MESSAGES.downloadKeystoreMenuItem(), true); } }); } //Admin commands private static class DownloadUserSourceAction implements Command { @Override public void execute() { new DownloadUserSourceWizard().center(); } } private static class SwitchToDebugAction implements Command { @Override public void execute() { Ode.getInstance().switchToDebuggingView(); } } private static class SwitchToUserAdminAction implements Command { @Override public void execute() { Ode.getInstance().switchToUserAdminPanel(); } } }