a8ec86a132ac8770c9b351133b0e2b7c84b3ab08
[idea/community.git] / java / idea-ui / src / com / intellij / openapi / roots / ui / configuration / GeneralProjectSettingsElement.java
1 /*
2  * Copyright 2000-2011 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 package com.intellij.openapi.roots.ui.configuration;
17
18 import com.intellij.compiler.ModuleCompilerUtil;
19 import com.intellij.compiler.ModuleSourceSet;
20 import com.intellij.compiler.server.impl.BuildProcessCustomPluginsConfiguration;
21 import com.intellij.ide.JavaUiBundle;
22 import com.intellij.openapi.module.Module;
23 import com.intellij.openapi.module.ModuleManager;
24 import com.intellij.openapi.module.UnloadedModuleDescription;
25 import com.intellij.openapi.project.Project;
26 import com.intellij.openapi.projectRoots.Sdk;
27 import com.intellij.openapi.roots.ModuleRootModel;
28 import com.intellij.openapi.roots.libraries.Library;
29 import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel;
30 import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext;
31 import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.*;
32 import com.intellij.openapi.util.text.StringUtil;
33 import com.intellij.util.Chunk;
34 import com.intellij.util.containers.MultiMap;
35 import org.jetbrains.annotations.NonNls;
36 import org.jetbrains.annotations.NotNull;
37
38 import java.util.*;
39
40 public class GeneralProjectSettingsElement extends ProjectStructureElement {
41   public GeneralProjectSettingsElement(@NotNull StructureConfigurableContext context) {
42     super(context);
43   }
44
45   @NotNull
46   @Override
47   public String getPresentableText() {
48     return "Project";
49   }
50
51   @Override
52   public String getPresentableName() {
53     return ProjectStructureConfigurable.getInstance(myContext.getProject()).getProjectConfig().getProjectName();
54   }
55
56   @Override
57   public String getTypeName() {
58     return "Project";
59   }
60
61   @Override
62   public void check(ProjectStructureProblemsHolder problemsHolder) {
63     final Project project = myContext.getProject();
64     if (containsModuleWithInheritedSdk()) {
65       ProjectSdksModel model = ProjectStructureConfigurable.getInstance(project).getProjectJdksModel();
66       Sdk sdk = model.getProjectSdk();
67       if (sdk == null) {
68         PlaceInProjectStructureBase place = new PlaceInProjectStructureBase(project, ProjectStructureConfigurable.getInstance(project).createProjectConfigurablePlace(), this);
69         problemsHolder.registerProblem(JavaUiBundle.message("project.roots.project.jdk.problem.message"), null,
70                                        ProjectStructureProblemType.error("project-sdk-not-defined"), place,
71                                        null);
72       }
73     }
74
75
76     List<Chunk<ModuleSourceSet>> sourceSetCycles = ModuleCompilerUtil.computeSourceSetCycles(myContext.getModulesConfigurator());
77
78     List<String> cycles = new ArrayList<>();
79
80     for (Chunk<ModuleSourceSet> chunk : sourceSetCycles) {
81       final Set<ModuleSourceSet> sourceSets = chunk.getNodes();
82       List<String> names = new ArrayList<>();
83       for (ModuleSourceSet sourceSet : sourceSets) {
84         String name = sourceSet.getDisplayName();
85         names.add(names.isEmpty() ? name : StringUtil.decapitalize(name));
86       }
87       cycles.add(StringUtil.join(names, ", "));
88     }
89     if (!cycles.isEmpty()) {
90       final PlaceInProjectStructureBase place =
91         new PlaceInProjectStructureBase(project, ProjectStructureConfigurable.getInstance(project).createModulesPlace(), this);
92       final String message;
93       final String description;
94       if (cycles.size() > 1) {
95         message = "Circular dependencies";
96         @NonNls final String br = "<br>&nbsp;&nbsp;&nbsp;&nbsp;";
97         StringBuilder cyclesString = new StringBuilder();
98         for (int i = 0; i < cycles.size(); i++) {
99           cyclesString.append(br).append(i + 1).append(". ").append(cycles.get(i));
100         }
101         description = JavaUiBundle.message("module.circular.dependency.warning.description", cyclesString);
102       }
103       else {
104         message = JavaUiBundle.message("module.circular.dependency.warning.short", StringUtil.decapitalize(cycles.get(0)));
105         description = null;
106       }
107       problemsHolder.registerProblem(new ProjectStructureProblemDescription(message, description, place,
108                                                                             ProjectStructureProblemType
109                                                                               .warning("module-circular-dependency"),
110                                                                             Collections.emptyList()));
111     }
112   }
113
114   private boolean containsModuleWithInheritedSdk() {
115     for (Module module : myContext.getModules()) {
116       ModuleRootModel rootModel = myContext.getModulesConfigurator().getRootModel(module);
117       if (rootModel.isSdkInherited()) {
118         return true;
119       }
120     }
121     return false;
122   }
123
124   @Override
125   public List<ProjectStructureElementUsage> getUsagesInElement() {
126     List<ProjectStructureElementUsage> usages = new ArrayList<>();
127
128     Collection<UnloadedModuleDescription> unloadedModules = ModuleManager.getInstance(myContext.getProject()).getUnloadedModuleDescriptions();
129     if (!unloadedModules.isEmpty()) {
130       MultiMap<Module, UnloadedModuleDescription> dependenciesInUnloadedModules = new MultiMap<>();
131       for (UnloadedModuleDescription unloaded : unloadedModules) {
132         for (String moduleName : unloaded.getDependencyModuleNames()) {
133           Module depModule = myContext.getModulesConfigurator().getModuleModel().findModuleByName(moduleName);
134           if (depModule != null) {
135             dependenciesInUnloadedModules.putValue(depModule, unloaded);
136           }
137         }
138       }
139
140       for (Map.Entry<Module, Collection<UnloadedModuleDescription>> entry : dependenciesInUnloadedModules.entrySet()) {
141         usages.add(new UsagesInUnloadedModules(myContext, this, new ModuleProjectStructureElement(myContext, entry.getKey()),
142                                                entry.getValue()));
143       }
144
145       //currently we don't store dependencies on project libraries from unloaded modules in the model, so suppose that all the project libraries are used
146       for (Library library : myContext.getProjectLibrariesProvider().getModifiableModel().getLibraries()) {
147         usages.add(new UsagesInUnloadedModules(myContext, this, new LibraryProjectStructureElement(myContext, library), unloadedModules));
148       }
149     }
150
151     for (String libraryName : BuildProcessCustomPluginsConfiguration.getInstance(myContext.getProject()).getProjectLibraries()) {
152       Library library = myContext.getProjectLibrariesProvider().getModifiableModel().getLibraryByName(libraryName);
153       if (library != null) {
154         usages.add(new UsageInProjectSettings(myContext, new LibraryProjectStructureElement(myContext, library), "Build process configuration"));
155       }
156     }
157
158     return usages;
159   }
160
161   @Override
162   public String getId() {
163     return "project:general";
164   }
165
166   @Override
167   public boolean equals(Object obj) {
168     return obj instanceof GeneralProjectSettingsElement;
169   }
170
171   @Override
172   public int hashCode() {
173     return 0;
174   }
175 }