diff --git a/appinventor/appengine/src/com/google/appinventor/client/OdeMessages.java b/appinventor/appengine/src/com/google/appinventor/client/OdeMessages.java index e4180713f0f..440a007ce94 100755 --- a/appinventor/appengine/src/com/google/appinventor/client/OdeMessages.java +++ b/appinventor/appengine/src/com/google/appinventor/client/OdeMessages.java @@ -1820,13 +1820,20 @@ public interface OdeMessages extends Messages, ComponentTranslations { @Description("Confirmation message for selecting multiple projects and clicking delete") String confirmDeleteManyProjects(String projectNames); - @DefaultMessage("Are you sure you want to move these projects to trash: {0}?") + @DefaultMessage("Are you sure you want to move these items to trash? {0}") @Description("Confirmation message for selecting multiple projects and clicking trash") String confirmMoveToTrash(String projectNames); + @DefaultMessage("Are you sure you want to delete these items permanently? {0}") + @Description("Confirmation message for selecting multiple projects in trash and clicking delete") + String confirmDeleteForever(String projectNames); - @DefaultMessage("Are you sure you want to move {0} projects to trash?") - @Description("Confirmation message deleting large number of selected projects") - String confirmMoveToTrashCount(String projectNames); + @DefaultMessage("Projects: {0}") + @Description("Information on selected projects for delete/trash confirmation") + String confirmTrashDeleteProjects(String projectNames); + + @DefaultMessage("Folders: {0}") + @Description("Information on selected folders for delete/trash confirmation") + String confirmTrashDeleteFolders(String folderNames); @DefaultMessage("Server error: could not delete project. Please try again later!") @Description("Error message reported when deleting a project failed on the server.") diff --git a/appinventor/appengine/src/com/google/appinventor/client/actions/DeleteAction.java b/appinventor/appengine/src/com/google/appinventor/client/actions/DeleteAction.java index 0c7d224b9de..5f03acceed5 100644 --- a/appinventor/appengine/src/com/google/appinventor/client/actions/DeleteAction.java +++ b/appinventor/appengine/src/com/google/appinventor/client/actions/DeleteAction.java @@ -25,22 +25,21 @@ public void execute() { @Override public void execute() { if (Ode.getInstance().getCurrentView() == Ode.PROJECTS) { - List selectedProjects = - ProjectListBox.getProjectListBox().getProjectList().getSelectedProjects(); + List selectedProjects = ProjectListBox.getProjectListBox().getProjectList() + .getSelectedProjects(); List selectedFolders = ProjectListBox.getProjectListBox().getProjectList().getSelectedFolders(); - if (selectedProjects.size() > 0 || selectedFolders.size() > 0) { - List projectsToDelete = selectedProjects; + if (!selectedProjects.isEmpty() || !selectedFolders.isEmpty()) { + List projectsToDelete = new ArrayList<>(selectedProjects); + List foldersToDelete = new ArrayList<>(selectedFolders); for (ProjectFolder f : selectedFolders) { projectsToDelete.addAll(f.getNestedProjects()); + foldersToDelete.addAll(f.getNestedFolders()); } // Show one confirmation window for selected projects. - if (deleteConfirmation(projectsToDelete)) { - for (Project project : projectsToDelete) { - project.moveToTrash(); - } - for (ProjectFolder f : selectedFolders) { - f.getParentFolder().removeChildFolder(f); - } + if (deleteConfirmation(true, projectsToDelete, foldersToDelete)) { + Ode.getInstance().getFolderManager().moveItemsToFolder(selectedProjects, selectedFolders, + Ode.getInstance().getFolderManager().getTrashFolder()); + Ode.getInstance().getFolderManager().saveAllFolders(); } } else { // The user can select a project to resolve the @@ -48,10 +47,10 @@ public void execute() { ErrorReporter.reportInfo(MESSAGES.noProjectSelectedForDelete()); } } else { //We are deleting a project in the designer view - List selectedProjects = new ArrayList(); + List selectedProjects = new ArrayList<>(); Project currentProject = Ode.getInstance().getProjectManager().getProject(Ode.getInstance().getCurrentYoungAndroidProjectId()); selectedProjects.add(currentProject); - if (deleteConfirmation(selectedProjects)) { + if (deleteConfirmation(true, selectedProjects, new ArrayList<>())) { currentProject.moveToTrash(); //Add the command to stop this current project from saving } @@ -62,21 +61,46 @@ public void execute() { } - private boolean deleteConfirmation(List projects) { - String message; - if (projects.size() == 1) { + public static boolean deleteConfirmation(boolean toTrash, List projects, List folders) { + String message = ""; + if (toTrash && projects.size() == 1 && folders.isEmpty()) { message = MESSAGES.confirmMoveToTrashSingleProject(projects.get(0).getProjectName()); - } else if (projects.size() < 10) { - StringBuilder sb = new StringBuilder(); - String separator = ""; - for (Project project : projects) { - sb.append(separator).append(project.getProjectName()); - separator = ", "; - } - String projectNames = sb.toString(); - message = MESSAGES.confirmMoveToTrash(projectNames); } else { - message = MESSAGES.confirmMoveToTrashCount(Integer.toString(projects.size())); + String projMsg = ""; + String folderMsg = ""; + if (projects.isEmpty()) { + projMsg = ""; + } else if (projects.size() < 10) { + StringBuilder sb = new StringBuilder(); + String separator = ""; + for (Project project : projects) { + sb.append(separator).append(project.getProjectName()); + separator = ", "; + } + String projectNames = sb.toString(); + projMsg = "\n " +MESSAGES.confirmTrashDeleteProjects(projectNames); + } else { + projMsg = "\n " +MESSAGES.confirmTrashDeleteFolders(Integer.toString(projects.size())); + } + if (folders.isEmpty()) { + folderMsg = ""; + } else if (folders.size() < 10) { + StringBuilder sb = new StringBuilder(); + String separator = ""; + for (ProjectFolder folder : folders) { + sb.append(separator).append(folder.getName()); + separator = ", "; + } + String folderNames = sb.toString(); + folderMsg = "\n " + MESSAGES.confirmTrashDeleteFolders(folderNames); + } else { + folderMsg = "\n " + MESSAGES.confirmTrashDeleteFolders(Integer.toString(folders.size())); + } + if (toTrash) { + message = MESSAGES.confirmMoveToTrash(projMsg + folderMsg); + } else { + message = MESSAGES.confirmDeleteForever(projMsg + folderMsg); + } } return Window.confirm(message); } diff --git a/appinventor/appengine/src/com/google/appinventor/client/actions/DeleteForeverProjectAction.java b/appinventor/appengine/src/com/google/appinventor/client/actions/DeleteForeverProjectAction.java index e288540b375..8943bbb6d0c 100644 --- a/appinventor/appengine/src/com/google/appinventor/client/actions/DeleteForeverProjectAction.java +++ b/appinventor/appengine/src/com/google/appinventor/client/actions/DeleteForeverProjectAction.java @@ -11,9 +11,12 @@ import com.google.appinventor.client.ErrorReporter; import com.google.appinventor.client.Ode; import com.google.appinventor.client.boxes.ProjectListBox; +import com.google.appinventor.client.explorer.folder.ProjectFolder; import com.google.appinventor.client.explorer.project.Project; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.Window; + +import java.util.ArrayList; import java.util.List; public class DeleteForeverProjectAction implements Command { @@ -23,15 +26,27 @@ public void execute() { @Override public void execute() { if (Ode.getInstance().getCurrentView() == Ode.TRASHCAN) { - List deletedProjects = ProjectListBox.getProjectListBox().getProjectList() + List selectedProjects = ProjectListBox.getProjectListBox().getProjectList() .getSelectedProjects(); - if (deletedProjects.size() > 0) { + List selectedFolders = ProjectListBox.getProjectListBox().getProjectList() + .getSelectedFolders(); + if (!selectedProjects.isEmpty() || !selectedFolders.isEmpty()) { + List projectsToDelete = new ArrayList<>(selectedProjects); + List foldersToDelete = new ArrayList<>(selectedFolders); + for (ProjectFolder f : selectedFolders) { + projectsToDelete.addAll(f.getNestedProjects()); + foldersToDelete.addAll(f.getNestedFolders()); + } // Show one confirmation window for selected projects. - if (deleteConfirmation(deletedProjects)) { - for (Project project : deletedProjects) { + if (DeleteAction.deleteConfirmation(false, projectsToDelete, foldersToDelete)) { + for (Project project : selectedProjects) { project.deleteFromTrash(); } + for (ProjectFolder folder : selectedFolders) { + folder.deleteFromTrash(); + } } + Ode.getInstance().getFolderManager().saveAllFolders(); Ode.getInstance().switchToTrash(); } else { // The user can select a project to resolve the diff --git a/appinventor/appengine/src/com/google/appinventor/client/actions/RestoreProjectAction.java b/appinventor/appengine/src/com/google/appinventor/client/actions/RestoreProjectAction.java index 64fad5ce4cb..c96b653fbe9 100644 --- a/appinventor/appengine/src/com/google/appinventor/client/actions/RestoreProjectAction.java +++ b/appinventor/appengine/src/com/google/appinventor/client/actions/RestoreProjectAction.java @@ -9,6 +9,7 @@ import com.google.appinventor.client.ErrorReporter; import com.google.appinventor.client.Ode; import com.google.appinventor.client.boxes.ProjectListBox; +import com.google.appinventor.client.explorer.folder.ProjectFolder; import com.google.appinventor.client.explorer.project.Project; import com.google.gwt.user.client.Command; @@ -22,10 +23,11 @@ public void execute() { if (Ode.getInstance().getCurrentView() == Ode.TRASHCAN) { List selectedProjects = ProjectListBox.getProjectListBox().getProjectList() .getSelectedProjects(); - if (selectedProjects.size() > 0) { - for (Project project : selectedProjects) { - project.restoreFromTrash(); - } + List selectedFolders = ProjectListBox.getProjectListBox().getProjectList() + .getSelectedFolders(); + if (!selectedProjects.isEmpty() || !selectedFolders.isEmpty()) { + Ode.getInstance().getFolderManager().moveItemsToFolder(selectedProjects, selectedFolders, + Ode.getInstance().getFolderManager().getGlobalFolder()); Ode.getInstance().switchToTrash(); } else { // The user can select a project to resolve the diff --git a/appinventor/appengine/src/com/google/appinventor/client/explorer/folder/ProjectFolder.java b/appinventor/appengine/src/com/google/appinventor/client/explorer/folder/ProjectFolder.java index 08cda851d62..eb50917c1c3 100644 --- a/appinventor/appengine/src/com/google/appinventor/client/explorer/folder/ProjectFolder.java +++ b/appinventor/appengine/src/com/google/appinventor/client/explorer/folder/ProjectFolder.java @@ -282,7 +282,7 @@ public List getVisibleProjects(boolean onlySelected) { } public boolean containsAnyProjects() { - if (projectListItems.size() > 0) { + if (!projectListItems.isEmpty()) { return true; } else if (hasChildFolders()) { for (ProjectFolder f : folders.values()) { @@ -294,6 +294,26 @@ public boolean containsAnyProjects() { return false; } + public boolean isInTrash() { + if (parent == null || parent == Ode.getInstance().getFolderManager().getGlobalFolder()) { + return false; + } else if (parent == Ode.getInstance().getFolderManager().getTrashFolder()) { + return true; + } else { + return parent.isInTrash(); + } + } + + public void deleteFromTrash() { + for (Project project : projects) { + project.deleteFromTrash(); + } + for (ProjectFolder folder : getChildFolders()) { + folder.deleteFromTrash(); + } + parent.removeChildFolder(this); + } + public List getSelectedFolders() { return getSelectableFolders(true); } @@ -356,6 +376,15 @@ public List getChildFolders() { return Arrays.asList(folders.values().toArray(new ProjectFolder[0])); } + public List getNestedFolders() { + List flist = new ArrayList<>(); + flist.addAll(getChildFolders()); + for (ProjectFolder child : getChildFolders()) { + flist.addAll(child.getNestedFolders()); + } + return flist; + } + public boolean hasChildFolders() { return !folders.isEmpty(); } diff --git a/appinventor/appengine/src/com/google/appinventor/client/explorer/project/Project.java b/appinventor/appengine/src/com/google/appinventor/client/explorer/project/Project.java index 150b0db86a0..9384e19de77 100644 --- a/appinventor/appengine/src/com/google/appinventor/client/explorer/project/Project.java +++ b/appinventor/appengine/src/com/google/appinventor/client/explorer/project/Project.java @@ -242,29 +242,11 @@ public void moveToTrash() { public void onSuccess(UserProject project) { if (project.getProjectId() == projectInfo.getProjectId()) { projectInfo.moveToTrash(); - Ode.getInstance().getProjectManager().trashProject(getProjectId()); } } }); } - public void restoreFromTrash() { - Tracking.trackEvent(Tracking.PROJECT_EVENT, - Tracking.PROJECT_ACTION_RESTORE_PROJECT_YA, getProjectName()); - Ode.getInstance().getProjectService().restoreProject(getProjectId(), - new OdeAsyncCallback( - // failure message - MESSAGES.restoreProjectError()) { - @Override - public void onSuccess(UserProject project) { - if (project.getProjectId() == projectInfo.getProjectId()) { - projectInfo.restoreFromTrash(); - Ode.getInstance().getProjectManager().restoreTrashProject(getProjectId()); - } - } - }); - } - public void deleteFromTrash() { Tracking.trackEvent(Tracking.PROJECT_EVENT, Tracking.PROJECT_ACTION_DELETE_PROJECT_YA, getProjectName()); @@ -278,7 +260,12 @@ public void onSuccess(Void result) { } public boolean isInTrash() { - return projectInfo.isInTrash(); + if (homeFolder == null || homeFolder == Ode.getInstance().getFolderManager().getGlobalFolder()) { + return false; + } else if (homeFolder == Ode.getInstance().getFolderManager().getTrashFolder()) { + return true; + } + return homeFolder.isInTrash(); } /** diff --git a/appinventor/appengine/src/com/google/appinventor/client/explorer/project/ProjectManager.java b/appinventor/appengine/src/com/google/appinventor/client/explorer/project/ProjectManager.java index 28605963018..10d5af52c55 100644 --- a/appinventor/appengine/src/com/google/appinventor/client/explorer/project/ProjectManager.java +++ b/appinventor/appengine/src/com/google/appinventor/client/explorer/project/ProjectManager.java @@ -164,24 +164,7 @@ public Project addProject(UserProject projectInfo) { */ public void removeDeletedProject(long projectId) { - Project project = projectsMap.remove(projectId); - fireProjectDeleted(project); - } - - /** - * Restores the project from trash back to my projects. - * - * @param projectId project ID - */ - - public void restoreTrashProject(long projectId) { - Project project = projectsMap.get(projectId); - fireTrashProjectRestored(project); - } - - public void trashProject(long projectId) { - Project project = projectsMap.get(projectId); - fireProjectTrashed(project); + projectsMap.remove(projectId); } /** @@ -219,27 +202,6 @@ private void fireProjectAdded(Project project) { } } - /* - * Triggers a 'project removed' event to be sent to the listener on the listener list. - */ - private void fireTrashProjectRestored(Project project) { - for (ProjectManagerEventListener listener : copyProjectManagerEventListeners()) { - listener.onTrashProjectRestored(project); - } - } - - private void fireProjectTrashed(Project project) { - for (ProjectManagerEventListener listener : copyProjectManagerEventListeners()) { - listener.onProjectTrashed(project); - } - } - - private void fireProjectDeleted(Project project) { - for (ProjectManagerEventListener listener : copyProjectManagerEventListeners()) { - listener.onProjectDeleted(project); - } - } - public boolean isProjectInTrash(long projectId) { Project project = projectsMap.get(projectId); return project != null && project.isInTrash(); diff --git a/appinventor/appengine/src/com/google/appinventor/client/explorer/youngandroid/ProjectList.java b/appinventor/appengine/src/com/google/appinventor/client/explorer/youngandroid/ProjectList.java index c969ef521d4..eaa6b196152 100644 --- a/appinventor/appengine/src/com/google/appinventor/client/explorer/youngandroid/ProjectList.java +++ b/appinventor/appengine/src/com/google/appinventor/client/explorer/youngandroid/ProjectList.java @@ -87,10 +87,10 @@ public ProjectList() { bindIU(); setIsTrash(false); refreshSortIndicators(); - Ode.getInstance().getFolderManager().addFolderManagerEventListener(this); +// Ode.getInstance().getFolderManager().addFolderManagerEventListener(this); // It is important to listen to project manager events as soon as possible. - Ode.getInstance().getProjectManager().addProjectManagerEventListener(this); +// Ode.getInstance().getProjectManager().addProjectManagerEventListener(this); } public void bindIU() { @@ -261,7 +261,7 @@ public void onSelectionChange(boolean selected) { selectAllCheckBox.setValue(false); Ode.getInstance().getProjectToolbar().updateButtons(); - if (isTrash && folder.getProjects().isEmpty()) { + if (isTrash && folder.getProjects().isEmpty() && folder.getChildFolders().isEmpty()) { Ode.getInstance().createEmptyTrashDialog(true); } } @@ -386,29 +386,16 @@ public void onProjectAdded(Project project) { @Override public void onTrashProjectRestored(Project project) { - Ode.getInstance().getFolderManager().getGlobalFolder().addProject(project); - Ode.getInstance().getFolderManager().getTrashFolder().removeProject(project); - Ode.getInstance().getFolderManager().saveAllFolders(); - refresh(); } @Override public void onProjectTrashed(Project project) { - folder.removeProject(project); - Ode.getInstance().getFolderManager().getTrashFolder().addProject(project); - Ode.getInstance().getFolderManager().saveAllFolders(); - refresh(); - } - public void onProjectMoved(Project project) { - refresh(); } @Override public void onProjectDeleted(Project project) { - folder.removeProject(project); - Ode.getInstance().getFolderManager().saveAllFolders(); - refresh(); + } @Override diff --git a/appinventor/appengine/src/com/google/appinventor/client/wizards/MoveProjectsWizard.java b/appinventor/appengine/src/com/google/appinventor/client/wizards/MoveProjectsWizard.java index b4f739d9c0a..172d89111aa 100644 --- a/appinventor/appengine/src/com/google/appinventor/client/wizards/MoveProjectsWizard.java +++ b/appinventor/appengine/src/com/google/appinventor/client/wizards/MoveProjectsWizard.java @@ -42,6 +42,8 @@ interface MoveProjectsWizardUiBinder extends UiBinder selectedProjects; + private List selectedFolders; /** * Creates a new wizard for moving projects. @@ -50,7 +52,12 @@ public MoveProjectsWizard() { uibinder.createAndBindUi(this); manager = Ode.getInstance().getFolderManager(); + ProjectList projectList = ProjectListBox.getProjectListBox().getProjectList(); + selectedProjects = projectList.getSelectedProjects(); + selectedFolders = projectList.getSelectedFolders(); FolderTreeItem root = renderFolder(manager.getGlobalFolder()); + // This undescriptive method below sets whether the tree is expanded or not + root.setState(true); tree.addItem(root); tree.setSelectedItem(root); moveDialog.center(); @@ -71,15 +78,15 @@ public void onBlur(BlurEvent event) { }); } - static FolderTreeItem renderFolder(ProjectFolder folder) { + FolderTreeItem renderFolder(ProjectFolder folder) { FolderTreeItem treeItem = new FolderTreeItem(folder); - for (ProjectFolder child : folder.getChildFolders()) { - if (!"*trash*".equals(child.getName())) { - FolderTreeItem childItem = renderFolder(child); - childItem.setState(true); - treeItem.addItem(childItem); + for (ProjectFolder child : folder.getChildFolders()) { + if (!"*trash*".equals(child.getName()) && !selectedFolders.contains(child)) { + FolderTreeItem childItem = renderFolder(child); + childItem.setState(true); + treeItem.addItem(childItem); + } } - } return treeItem; } @@ -93,9 +100,6 @@ void cancelMove(ClickEvent e) { @UiHandler("moveButton") void moveProjects(ClickEvent e) { FolderTreeItem treeItem = (FolderTreeItem) tree.getSelectedItem(); - ProjectList projectList = ProjectListBox.getProjectListBox().getProjectList(); - List selectedProjects = projectList.getSelectedProjects(); - List selectedFolders = projectList.getSelectedFolders(); manager.moveItemsToFolder(selectedProjects, selectedFolders, treeItem.getFolder()); moveDialog.hide();