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