add file color for navigation list items which are not PsiElements but could fetch...
[fedora-idea.git] / platform / lang-impl / src / com / intellij / ide / util / DeleteHandler.java
blobbc6793aa0b51a728f5d1c7a013c0f6697944edae
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.intellij.ide.util;
19 import com.intellij.CommonBundle;
20 import com.intellij.history.LocalHistory;
21 import com.intellij.history.LocalHistoryAction;
22 import com.intellij.ide.DataManager;
23 import com.intellij.ide.DeleteProvider;
24 import com.intellij.ide.IdeBundle;
25 import com.intellij.openapi.actionSystem.DataConstants;
26 import com.intellij.openapi.actionSystem.DataContext;
27 import com.intellij.openapi.actionSystem.PlatformDataKeys;
28 import com.intellij.openapi.application.ApplicationManager;
29 import com.intellij.openapi.command.CommandProcessor;
30 import com.intellij.openapi.fileTypes.FileTypeManager;
31 import com.intellij.openapi.project.DumbService;
32 import com.intellij.openapi.project.Project;
33 import com.intellij.openapi.ui.Messages;
34 import com.intellij.openapi.ui.ex.MessagesEx;
35 import com.intellij.openapi.vfs.VirtualFile;
36 import com.intellij.psi.PsiCompiledElement;
37 import com.intellij.psi.PsiDirectory;
38 import com.intellij.psi.PsiElement;
39 import com.intellij.psi.PsiFile;
40 import com.intellij.psi.util.PsiTreeUtil;
41 import com.intellij.refactoring.RefactoringBundle;
42 import com.intellij.refactoring.safeDelete.SafeDeleteProcessor;
43 import com.intellij.refactoring.util.CommonRefactoringUtil;
44 import com.intellij.refactoring.util.RefactoringUIUtil;
45 import com.intellij.util.IncorrectOperationException;
46 import com.intellij.util.io.ReadOnlyAttributeUtil;
47 import org.jetbrains.annotations.Nullable;
49 import java.io.IOException;
50 import java.util.ArrayList;
51 import java.util.Arrays;
53 public class DeleteHandler {
54 public static class DefaultDeleteProvider implements DeleteProvider {
55 public boolean canDeleteElement(DataContext dataContext) {
56 if (dataContext.getData(DataConstants.PROJECT) == null) return false;
57 final PsiElement[] elements = getPsiElements(dataContext);
58 return elements != null && DeleteHandler.shouldEnableDeleteAction(elements);
61 @Nullable
62 private PsiElement[] getPsiElements(DataContext dataContext) {
63 PsiElement[] elements = (PsiElement[])dataContext.getData(DataConstants.PSI_ELEMENT_ARRAY);
64 if (elements == null) {
65 final Object data = dataContext.getData(DataConstants.PSI_ELEMENT);
66 if (data != null) {
67 elements = new PsiElement[]{(PsiElement)data};
69 else {
70 final Object data1 = dataContext.getData(DataConstants.PSI_FILE);
71 if (data1 != null) {
72 elements = new PsiElement[]{(PsiFile)data1};
76 return elements;
79 public void deleteElement(DataContext dataContext) {
80 PsiElement[] elements = getPsiElements(dataContext);
81 if (elements == null) return;
82 Project project = PlatformDataKeys.PROJECT.getData(dataContext);
83 if (project == null) return;
84 LocalHistoryAction a = LocalHistory.startAction(project, IdeBundle.message("progress.deleting"));
85 try {
86 deletePsiElement(elements, project);
88 finally {
89 a.finish();
94 public static void deletePsiElement(final PsiElement[] elementsToDelete, final Project project) {
95 if (elementsToDelete == null || elementsToDelete.length == 0) return;
97 final PsiElement[] elements = PsiTreeUtil.filterAncestors(elementsToDelete);
99 boolean safeDeleteApplicable = true;
100 for (int i = 0; i < elements.length && safeDeleteApplicable; i++) {
101 PsiElement element = elements[i];
102 safeDeleteApplicable = SafeDeleteProcessor.validElement(element);
105 final boolean dumb = DumbService.getInstance(project).isDumb();
106 if (safeDeleteApplicable && !dumb) {
107 DeleteDialog dialog = new DeleteDialog(project, elements, new DeleteDialog.Callback() {
108 public void run(final DeleteDialog dialog) {
109 if (!CommonRefactoringUtil.checkReadOnlyStatusRecursively(project, Arrays.asList(elements))) return;
110 SafeDeleteProcessor.createInstance(project, new Runnable() {
111 public void run() {
112 dialog.close(DeleteDialog.CANCEL_EXIT_CODE);
114 }, elements, dialog.isSearchInComments(), dialog.isSearchInNonJava(), true).run();
117 dialog.show();
118 if (!dialog.isOK()) return;
120 else {
121 @SuppressWarnings({"UnresolvedPropertyKey"})
122 String warningMessage = DeleteUtil.generateWarningMessage(IdeBundle.message("prompt.delete.elements"), elements);
124 boolean anyDirectories = false;
125 String directoryName = null;
126 for (PsiElement psiElement : elementsToDelete) {
127 if (psiElement instanceof PsiDirectory) {
128 anyDirectories = true;
129 directoryName = ((PsiDirectory)psiElement).getName();
130 break;
133 if (anyDirectories) {
134 if (elements.length == 1) {
135 warningMessage += IdeBundle.message("warning.delete.all.files.and.subdirectories", directoryName);
137 else {
138 warningMessage += IdeBundle.message("warning.delete.all.files.and.subdirectories.in.the.selected.directory");
142 if (safeDeleteApplicable && dumb) {
143 warningMessage += "\n\nWarning:\n Safe delete is not available while IntelliJ IDEA updates indices,\n no usages will be checked.";
146 int result = Messages.showDialog(project, warningMessage, IdeBundle.message("title.delete"),
147 new String[]{CommonBundle.getOkButtonText(), CommonBundle.getCancelButtonText()}, 0,
148 Messages.getQuestionIcon());
149 if (result != 0) return;
152 final FileTypeManager ftManager = FileTypeManager.getInstance();
153 CommandProcessor.getInstance().executeCommand(project, new Runnable() {
154 public void run() {
155 CommonRefactoringUtil.checkReadOnlyStatusRecursively(project, Arrays.asList(elements), false);
157 // deleted from project view or something like that.
158 if (PlatformDataKeys.EDITOR.getData(DataManager.getInstance().getDataContext()) == null) {
159 CommandProcessor.getInstance().markCurrentCommandAsGlobal(project);
162 for (final PsiElement elementToDelete : elements) {
163 if (!elementToDelete.isValid()) continue; //was already deleted
164 if (elementToDelete instanceof PsiDirectory) {
165 VirtualFile virtualFile = ((PsiDirectory)elementToDelete).getVirtualFile();
166 if (virtualFile.isInLocalFileSystem()) {
168 ArrayList<VirtualFile> readOnlyFiles = new ArrayList<VirtualFile>();
169 getReadOnlyVirtualFiles(virtualFile, readOnlyFiles, ftManager);
171 if (readOnlyFiles.size() > 0) {
172 int _result = Messages.showYesNoDialog(project, IdeBundle.message("prompt.directory.contains.read.only.files",
173 virtualFile.getPresentableUrl()),
174 IdeBundle.message("title.delete"), Messages.getQuestionIcon());
175 if (_result != 0) continue;
177 boolean success = true;
178 for (VirtualFile file : readOnlyFiles) {
179 success = clearReadOnlyFlag(file, project);
180 if (!success) break;
182 if (!success) continue;
186 else if (!elementToDelete.isWritable()) {
187 final PsiFile file = elementToDelete.getContainingFile();
188 if (file != null) {
189 final VirtualFile virtualFile = file.getVirtualFile();
190 if (virtualFile.isInLocalFileSystem()) {
191 int _result = MessagesEx.fileIsReadOnly(project, virtualFile)
192 .setTitle(IdeBundle.message("title.delete"))
193 .appendMessage(IdeBundle.message("prompt.delete.it.anyway"))
194 .askYesNo();
195 if (_result != 0) continue;
197 boolean success = clearReadOnlyFlag(virtualFile, project);
198 if (!success) continue;
203 try {
204 elementToDelete.checkDelete();
206 catch (IncorrectOperationException ex) {
207 Messages.showMessageDialog(project, ex.getMessage(), CommonBundle.getErrorTitle(), Messages.getErrorIcon());
208 continue;
211 ApplicationManager.getApplication().runWriteAction(new Runnable() {
212 public void run() {
213 try {
214 elementToDelete.delete();
216 catch (final IncorrectOperationException ex) {
217 ApplicationManager.getApplication().invokeLater(new Runnable() {
218 public void run() {
219 Messages.showMessageDialog(project, ex.getMessage(), CommonBundle.getErrorTitle(), Messages.getErrorIcon());
227 }, RefactoringBundle.message("safe.delete.command", RefactoringUIUtil.calculatePsiElementDescriptionList(elements)), null);
230 private static boolean clearReadOnlyFlag(final VirtualFile virtualFile, final Project project) {
231 final boolean[] success = new boolean[1];
232 CommandProcessor.getInstance().executeCommand(project, new Runnable() {
233 public void run() {
234 Runnable action = new Runnable() {
235 public void run() {
236 try {
237 ReadOnlyAttributeUtil.setReadOnlyAttribute(virtualFile, false);
238 success[0] = true;
240 catch (IOException e1) {
241 Messages.showMessageDialog(project, e1.getMessage(), CommonBundle.getErrorTitle(), Messages.getErrorIcon());
245 ApplicationManager.getApplication().runWriteAction(action);
247 }, "", null);
248 return success[0];
252 * Fills readOnlyFiles with VirtualFiles
254 private static void getReadOnlyVirtualFiles(VirtualFile file, ArrayList<VirtualFile> readOnlyFiles, final FileTypeManager ftManager) {
255 if (ftManager.isFileIgnored(file.getName())) return;
256 if (!file.isWritable()) {
257 readOnlyFiles.add(file);
259 if (file.isDirectory()) {
260 VirtualFile[] children = file.getChildren();
261 for (VirtualFile child : children) {
262 getReadOnlyVirtualFiles(child, readOnlyFiles, ftManager);
267 public static boolean shouldEnableDeleteAction(PsiElement[] elements) {
268 if (elements == null || elements.length == 0) return false;
269 for (PsiElement element : elements) {
270 if (element instanceof PsiCompiledElement) {
271 return false;
274 return true;