Show Python packages in sdk settings tab (PY-21270) appcode/171.2213 clion/171.2208 dbe/171.2212 idea/171.2207 phpstorm/171.2211 pycharm/171.2205 pycharm/171.2210 rubymine/171.2209 webstorm/171.2214
authorDmitry Trofimov <dmitry.trofimov@jetbrains.com>
Tue, 22 Nov 2016 17:55:39 +0000 (18:55 +0100)
committerDmitry Trofimov <dmitry.trofimov@jetbrains.com>
Thu, 5 Jan 2017 20:10:24 +0000 (21:10 +0100)
java/idea-ui/src/com/intellij/openapi/SdkEditorAdditionalOptionsProvider.java [new file with mode: 0644]
java/idea-ui/src/com/intellij/openapi/projectRoots/ui/SdkEditor.java
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/JdkConfigurable.java
platform/lang-api/src/com/intellij/openapi/projectRoots/AdditionalDataConfigurable.java
platform/lang-impl/src/com/intellij/webcore/packaging/InstalledPackagesPanel.java
platform/platform-resources/src/META-INF/LangExtensionPoints.xml
python/pluginJava/META-INF/python-community-plugin-java.xml
python/pluginJava/com/jetbrains/python/PythonSdkEditorAdditionalOptionsProvider.java [new file with mode: 0644]
python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java

diff --git a/java/idea-ui/src/com/intellij/openapi/SdkEditorAdditionalOptionsProvider.java b/java/idea-ui/src/com/intellij/openapi/SdkEditorAdditionalOptionsProvider.java
new file mode 100644 (file)
index 0000000..be0b1ee
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.openapi;
+
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.AdditionalDataConfigurable;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.projectRoots.SdkType;
+import com.intellij.openapi.projectRoots.SdkTypeId;
+import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+/**
+ * @author traff
+ */
+public abstract class SdkEditorAdditionalOptionsProvider {
+  private static final ExtensionPointName<SdkEditorAdditionalOptionsProvider> EP_NAME = ExtensionPointName.create("com.intellij.sdkEditorAdditionalOptionsProvider");
+
+  private final SdkType myType;
+
+  protected SdkEditorAdditionalOptionsProvider(SdkType type) {
+    myType = type;
+  }
+
+  public static List<SdkEditorAdditionalOptionsProvider> getSdkOptionsFactory(SdkTypeId sdkType) {
+    return ContainerUtil.filter(EP_NAME.getExtensions(), (e) -> sdkType == e.myType);
+  }
+
+  @Nullable
+  public abstract AdditionalDataConfigurable createOptions(@NotNull Project project, @NotNull Sdk sdk);
+}
index 489450f00e90d994045cc113d580415e814efffd..d7dd3efc7cdf1a24a84ea68804d9b541d7a8c3fe 100644 (file)
  */
 package com.intellij.openapi.projectRoots.ui;
 
+import com.google.common.collect.Lists;
 import com.intellij.openapi.Disposable;
+import com.intellij.openapi.SdkEditorAdditionalOptionsProvider;
 import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.options.Configurable;
 import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.openapi.project.Project;
 import com.intellij.openapi.project.ProjectBundle;
 import com.intellij.openapi.projectRoots.*;
 import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl;
@@ -36,7 +39,7 @@ import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.ui.TabbedPaneWrapper;
 import com.intellij.ui.navigation.History;
 import com.intellij.ui.navigation.Place;
-import com.intellij.util.Consumer;
+import com.intellij.util.containers.ContainerUtil;
 import com.intellij.util.ui.JBUI;
 import com.intellij.util.ui.UIUtil;
 import org.jetbrains.annotations.NonNls;
@@ -50,10 +53,8 @@ import java.awt.*;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.io.File;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
+import java.util.List;
 
 /**
  * @author: MYakovlev
@@ -67,7 +68,7 @@ public class SdkEditor implements Configurable, Place.Navigator {
   private final Map<OrderRootType, SdkPathEditor> myPathEditors = new HashMap<>();
 
   private TextFieldWithBrowseButton myHomeComponent;
-  private final Map<SdkType, AdditionalDataConfigurable> myAdditionalDataConfigurables = new HashMap<>();
+  private final Map<SdkType, List<AdditionalDataConfigurable>> myAdditionalDataConfigurables = new HashMap<>();
   private final Map<AdditionalDataConfigurable, JComponent> myAdditionalDataComponents = new HashMap<>();
   private JPanel myAdditionalDataPanel;
   private final SdkModificator myEditedSdkModificator = new EditedSdkModificator();
@@ -75,6 +76,7 @@ public class SdkEditor implements Configurable, Place.Navigator {
   // GUI components
   private JPanel myMainPanel;
   private TabbedPaneWrapper myTabbedPane;
+  private Project myProject;
   private final SdkModel mySdkModel;
   private JLabel myHomeFieldLabel;
   private String myVersionString;
@@ -85,7 +87,8 @@ public class SdkEditor implements Configurable, Place.Navigator {
 
   private final Disposable myDisposable = Disposer.newDisposable();
 
-  public SdkEditor(SdkModel sdkModel, History history, final ProjectJdkImpl sdk) {
+  public SdkEditor(Project project, SdkModel sdkModel, History history, final ProjectJdkImpl sdk) {
+    myProject = project;
     mySdkModel = sdkModel;
     myHistory = history;
     mySdk = sdk;
@@ -93,40 +96,40 @@ public class SdkEditor implements Configurable, Place.Navigator {
     initSdk(sdk);
   }
 
-  private void initSdk(Sdk sdk){
+  private void initSdk(Sdk sdk) {
     mySdk = sdk;
     if (mySdk != null) {
       myInitialName = mySdk.getName();
       myInitialPath = mySdk.getHomePath();
-    } else {
+    }
+    else {
       myInitialName = "";
       myInitialPath = "";
     }
-    final AdditionalDataConfigurable additionalDataConfigurable = getAdditionalDataConfigurable();
-    if (additionalDataConfigurable != null) {
+    for (final AdditionalDataConfigurable additionalDataConfigurable : getAdditionalDataConfigurable()) {
       additionalDataConfigurable.setSdk(sdk);
     }
-    if (myMainPanel != null){
+    if (myMainPanel != null) {
       reset();
     }
   }
 
   @Override
-  public String getDisplayName(){
+  public String getDisplayName() {
     return ProjectBundle.message("sdk.configure.editor.title");
   }
 
   @Override
-  public String getHelpTopic(){
+  public String getHelpTopic() {
     return null;
   }
 
   @Override
-  public JComponent createComponent(){
+  public JComponent createComponent() {
     return myMainPanel;
   }
 
-  private void createMainPanel(){
+  private void createMainPanel() {
     myMainPanel = new JPanel(new GridBagLayout());
 
     myTabbedPane = new TabbedPaneWrapper(myDisposable);
@@ -154,17 +157,22 @@ public class SdkEditor implements Configurable, Place.Navigator {
     myHomeFieldLabel = new JLabel(getHomeFieldLabelValue());
     final int leftInset = 10;
     final int rightInset = 10;
-    myMainPanel.add(myHomeFieldLabel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE,
-                                                             JBUI.insets(2, leftInset, 2, 2), 0, 0));
-    myMainPanel.add(myHomeComponent, new GridBagConstraints(1, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
+    myMainPanel.add(myHomeFieldLabel,
+                    new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE,
+                                           JBUI.insets(2, leftInset, 2, 2), 0, 0));
+    myMainPanel.add(myHomeComponent, new GridBagConstraints(1, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER,
+                                                            GridBagConstraints.HORIZONTAL,
                                                             JBUI.insets(2, 2, 2, rightInset), 0, 0));
 
     myAdditionalDataPanel = new JPanel(new BorderLayout());
-    myMainPanel.add(myAdditionalDataPanel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
+    myMainPanel.add(myAdditionalDataPanel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER,
+                                                                  GridBagConstraints.BOTH,
                                                                   JBUI.insets(2, leftInset, 0, rightInset), 0, 0));
 
-    myMainPanel.add(myTabbedPane.getComponent(), new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
-                                                                        JBUI.insetsTop(2), 0, 0));
+    myMainPanel.add(myTabbedPane.getComponent(),
+                    new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1.0, 1.0, GridBagConstraints.CENTER,
+                                           GridBagConstraints.BOTH,
+                                           JBUI.insetsTop(2), 0, 0));
   }
 
   protected TextFieldWithBrowseButton createHomeComponent() {
@@ -177,38 +185,38 @@ public class SdkEditor implements Configurable, Place.Navigator {
   }
 
   protected boolean showTabForType(@NotNull OrderRootType type) {
-    return ((SdkType) mySdk.getSdkType()).isRootTypeApplicable(type);
+    return ((SdkType)mySdk.getSdkType()).isRootTypeApplicable(type);
   }
 
   private String getHomeFieldLabelValue() {
     if (mySdk != null) {
-      return ((SdkType) mySdk.getSdkType()).getHomeFieldLabel();
+      return ((SdkType)mySdk.getSdkType()).getHomeFieldLabel();
     }
     return ProjectBundle.message("sdk.configure.general.home.path");
   }
 
   @Override
-  public boolean isModified(){
-    boolean isModified = !Comparing.equal(mySdk == null? null : mySdk.getName(), myInitialName);
-    isModified = isModified || !Comparing.equal(FileUtil.toSystemIndependentName(getHomeValue()), FileUtil.toSystemIndependentName(myInitialPath));
+  public boolean isModified() {
+    boolean isModified = !Comparing.equal(mySdk == null ? null : mySdk.getName(), myInitialName);
+    isModified =
+      isModified || !Comparing.equal(FileUtil.toSystemIndependentName(getHomeValue()), FileUtil.toSystemIndependentName(myInitialPath));
     for (PathEditor pathEditor : myPathEditors.values()) {
       isModified = isModified || pathEditor.isModified();
     }
-    final AdditionalDataConfigurable configurable = getAdditionalDataConfigurable();
-    if (configurable != null) {
+    for (final AdditionalDataConfigurable configurable : getAdditionalDataConfigurable()) {
       isModified = isModified || configurable.isModified();
     }
     return isModified;
   }
 
   @Override
-  public void apply() throws ConfigurationException{
-    if(!Comparing.equal(myInitialName, mySdk == null ? "" : mySdk.getName())){
-      if(mySdk == null || mySdk.getName().isEmpty()){
+  public void apply() throws ConfigurationException {
+    if (!Comparing.equal(myInitialName, mySdk == null ? "" : mySdk.getName())) {
+      if (mySdk == null || mySdk.getName().isEmpty()) {
         throw new ConfigurationException(ProjectBundle.message("sdk.list.name.required.error"));
       }
     }
-    if (mySdk != null){
+    if (mySdk != null) {
       myInitialName = mySdk.getName();
       myInitialPath = mySdk.getHomePath();
       final SdkModificator sdkModificator = mySdk.getSdkModificator();
@@ -217,22 +225,23 @@ public class SdkEditor implements Configurable, Place.Navigator {
         pathEditor.apply(sdkModificator);
       }
       ApplicationManager.getApplication().runWriteAction(() -> sdkModificator.commitChanges());
-      final AdditionalDataConfigurable configurable = getAdditionalDataConfigurable();
-      if (configurable != null) {
-        configurable.apply();
+      for (final AdditionalDataConfigurable configurable : getAdditionalDataConfigurable()) {
+        if (configurable != null) {
+          configurable.apply();
+        }
       }
     }
   }
 
   @Override
-  public void reset(){
-    if (mySdk == null){
+  public void reset() {
+    if (mySdk == null) {
       setHomePathValue("");
       for (SdkPathEditor pathEditor : myPathEditors.values()) {
         pathEditor.reset(null);
       }
     }
-    else{
+    else {
       final SdkModificator sdkModificator = mySdk.getSdkModificator();
       for (OrderRootType type : myPathEditors.keySet()) {
         myPathEditors.get(type).reset(sdkModificator);
@@ -243,23 +252,24 @@ public class SdkEditor implements Configurable, Place.Navigator {
     myVersionString = null;
     myHomeFieldLabel.setText(getHomeFieldLabelValue());
     updateAdditionalDataComponent();
-    final AdditionalDataConfigurable configurable = getAdditionalDataConfigurable();
-    if (configurable != null) {
+
+    for (final AdditionalDataConfigurable configurable : getAdditionalDataConfigurable()) {
       configurable.reset();
     }
 
     myHomeComponent.setEnabled(mySdk != null);
 
-    for(int i = 0; i < myTabbedPane.getTabCount(); i++){
+    for (int i = 0; i < myTabbedPane.getTabCount(); i++) {
       myTabbedPane.setEnabledAt(i, mySdk != null);
     }
   }
 
   @Override
-  public void disposeUIResources(){
+  public void disposeUIResources() {
     for (final SdkType sdkType : myAdditionalDataConfigurables.keySet()) {
-      final AdditionalDataConfigurable configurable = myAdditionalDataConfigurables.get(sdkType);
-      configurable.disposeUIResources();
+      for (final AdditionalDataConfigurable configurable : myAdditionalDataConfigurables.get(sdkType)) {
+        configurable.disposeUIResources();
+      }
     }
     myAdditionalDataConfigurables.clear();
     myAdditionalDataComponents.clear();
@@ -271,8 +281,8 @@ public class SdkEditor implements Configurable, Place.Navigator {
     return myHomeComponent.getText().trim();
   }
 
-  private void clearAllPaths(){
-    for(PathEditor editor: myPathEditors.values()) {
+  private void clearAllPaths() {
+    for (PathEditor editor : myPathEditors.values()) {
       editor.clearList();
     }
   }
@@ -282,9 +292,9 @@ public class SdkEditor implements Configurable, Place.Navigator {
     final Color fg;
     if (absolutePath != null && !absolutePath.isEmpty()) {
       final File homeDir = new File(absolutePath);
-      boolean homeMustBeDirectory = mySdk == null || ((SdkType) mySdk.getSdkType()).getHomeChooserDescriptor().isChooseFolders();
+      boolean homeMustBeDirectory = mySdk == null || ((SdkType)mySdk.getSdkType()).getHomeChooserDescriptor().isChooseFolders();
       fg = homeDir.exists() && homeDir.isDirectory() == homeMustBeDirectory
-           ? UIUtil.getFieldForegroundColor() 
+           ? UIUtil.getFieldForegroundColor()
            : PathEditor.INVALID_COLOR;
     }
     else {
@@ -293,14 +303,13 @@ public class SdkEditor implements Configurable, Place.Navigator {
     myHomeComponent.getTextField().setForeground(fg);
   }
 
-  private void doSelectHomePath(){
+  private void doSelectHomePath() {
     final SdkType sdkType = (SdkType)mySdk.getSdkType();
     SdkConfigurationUtil.selectSdkHome(sdkType, path -> doSetHomePath(path, sdkType));
-
   }
 
   private void doSetHomePath(final String homePath, final SdkType sdkType) {
-    if (homePath == null){
+    if (homePath == null) {
       return;
     }
     setHomePathValue(homePath.replace('/', File.separatorChar));
@@ -321,7 +330,7 @@ public class SdkEditor implements Configurable, Place.Navigator {
       myVersionString = dummySdk.getVersionString();
       if (myVersionString == null) {
         Messages.showMessageDialog(ProjectBundle.message("sdk.java.corrupt.error", homePath),
-                                 ProjectBundle.message("sdk.java.corrupt.title"), Messages.getErrorIcon());
+                                   ProjectBundle.message("sdk.java.corrupt.title"), Messages.getErrorIcon());
       }
       sdkModificator = dummySdk.getSdkModificator();
       for (OrderRootType type : myPathEditors.keySet()) {
@@ -338,7 +347,7 @@ public class SdkEditor implements Configurable, Place.Navigator {
 
   private String suggestSdkName(final String homePath) {
     final String currentName = mySdk.getName();
-    final String suggestedName = ((SdkType) mySdk.getSdkType()).suggestSdkName(currentName , homePath);
+    final String suggestedName = ((SdkType)mySdk.getSdkType()).suggestSdkName(currentName, homePath);
     if (Comparing.equal(currentName, suggestedName)) return currentName;
     String newSdkName = suggestedName;
     final Set<String> allNames = new HashSet<>();
@@ -347,7 +356,7 @@ public class SdkEditor implements Configurable, Place.Navigator {
       allNames.add(sdk.getName());
     }
     int i = 0;
-    while(allNames.contains(newSdkName)){
+    while (allNames.contains(newSdkName)) {
       newSdkName = suggestedName + " (" + ++i + ")";
     }
     return newSdkName;
@@ -355,36 +364,54 @@ public class SdkEditor implements Configurable, Place.Navigator {
 
   private void updateAdditionalDataComponent() {
     myAdditionalDataPanel.removeAll();
-    final AdditionalDataConfigurable configurable = getAdditionalDataConfigurable();
-    if (configurable != null) {
+    for (AdditionalDataConfigurable configurable : getAdditionalDataConfigurable()) {
       JComponent component = myAdditionalDataComponents.get(configurable);
       if (component == null) {
         component = configurable.createComponent();
         myAdditionalDataComponents.put(configurable, component);
-      }      
-      myAdditionalDataPanel.add(component, BorderLayout.CENTER);
+      }
+      if (component != null) {
+        if (configurable.getTabName() != null) {
+          myTabbedPane.addTab(configurable.getTabName(), component);
+        }
+        else {
+          myAdditionalDataPanel.add(component, BorderLayout.CENTER);
+        }
+      }
     }
   }
 
-  @Nullable
-  private AdditionalDataConfigurable getAdditionalDataConfigurable() {
+  @NotNull
+  private List<AdditionalDataConfigurable> getAdditionalDataConfigurable() {
     if (mySdk == null) {
-      return null;
+      return ContainerUtil.emptyList();
     }
     return initAdditionalDataConfigurable(mySdk);
   }
 
-  @Nullable
-  private AdditionalDataConfigurable initAdditionalDataConfigurable(Sdk sdk) {
+  @NotNull
+  private List<AdditionalDataConfigurable> initAdditionalDataConfigurable(Sdk sdk) {
     final SdkType sdkType = (SdkType)sdk.getSdkType();
-    AdditionalDataConfigurable configurable = myAdditionalDataConfigurables.get(sdkType);
-    if (configurable == null) {
-      configurable = sdkType.createAdditionalDataConfigurable(mySdkModel, myEditedSdkModificator);
-      if (configurable != null) {
-        myAdditionalDataConfigurables.put(sdkType, configurable);
+    List<AdditionalDataConfigurable> configurables = myAdditionalDataConfigurables.get(sdkType);
+    if (configurables == null) {
+      configurables = Lists.newArrayList();
+      myAdditionalDataConfigurables.put(sdkType, configurables);
+
+
+      AdditionalDataConfigurable sdkConfigurable = sdkType.createAdditionalDataConfigurable(mySdkModel, myEditedSdkModificator);
+      if (sdkConfigurable != null) {
+        configurables.add(sdkConfigurable);
+      }
+
+      for (SdkEditorAdditionalOptionsProvider factory : SdkEditorAdditionalOptionsProvider.getSdkOptionsFactory(mySdk.getSdkType())) {
+        AdditionalDataConfigurable options = factory.createOptions(myProject, mySdk);
+        if (options != null) {
+          configurables.add(options);
+        }
       }
     }
-    return configurable;
+
+    return configurables;
   }
 
   private class EditedSdkModificator implements SdkModificator {
@@ -410,7 +437,7 @@ public class SdkEditor implements Configurable, Place.Navigator {
 
     @Override
     public String getVersionString() {
-      return myVersionString != null? myVersionString : mySdk.getVersionString();
+      return myVersionString != null ? myVersionString : mySdk.getVersionString();
     }
 
     @Override
@@ -454,7 +481,7 @@ public class SdkEditor implements Configurable, Place.Navigator {
 
     @Override
     public void removeAllRoots() {
-      for(PathEditor editor: myPathEditors.values()) {
+      for (PathEditor editor : myPathEditors.values()) {
         editor.clearList();
       }
     }
index 0729c124f1c7333cbe26d54f83dd67ab3341f805..c38e1d92a15037c1110e2b143bd6ce8796b0cf3a 100644 (file)
@@ -45,16 +45,16 @@ public class JdkConfigurable extends ProjectStructureElementConfigurable<Sdk> im
 
   public JdkConfigurable(final ProjectJdkImpl projectJdk,
                          final ProjectSdksModel sdksModel,
-                         final Runnable updateTree, @NotNull History history, Project project) {
+                         final Runnable updateTree, @NotNull History history, @NotNull Project project) {
     super(true, updateTree);
     myProjectJdk = projectJdk;
-    mySdkEditor = createSdkEditor(sdksModel, history, myProjectJdk);
+    mySdkEditor = createSdkEditor(project, sdksModel, history, myProjectJdk);
     final StructureConfigurableContext context = ModuleStructureConfigurable.getInstance(project).getContext();
     myProjectStructureElement = new SdkProjectStructureElement(context, myProjectJdk);
   }
 
-  protected SdkEditor createSdkEditor(ProjectSdksModel sdksModel, History history, ProjectJdkImpl projectJdk) {
-    return new SdkEditor(sdksModel, history, projectJdk);
+  protected SdkEditor createSdkEditor(@NotNull Project project, ProjectSdksModel sdksModel, History history, ProjectJdkImpl projectJdk) {
+    return new SdkEditor(project, sdksModel, history, projectJdk);
   }
 
   @Override
index 30f27849b4263aaef8a36e90c43eef94b9c75af4..3fb6e2701799b0c68cd37628d3ed16023b13fb21 100644 (file)
 package com.intellij.openapi.projectRoots;
 
 import com.intellij.openapi.options.UnnamedConfigurable;
+import org.jetbrains.annotations.Nullable;
 
 public interface AdditionalDataConfigurable extends UnnamedConfigurable {
   void setSdk(Sdk sdk);
+
+  /**
+   *  In case of non-null value the component returned by {@link #createComponent()} will be added as a tab to myTabbedPane in SdkEditor
+   */
+  @Nullable
+  default String getTabName() {
+    return null;
+  }
 }
index 77df3a1a4b1e26bd24ea63c02c61797b605dce95..de1d102c51cbef0b2810297a84d8b8372312b944 100644 (file)
@@ -60,7 +60,7 @@ public class InstalledPackagesPanel extends JPanel {
   private final Set<String> myCurrentlyInstalling = ContainerUtil.newHashSet();
   private final Set<InstalledPackage> myWaitingToUpgrade = ContainerUtil.newHashSet();
 
-  public InstalledPackagesPanel(Project project, PackagesNotificationPanel area) {
+  public InstalledPackagesPanel(@NotNull Project project, @NotNull PackagesNotificationPanel area) {
     super(new BorderLayout());
     myProject = project;
     myNotificationArea = area;
index d8b4be9f8ee7accfd055aef97dcdd5aa7e148d17..5fa964c3dc8504a00f3ef3e5c95bcc6fd1e4f55c 100644 (file)
                     interface="com.intellij.ide.projectView.ProjectViewNestingRulesProvider"/>
     <extensionPoint name="importTestOutput"
                     interface="com.intellij.execution.testframework.sm.runner.history.ImportTestOutputExtension"/>
+
+    <extensionPoint name="sdkEditorAdditionalOptionsProvider" interface="com.intellij.openapi.SdkEditorAdditionalOptionsProvider"/>
   </extensionPoints>
 </idea-plugin>
 
index 90f3df261b846d6bd074840eb0f69708ab546904..8e3e2911d2ea68fad96f3aef5d18ca3569dd421a 100644 (file)
@@ -11,6 +11,7 @@
     <completion.contributor language="Python" implementationClass="com.jetbrains.python.psi.impl.PyConstructorArgumentCompletionContributor"/>
     <!-- Console folding for Jython only, thus it's located in python-plugin only -->
     <stacktrace.fold substring="*sys-package-mgr*:"/>
+    <sdkEditorAdditionalOptionsProvider implementation="com.jetbrains.python.PythonSdkEditorAdditionalOptionsProvider"/>
   </extensions>
 
   <extensions defaultExtensionNs="Pythonid">
diff --git a/python/pluginJava/com/jetbrains/python/PythonSdkEditorAdditionalOptionsProvider.java b/python/pluginJava/com/jetbrains/python/PythonSdkEditorAdditionalOptionsProvider.java
new file mode 100644 (file)
index 0000000..f47355d
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python;
+
+import com.intellij.openapi.SdkEditorAdditionalOptionsProvider;
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.AdditionalDataConfigurable;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.webcore.packaging.PackagesNotificationPanel;
+import com.jetbrains.python.packaging.PyPackageManagers;
+import com.jetbrains.python.packaging.ui.PyInstalledPackagesPanel;
+import com.jetbrains.python.sdk.PythonSdkType;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * @author traff
+ */
+public class PythonSdkEditorAdditionalOptionsProvider extends SdkEditorAdditionalOptionsProvider {
+  protected PythonSdkEditorAdditionalOptionsProvider() {
+    super(PythonSdkType.getInstance());
+  }
+
+  @Nullable
+  @Override
+  public AdditionalDataConfigurable createOptions(@NotNull Project project, @NotNull Sdk sdk) {
+    return new PythonSdkOptionsAdditionalDataConfigurable(project);
+  }
+
+  private static class PythonSdkOptionsAdditionalDataConfigurable implements AdditionalDataConfigurable {
+    private final Project myProject;
+
+    private Sdk mySdk;
+
+    private PythonSdkOptionsAdditionalDataConfigurable(Project project) {
+      myProject = project;
+    }
+
+    @Override
+    public void setSdk(Sdk sdk) {
+      mySdk = sdk;
+    }
+
+    @Nullable
+    @Override
+    public JComponent createComponent() {
+      final PackagesNotificationPanel notificationsArea = new PackagesNotificationPanel();
+      final JComponent notificationsComponent = notificationsArea.getComponent();
+
+      JPanel panel = new JPanel(new BorderLayout());
+      panel.add(notificationsComponent, BorderLayout.SOUTH);
+      PyInstalledPackagesPanel packagesPanel = new PyInstalledPackagesPanel(myProject, notificationsArea);
+      panel.add(packagesPanel, BorderLayout.CENTER);
+
+      packagesPanel.updatePackages(PyPackageManagers.getInstance().getManagementService(myProject, mySdk));
+      packagesPanel.updateNotifications(mySdk);
+      return panel;
+    }
+
+    @Override
+    public String getTabName() {
+      return "Packages";
+    }
+
+    @Override
+    public boolean isModified() {
+      return false;
+    }
+
+    @Override
+    public void apply() throws ConfigurationException {
+    }
+
+    @Override
+    public void reset() {
+    }
+  }
+}
index f84a7eb24b519d21ac917556acd861cbb9c75e39..152b9b3b4e5a2e548973ff4ec272dad8558b85ba 100644 (file)
@@ -43,7 +43,7 @@ import java.util.Set;
 public class PyInstalledPackagesPanel extends InstalledPackagesPanel {
   private boolean myHasManagement = false;
 
-  public PyInstalledPackagesPanel(Project project, PackagesNotificationPanel area) {
+  public PyInstalledPackagesPanel(@NotNull Project project, @NotNull PackagesNotificationPanel area) {
     super(project, area);
   }