3943f55c770b69052025ab1714b5fe04b7585372
[idea/community.git] / java / idea-ui / src / com / intellij / openapi / roots / ui / configuration / ProjectJdksConfigurable.java
1 /*
2  * Copyright 2000-2015 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;
18
19 import com.intellij.ide.JavaUiBundle;
20 import com.intellij.openapi.actionSystem.AnAction;
21 import com.intellij.openapi.actionSystem.DefaultActionGroup;
22 import com.intellij.openapi.options.ConfigurationException;
23 import com.intellij.openapi.project.Project;
24 import com.intellij.openapi.projectRoots.JavaSdk;
25 import com.intellij.openapi.projectRoots.JavaSdkVersion;
26 import com.intellij.openapi.projectRoots.Sdk;
27 import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl;
28 import com.intellij.openapi.roots.ui.configuration.projectRoot.JdkConfigurable;
29 import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel;
30 import com.intellij.openapi.ui.MasterDetailsComponent;
31 import com.intellij.openapi.ui.MasterDetailsStateService;
32 import com.intellij.openapi.ui.NamedConfigurable;
33 import com.intellij.openapi.util.Conditions;
34 import com.intellij.openapi.util.Ref;
35 import com.intellij.ui.JBSplitter;
36 import com.intellij.ui.TreeSpeedSearch;
37 import com.intellij.util.IconUtil;
38 import org.jetbrains.annotations.NonNls;
39 import org.jetbrains.annotations.NotNull;
40 import org.jetbrains.annotations.Nullable;
41
42 import javax.swing.tree.DefaultMutableTreeNode;
43 import java.awt.*;
44 import java.util.*;
45
46 import static com.intellij.openapi.projectRoots.SimpleJavaSdkType.notSimpleJavaSdkType;
47
48 public class ProjectJdksConfigurable extends MasterDetailsComponent {
49   private final ProjectSdksModel myProjectJdksModel;
50   private final Project myProject;
51
52   public ProjectJdksConfigurable(@NotNull Project project) {
53     this(project, ProjectStructureConfigurable.getInstance(project).getProjectJdksModel());
54   }
55
56   public ProjectJdksConfigurable(@NotNull Project project, @NotNull ProjectSdksModel sdksModel) {
57     myProject = project;
58     myProjectJdksModel = sdksModel;
59     initTree();
60     myToReInitWholePanel = true;
61     reInitWholePanelIfNeeded();
62   }
63
64   @Override
65   protected String getComponentStateKey() {
66     return "ProjectJDKs.UI";
67   }
68
69   @Override
70   protected MasterDetailsStateService getStateService() {
71     return MasterDetailsStateService.getInstance(myProject);
72   }
73
74   @Override
75   protected void initTree() {
76     super.initTree();
77     new TreeSpeedSearch(myTree, treePath -> ((MyNode)treePath.getLastPathComponent()).getDisplayName(), true);
78
79     myTree.setRootVisible(false);
80   }
81
82   @Override
83   public void reset() {
84     super.reset();
85
86     myProjectJdksModel.reset(myProject);
87
88     myRoot.removeAllChildren();
89     final Map<Sdk, Sdk> sdks = myProjectJdksModel.getProjectSdks();
90     for (Sdk sdk : sdks.keySet()) {
91       if (!(sdk instanceof ProjectJdkImpl)) continue;
92
93       final JdkConfigurable configurable = new JdkConfigurable((ProjectJdkImpl)sdks.get(sdk), myProjectJdksModel, TREE_UPDATER, myHistory, myProject);
94       addNode(new MyNode(configurable), myRoot);
95     }
96     selectJdk(myProjectJdksModel.getProjectSdk()); //restore selection
97
98     JBSplitter splitter = extractSplitter();
99     if (splitter != null) {
100       splitter.setAndLoadSplitterProportionKey("project.jdk.splitter");
101     }
102   }
103
104   @Nullable
105   private JBSplitter extractSplitter() {
106     final Component[] components = myWholePanel.getComponents();
107     return components.length == 1 && components[0] instanceof JBSplitter ? (JBSplitter)components[0] : null;
108   }
109
110   @Override
111   public void apply() throws ConfigurationException {
112     final Ref<ConfigurationException> exceptionRef = Ref.create();
113     try {
114       super.apply();
115       boolean modifiedJdks = false;
116       for (int i = 0; i < myRoot.getChildCount(); i++) {
117         final NamedConfigurable configurable = ((MyNode)myRoot.getChildAt(i)).getConfigurable();
118         if (configurable.isModified()) {
119           configurable.apply();
120           modifiedJdks = true;
121         }
122       }
123
124       if (myProjectJdksModel.isModified() || modifiedJdks) {
125         myProjectJdksModel.apply(this);
126       }
127       myProjectJdksModel.setProjectSdk(getSelectedJdk());
128     }
129     catch (ConfigurationException e) {
130       exceptionRef.set(e);
131     }
132     if (!exceptionRef.isNull()) {
133       throw exceptionRef.get();
134     }
135   }
136
137
138   @Override
139   public boolean isModified() {
140     return super.isModified() || myProjectJdksModel.isModified();
141   }
142
143
144   @Override
145   public void disposeUIResources() {
146     myProjectJdksModel.disposeUIResources();
147     super.disposeUIResources();
148   }
149
150   @Override
151   @Nullable
152   protected ArrayList<AnAction> createActions(final boolean fromPopup) {
153     if (myProjectJdksModel == null) {
154       return null;
155     }
156     final ArrayList<AnAction> actions = new ArrayList<>();
157     DefaultActionGroup group = DefaultActionGroup.createPopupGroup(JavaUiBundle.messagePointer("add.new.jdk.text"));
158     group.getTemplatePresentation().setIcon(IconUtil.getAddIcon());
159     myProjectJdksModel.createAddActions(group, myTree, projectJdk -> {
160       addNode(new MyNode(new JdkConfigurable(((ProjectJdkImpl)projectJdk), myProjectJdksModel, TREE_UPDATER, myHistory, myProject), false), myRoot);
161       selectNodeInTree(findNodeByObject(myRoot, projectJdk));
162     }, notSimpleJavaSdkType());
163     actions.add(new MyActionGroupWrapper(group));
164     actions.add(new MyDeleteAction(Conditions.alwaysTrue()));
165     return actions;
166   }
167
168   @Override
169   protected void processRemovedItems() {
170     final Set<Sdk> jdks = new HashSet<>();
171     for(int i = 0; i < myRoot.getChildCount(); i++){
172       final DefaultMutableTreeNode node = (DefaultMutableTreeNode)myRoot.getChildAt(i);
173       final NamedConfigurable namedConfigurable = (NamedConfigurable)node.getUserObject();
174       jdks.add(((JdkConfigurable)namedConfigurable).getEditableObject());
175     }
176     final HashMap<Sdk, Sdk> sdks = new HashMap<>(myProjectJdksModel.getProjectSdks());
177     for (Sdk sdk : sdks.values()) {
178       if (!jdks.contains(sdk)) {
179         myProjectJdksModel.removeSdk(sdk);
180       }
181     }
182   }
183
184   @Override
185   protected boolean wasObjectStored(Object editableObject) {
186     return myProjectJdksModel.getProjectSdks().containsKey((Sdk)editableObject);
187   }
188
189   @Nullable
190   public Sdk getSelectedJdk() {
191     return (Sdk)getSelectedObject();
192   }
193
194   public void selectJdk(final Sdk projectJdk) {
195     selectNodeInTree(projectJdk);
196   }
197
198   @Override
199   @Nullable
200   public String getDisplayName() {
201     return null;
202   }
203
204   @Override
205   @Nullable
206   @NonNls
207   public String getHelpTopic() {
208     return null;
209   }
210
211   @Override
212   protected
213   @Nullable
214   String getEmptySelectionString() {
215     return "Select an SDK to view or edit its details here";
216   }
217
218   public void selectJdkVersion(JavaSdkVersion requiredJdkVersion) {
219     for (Sdk sdk : myProjectJdksModel.getSdks()) {
220       if (JavaSdk.getInstance().isOfVersionOrHigher(sdk, requiredJdkVersion)) {
221         selectJdk(sdk);
222         break;
223       }
224     }
225   }
226 }