hide "remove module" in IDEs other than IDEA which don't have attach capability ...
[idea/community.git] / platform / lang-impl / src / com / intellij / openapi / roots / ui / configuration / actions / ModuleDeleteProvider.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package com.intellij.openapi.roots.ui.configuration.actions;
18
19 import com.intellij.ide.DeleteProvider;
20 import com.intellij.ide.TitledHandler;
21 import com.intellij.openapi.actionSystem.DataContext;
22 import com.intellij.openapi.actionSystem.LangDataKeys;
23 import com.intellij.openapi.actionSystem.PlatformDataKeys;
24 import com.intellij.openapi.application.ApplicationManager;
25 import com.intellij.openapi.command.CommandProcessor;
26 import com.intellij.openapi.module.ModifiableModuleModel;
27 import com.intellij.openapi.module.Module;
28 import com.intellij.openapi.module.ModuleManager;
29 import com.intellij.openapi.project.Project;
30 import com.intellij.openapi.project.ProjectBundle;
31 import com.intellij.openapi.roots.*;
32 import com.intellij.openapi.ui.Messages;
33 import com.intellij.openapi.util.text.StringUtil;
34 import com.intellij.projectImport.ProjectAttachProcessor;
35 import com.intellij.util.ArrayUtil;
36 import com.intellij.util.Function;
37 import com.intellij.util.PlatformUtils;
38 import org.jetbrains.annotations.NotNull;
39 import org.jetbrains.annotations.Nullable;
40
41 import java.io.File;
42 import java.util.Arrays;
43 import java.util.Collection;
44 import java.util.HashMap;
45 import java.util.Map;
46
47 public class ModuleDeleteProvider  implements DeleteProvider, TitledHandler  {
48   public boolean canDeleteElement(DataContext dataContext) {
49     final Module[] modules = LangDataKeys.MODULE_CONTEXT_ARRAY.getData(dataContext);
50     return modules != null && !isPrimaryModule(modules);
51   }
52
53   private static boolean isPrimaryModule(Module[] modules) {
54     if (!ProjectAttachProcessor.canAttachToProject()) {
55       return !PlatformUtils.isIdea();
56     }
57     for (Module module : modules) {
58       final File moduleFile = new File(module.getModuleFilePath());
59       final File projectFile = new File(module.getProject().getProjectFilePath());
60       if (moduleFile.getParent().equals(projectFile.getParent()) && moduleFile.getParentFile().getName().equals(".idea")) {
61         return true;
62       }
63     }
64     return false;
65   }
66
67   public void deleteElement(DataContext dataContext) {
68     final Module[] modules = LangDataKeys.MODULE_CONTEXT_ARRAY.getData(dataContext);
69     assert modules != null;
70     final Project project = PlatformDataKeys.PROJECT.getData(dataContext);
71     String names = StringUtil.join(Arrays.asList(modules), new Function<Module, String>() {
72       public String fun(final Module module) {
73         return "\'" + module.getName() + "\'";
74       }
75     }, ", ");
76     int ret = Messages.showOkCancelDialog(getConfirmationText(modules, names), getActionTitle(), Messages.getQuestionIcon());
77     if (ret != 0) return;
78     CommandProcessor.getInstance().executeCommand(project, new Runnable() {
79       public void run() {
80         final Runnable action = new Runnable() {
81           public void run() {
82             final ModuleManager moduleManager = ModuleManager.getInstance(project);
83             final Module[] currentModules = moduleManager.getModules();
84             final ModifiableModuleModel modifiableModuleModel = moduleManager.getModifiableModel();
85             final Map<Module, ModifiableRootModel> otherModuleRootModels = new HashMap<Module, ModifiableRootModel>();
86             for (final Module module : modules) {
87               final ModifiableRootModel modifiableModel = ModuleRootManager.getInstance(module).getModifiableModel();
88               for (final Module otherModule : currentModules) {
89                 if (otherModule == module || ArrayUtil.find(modules, otherModule) != -1) continue;
90                 if (!otherModuleRootModels.containsKey(otherModule)) {
91                   otherModuleRootModels.put(otherModule, ModuleRootManager.getInstance(otherModule).getModifiableModel());
92                 }
93               }
94               removeModule(module, modifiableModel, otherModuleRootModels.values(), modifiableModuleModel);
95             }
96             final ModifiableRootModel[] modifiableRootModels = otherModuleRootModels.values().toArray(new ModifiableRootModel[otherModuleRootModels.size()]);
97             ProjectRootManager.getInstance(project).multiCommit(modifiableModuleModel, modifiableRootModels);
98           }
99         };
100         ApplicationManager.getApplication().runWriteAction(action);
101       }
102     }, ProjectBundle.message("module.remove.command"), null);
103   }
104
105   private static String getConfirmationText(Module[] modules, String names) {
106     if (ProjectAttachProcessor.canAttachToProject()) {
107       return "Would you like to detach the project" + (modules.length > 1 ? "s " : " ") +  names + "?";
108     }
109     return ProjectBundle.message("module.remove.confirmation.prompt", names, modules.length);
110   }
111
112   @Override
113   public String getActionTitle() {
114     return ProjectAttachProcessor.canAttachToProject() ? "Remove from Project View" : "Remove Module";
115   }
116
117   public static void removeModule(@NotNull final Module moduleToRemove,
118                                    @Nullable ModifiableRootModel modifiableRootModelToRemove,
119                                    @NotNull Collection<ModifiableRootModel> otherModuleRootModels,
120                                    @NotNull final ModifiableModuleModel moduleModel) {
121     // remove all dependencies on the module that is about to be removed
122     for (final ModifiableRootModel modifiableRootModel : otherModuleRootModels) {
123       final OrderEntry[] orderEntries = modifiableRootModel.getOrderEntries();
124       for (final OrderEntry orderEntry : orderEntries) {
125         if (orderEntry instanceof ModuleOrderEntry && orderEntry.isValid()) {
126           final Module orderEntryModule = ((ModuleOrderEntry)orderEntry).getModule();
127           if (orderEntryModule != null && orderEntryModule.equals(moduleToRemove)) {
128             modifiableRootModel.removeOrderEntry(orderEntry);
129           }
130         }
131       }
132     }
133     // destroyProcess editor
134     if (modifiableRootModelToRemove != null) {
135       modifiableRootModelToRemove.dispose();
136     }
137     // destroyProcess module
138     moduleModel.disposeModule(moduleToRemove);
139   }
140 }