package com.buildml.eclipse.files.handlers; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.viewers.TreeSelection; import org.eclipse.ui.handlers.HandlerUtil; import com.buildml.eclipse.MainEditor; import com.buildml.eclipse.utils.AlertDialog; import com.buildml.eclipse.utils.ConversionUtils; import com.buildml.eclipse.utils.EclipsePartUtils; import com.buildml.eclipse.utils.UndoOpAdapter; import com.buildml.eclipse.utils.handlers.AbstractHandlerWithProgress; import com.buildml.model.IActionMgr; import com.buildml.model.IBuildStore; import com.buildml.model.IFileMgr; import com.buildml.model.IFileMgr.PathType; import com.buildml.model.types.FileSet; import com.buildml.model.undo.MultiUndoOp; import com.buildml.refactor.CanNotRefactorException; import com.buildml.refactor.IImportRefactorer; /** * An Eclipse UI Handler for managing the "Delete File or Directory" UI command. * This handler tries to delete the file/directory and gives the user feedback * on anything that may have gone wrong in the process. * * @author Peter Smith <psmith@arapiki.com> */ public class HandlerDeletePath extends AbstractHandlerWithProgress { /*=====================================================================================* * PUBLIC METHODS *=====================================================================================*/ /* (non-Javadoc) * @see com.buildml.eclipse.utils.handlers.AbstractHandlerWithProgress#getCommandName() */ @Override public String getCommandName() { return "Deleting"; } /*-------------------------------------------------------------------------------------*/ /** * Execute the delete path operation (in a non-UI thread), but within the Progress Service. * * @param event The event information pass in from Eclipse. * @return Always null. */ @Override public Object executeWithProgress(ExecutionEvent event) { MainEditor mainEditor = EclipsePartUtils.getActiveMainEditor(); IBuildStore buildStore = mainEditor.getBuildStore(); IFileMgr fileMgr = buildStore.getFileMgr(); IActionMgr actionMgr = buildStore.getActionMgr(); IImportRefactorer refactorer = mainEditor.getImportRefactorer(); /* build a FileSet of all the selected files */ TreeSelection selection = (TreeSelection)HandlerUtil.getCurrentSelection(event); FileSet selectedPaths = EclipsePartUtils.getFileSetFromSelection(buildStore, selection); /* Note how many changes (deletions) actually happened */ int changesPerformed = 0; MultiUndoOp multiOp = new MultiUndoOp(); /* * For each file/directory that was selected, treat it as an individual "delete" * operation. */ for (int pathId : selectedPaths) { String pathName = fileMgr.getPathName(pathId); /* * Given that the user may select a directory and a file within that directory, * we first need to double-check that the path still exists when * we come to delete it. */ PathType pathType = fileMgr.getPathType(pathId); if (pathType == PathType.TYPE_INVALID) { continue; } boolean needsRetry; boolean deleteSubTree = false; boolean deleteActionToo = false; boolean deleteFromActions = false; do { needsRetry = false; try { if (deleteSubTree) { refactorer.deletePathTree(multiOp, pathId, deleteActionToo, deleteFromActions); } else { refactorer.deletePath(multiOp, pathId, deleteActionToo, deleteFromActions); } /* success! The file/directory was deleted */ changesPerformed++; } catch (CanNotRefactorException e) { Integer[] badIds = e.getCauseIDs(); boolean multipleActions = (badIds != null) && (badIds.length > 1); /* * Something stopped the delete from completing. Based on the error * code, we could potentially go back and try again. */ switch (e.getCauseCode()) { /* * The directory we're trying to delete is non-empty. Give the user the * option of deleting the whole sub-directory. */ case DIRECTORY_NOT_EMPTY: int status = AlertDialog.displayOKCancelDialog( "The directory: " + pathName + " is not empty.\n\n" + "Do you wish to try deleting all files in the directory?"); if (status == IDialogConstants.OK_ID) { needsRetry = true; deleteSubTree = true; } break; /* * The path we're trying to delete is a generated file. We'd need to * also delete the generating action. */ case PATH_IS_GENERATED: status = AlertDialog.displayOKCancelDialog( "The file " + pathName + " is generated by " + (multipleActions ? "several actions" : "an action") + ":\n\n" + ConversionUtils.getActionsAsText(actionMgr, badIds) + "\nDo you also wish to try deleting " + (multipleActions ? "the actions?" : "the action?")); if (status == IDialogConstants.OK_ID) { deleteActionToo = true; needsRetry = true; } break; /* * The path is used (read) by an action. It can't be deleted at all. */ case PATH_IN_USE: status = AlertDialog.displayOKCancelDialog( "The file " + pathName + " is still in use. Do you wish to delete it anyway?\n\n" + "It is used by the following " + (multipleActions ? "actions" : "action") + ":\n\n" + ConversionUtils.getActionsAsText(actionMgr, badIds)); if (status == IDialogConstants.OK_ID) { needsRetry = true; deleteFromActions = true; } break; /* * The path is a directory, but there are actions executing within that * directory. */ case DIRECTORY_CONTAINS_ACTIONS: AlertDialog.displayErrorDialog("Directory is busy", "The directory " + pathName + " can't be deleted as it's still " + "used as the working directory for the following " + (multipleActions ? "actions" : "action") + ":\n\n" + ConversionUtils.getActionsAsText(actionMgr, badIds)); break; /* * Can't delete a path that's generated by a non-atomic action. */ case ACTION_NOT_ATOMIC: AlertDialog.displayErrorDialog("Can't delete", "The file " + pathName + " can't be deleted as the action " + "that generates the file is not atomic:\n\n" + ConversionUtils.getActionsAsText(actionMgr, badIds)); break; /* * Can't delete an action (that generated the path), because it's in use * by some other paths. */ case ACTION_IN_USE: AlertDialog.displayErrorDialog("Can't delete", "The action that generates " + pathName + " can't be deleted since " + "the related files are still in use:\n\n" + ConversionUtils.getPathsAsText(fileMgr, badIds)); break; /* * Can't delete the path because it's still a member of a file group. */ case FILE_STILL_IN_GROUP: AlertDialog.displayErrorDialog("Can't delete", "The path " + pathName + " can't be deleted as it is currently " + "a member of one or more file groups."); break; /* * Ignore this case - it's likely because the parent has already been deleted. */ case INVALID_PATH: break; /* * These shouldn't happen. */ default: AlertDialog.displayErrorDialog("Deletion failed", "Deletion of the file/directory: " + pathName + " failed for the following reason: " + e.getCauseCode()); } } } while (needsRetry); } /* * If a deletion actually took place - refresh the view and add the operation * to the undo/redo history. */ if (changesPerformed > 0) { new UndoOpAdapter("Delete File" + ((changesPerformed > 1) ? "s" : ""), multiOp).invoke(); } return null; } /*-------------------------------------------------------------------------------------*/ }