From 7fd991d1a703b0d1d02c1f3b61288ba44d10329c Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Thu, 6 Feb 2014 19:16:11 +0400 Subject: [PATCH 01/39] fixed python community icon-robots.txt --- python/resources/icon-robots.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/resources/icon-robots.txt b/python/resources/icon-robots.txt index e1ca58536c30..e9cf8c7fee89 100644 --- a/python/resources/icon-robots.txt +++ b/python/resources/icon-robots.txt @@ -1,2 +1,3 @@ # Only has artwork and tips stuff -skip: * +skip: *.png +skip: tips From 057c5f332934dd0c16093cd71b8160d3dc688abe Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Thu, 6 Feb 2014 20:16:08 +0400 Subject: [PATCH 02/39] initial python project interpreters page --- .../packaging/InstalledPackagesPanel.java | 203 ++++++++---------- .../PyActiveSdkConfigurable.form | 40 ---- .../PyActiveSdkConfigurable.java | 111 ++++++++-- .../PyActiveSdkModuleConfigurable.java | 13 +- .../com/jetbrains/python/interpreterGear.png | Bin 0 -> 509 bytes .../jetbrains/python/interpreterGear@2x.png | Bin 0 -> 1019 bytes .../python/interpreterGear@2x_dark.png | Bin 0 -> 1090 bytes .../jetbrains/python/interpreterGear_dark.png | Bin 0 -> 537 bytes python/src/icons/PythonIcons.java | 1 + 9 files changed, 189 insertions(+), 179 deletions(-) delete mode 100644 python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.form create mode 100644 python/resources/icons/com/jetbrains/python/interpreterGear.png create mode 100644 python/resources/icons/com/jetbrains/python/interpreterGear@2x.png create mode 100644 python/resources/icons/com/jetbrains/python/interpreterGear@2x_dark.png create mode 100644 python/resources/icons/com/jetbrains/python/interpreterGear_dark.png diff --git a/platform/lang-impl/src/com/intellij/webcore/packaging/InstalledPackagesPanel.java b/platform/lang-impl/src/com/intellij/webcore/packaging/InstalledPackagesPanel.java index 5595212c4519..4aee4b7c2389 100644 --- a/platform/lang-impl/src/com/intellij/webcore/packaging/InstalledPackagesPanel.java +++ b/platform/lang-impl/src/com/intellij/webcore/packaging/InstalledPackagesPanel.java @@ -2,6 +2,7 @@ package com.intellij.webcore.packaging; import com.google.common.collect.Lists; import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; @@ -9,13 +10,13 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.ui.DoubleClickListener; -import com.intellij.ui.ScrollPaneFactory; +import com.intellij.ui.*; import com.intellij.ui.table.JBTable; import com.intellij.util.CatchingConsumer; import com.intellij.util.Consumer; +import com.intellij.util.IconUtil; import com.intellij.util.ObjectUtils; -import com.intellij.util.containers.*; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -26,20 +27,16 @@ import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableCellRenderer; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.io.IOException; import java.util.*; -import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; public class InstalledPackagesPanel extends JPanel { - protected final JButton myInstallButton; - private final JButton myUninstallButton; - private final JButton myUpgradeButton; + private final AnActionButton myUpgradeButton; + protected final AnActionButton myInstallButton; + private final AnActionButton myUninstallButton; protected final JBTable myPackagesTable; private DefaultTableModel myPackagesTableModel; @@ -51,19 +48,9 @@ public class InstalledPackagesPanel extends JPanel { private final Set myWaitingToUpgrade = ContainerUtil.newHashSet(); public InstalledPackagesPanel(Project project, PackagesNotificationPanel area) { - super(new GridBagLayout()); + super(new BorderLayout()); myProject = project; myNotificationArea = area; - myInstallButton = new JButton("Install"); - myUninstallButton = new JButton("Uninstall"); - myUpgradeButton = new JButton("Upgrade"); - myInstallButton.setMnemonic('I'); - myUninstallButton.setMnemonic('U'); - myUpgradeButton.setMnemonic('p'); - - myInstallButton.setEnabled(false); - myUninstallButton.setEnabled(false); - myUpgradeButton.setEnabled(false); myPackagesTableModel = new DefaultTableModel(new String[]{"Package", "Version", "Latest"}, 0) { @Override @@ -80,25 +67,37 @@ public class InstalledPackagesPanel extends JPanel { }; myPackagesTable.getTableHeader().setReorderingAllowed(false); - Insets anInsets = new Insets(2, 2, 2, 2); - JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(myPackagesTable, - ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, - ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); - scrollPane.setPreferredSize(new Dimension(500, 500)); - add(scrollPane, new GridBagConstraints(0, 0, 1, 3, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, - anInsets, 0, 0)); + myUpgradeButton = new AnActionButton("Upgrade", IconUtil.getMoveUpIcon()) { + @Override + public void actionPerformed(AnActionEvent e) { + upgradeAction(); + } + }; + final ToolbarDecorator decorator = ToolbarDecorator.createDecorator(myPackagesTable).disableUpDownActions() + .setAddAction(new AnActionButtonRunnable() { + @Override + public void run(AnActionButton button) { + if (myPackageManagementService != null) { + ManagePackagesDialog dialog = createManagePackagesDialog(); + dialog.show(); + } + } + }) + .setRemoveAction(new AnActionButtonRunnable() { + @Override + public void run(AnActionButton button) { + uninstallAction(); + } + }) + .addExtraAction(myUpgradeButton); - addUninstallAction(); - addUpgradeAction(); - - add(myInstallButton, - new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, - anInsets, 0, 0)); - add(myUninstallButton, - new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, - anInsets, 0, 0)); - add(myUpgradeButton, - new GridBagConstraints(1, 2, 1, 1, 0.0, 1.0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, anInsets, 0, 0)); + decorator.setPreferredSize(new Dimension(500, 500)); + add(decorator.createPanel()); + myInstallButton = decorator.getActionsPanel().getAnActionButton(CommonActionsPanel.Buttons.ADD); + myUninstallButton = decorator.getActionsPanel().getAnActionButton(CommonActionsPanel.Buttons.REMOVE); + myInstallButton.setEnabled(false); + myUninstallButton.setEnabled(false); + myUpgradeButton.setEnabled(false); myPackagesTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { @Override @@ -107,16 +106,6 @@ public class InstalledPackagesPanel extends JPanel { } }); - myInstallButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - if (myPackageManagementService != null) { - ManagePackagesDialog dialog = createManagePackagesDialog(); - dialog.show(); - } - } - }); - new DoubleClickListener() { @Override protected boolean onDoubleClick(MouseEvent e) { @@ -162,38 +151,33 @@ public class InstalledPackagesPanel extends JPanel { myPathChangedListeners.add(consumer); } - private void addUpgradeAction() { - myUpgradeButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - final int[] rows = myPackagesTable.getSelectedRows(); - if (myPackageManagementService != null) { - final Set upgradedPackages = new HashSet(); - final Set packagesShouldBePostponed = getPackagesToPostpone(); - for (int row : rows) { - final Object packageObj = myPackagesTableModel.getValueAt(row, 0); - if (packageObj instanceof InstalledPackage) { - InstalledPackage pkg = (InstalledPackage)packageObj; - final String packageName = pkg.getName(); - final String currentVersion = pkg.getVersion(); - final String availableVersion = (String)myPackagesTableModel.getValueAt(row, 2); + private void upgradeAction() { + final int[] rows = myPackagesTable.getSelectedRows(); + if (myPackageManagementService != null) { + final Set upgradedPackages = new HashSet(); + final Set packagesShouldBePostponed = getPackagesToPostpone(); + for (int row : rows) { + final Object packageObj = myPackagesTableModel.getValueAt(row, 0); + if (packageObj instanceof InstalledPackage) { + InstalledPackage pkg = (InstalledPackage)packageObj; + final String packageName = pkg.getName(); + final String currentVersion = pkg.getVersion(); + final String availableVersion = (String)myPackagesTableModel.getValueAt(row, 2); - if (packagesShouldBePostponed.contains(packageName)) { - myWaitingToUpgrade.add((InstalledPackage)packageObj); - } - else if (PackageVersionComparator.VERSION_COMPARATOR.compare(currentVersion, availableVersion) < 0) { - upgradePackage(pkg, availableVersion); - upgradedPackages.add(packageName); - } - } + if (packagesShouldBePostponed.contains(packageName)) { + myWaitingToUpgrade.add((InstalledPackage)packageObj); } - - if (myCurrentlyInstalling.isEmpty() && upgradedPackages.isEmpty() && !myWaitingToUpgrade.isEmpty()) { - upgradePostponedPackages(); + else if (PackageVersionComparator.VERSION_COMPARATOR.compare(currentVersion, availableVersion) < 0) { + upgradePackage(pkg, availableVersion); + upgradedPackages.add(packageName); } } } - }); + + if (myCurrentlyInstalling.isEmpty() && upgradedPackages.isEmpty() && !myWaitingToUpgrade.isEmpty()) { + upgradePostponedPackages(); + } + } } private void upgradePostponedPackages() { @@ -322,43 +306,38 @@ public class InstalledPackagesPanel extends JPanel { return true; } - private void addUninstallAction() { - myUninstallButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(final ActionEvent e) { - final List packages = getSelectedPackages(); - final PackageManagementService selPackageManagementService = myPackageManagementService; - if (selPackageManagementService != null) { - PackageManagementService.Listener listener = new PackageManagementService.Listener() { - @Override - public void operationStarted(String packageName) { - myPackagesTable.setPaintBusy(true); - } - - @Override - public void operationFinished(String packageName, @Nullable String errorDescription) { - myPackagesTable.clearSelection(); - updatePackages(selPackageManagementService); - myPackagesTable.setPaintBusy(false); - if (errorDescription == null) { - if (packageName != null) { - myNotificationArea.showSuccess("Package '" + packageName + "' successfully uninstalled"); - } - else { - myNotificationArea.showSuccess("Packages successfully uninstalled"); - } - } - else { - myNotificationArea.showError("Uninstall packages failed. Details...", - "Uninstall Packages Failed", - "Uninstall packages failed.\n" + errorDescription); - } - } - }; - myPackageManagementService.uninstallPackages(packages, listener); + private void uninstallAction() { + final List packages = getSelectedPackages(); + final PackageManagementService selPackageManagementService = myPackageManagementService; + if (selPackageManagementService != null) { + PackageManagementService.Listener listener = new PackageManagementService.Listener() { + @Override + public void operationStarted(String packageName) { + myPackagesTable.setPaintBusy(true); } - } - }); + + @Override + public void operationFinished(String packageName, @Nullable String errorDescription) { + myPackagesTable.clearSelection(); + updatePackages(selPackageManagementService); + myPackagesTable.setPaintBusy(false); + if (errorDescription == null) { + if (packageName != null) { + myNotificationArea.showSuccess("Package '" + packageName + "' successfully uninstalled"); + } + else { + myNotificationArea.showSuccess("Packages successfully uninstalled"); + } + } + else { + myNotificationArea.showError("Uninstall packages failed. Details...", + "Uninstall Packages Failed", + "Uninstall packages failed.\n" + errorDescription); + } + } + }; + myPackageManagementService.uninstallPackages(packages, listener); + } } @NotNull diff --git a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.form b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.form deleted file mode 100644 index 79a648b213a2..000000000000 --- a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.form +++ /dev/null @@ -1,40 +0,0 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java index e4f22dd51e60..807c8af0edd6 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java @@ -32,52 +32,133 @@ import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.ModuleRootModificationUtil; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel; +import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.CollectionComboBoxModel; +import com.intellij.util.ui.UIUtil; +import com.intellij.webcore.packaging.PackagesNotificationPanel; +import com.jetbrains.python.packaging.ui.PyInstalledPackagesPanel; +import com.jetbrains.python.packaging.ui.PyPackageManagementService; import com.jetbrains.python.psi.LanguageLevel; import com.jetbrains.python.sdk.PySdkListCellRenderer; import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; +import icons.PythonIcons; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.util.List; -/** - * @author yole - */ public class PyActiveSdkConfigurable implements UnnamedConfigurable { private JPanel myPanel; private final Project myProject; @Nullable private final Module myModule; - private JComboBox mySdkCombo; - private JPanel myConfigureInterpretersPanel; - private PyConfigurableInterpreterList myInterpreterList; - private ProjectSdksModel myProjectSdksModel; private MyListener myListener; - public PyActiveSdkConfigurable(Project project) { + private PyConfigurableInterpreterList myInterpreterList; + private ProjectSdksModel myProjectSdksModel; + private ComboBox mySdkCombo; + private PyInstalledPackagesPanel myPackagesPanel; + + public PyActiveSdkConfigurable(@NotNull Project project) { myModule = null; myProject = project; - init(); + layoutPanel(); + initContent(); } public PyActiveSdkConfigurable(@NotNull Module module) { myModule = module; myProject = module.getProject(); - init(); + layoutPanel(); + initContent(); } - private void init() { - mySdkCombo.setRenderer(new SdkListCellRenderer("")); - + private void initContent() { myInterpreterList = PyConfigurableInterpreterList.getInstance(myProject); + myInterpreterList.setSdkCombo(mySdkCombo); + myProjectSdksModel = myInterpreterList.getModel(); myListener = new MyListener(this); myProjectSdksModel.addListener(myListener); - myConfigureInterpretersPanel.add(new PyConfigureInterpretersLinkPanel(myPanel), BorderLayout.CENTER); - myInterpreterList.setSdkCombo(mySdkCombo); + + mySdkCombo.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + final Sdk selectedSdk = (Sdk)mySdkCombo.getSelectedItem(); + myPackagesPanel.updatePackages(selectedSdk == null ? null : new PyPackageManagementService(myProject, selectedSdk)); + } + }); + + } + + private void layoutPanel() { + final GridBagLayout layout = new GridBagLayout(); + myPanel = new JPanel(layout); + final JLabel label = new JLabel("Project Interpreter:"); + final JLabel label1 = new JLabel(" "); + mySdkCombo = new ComboBox(); + mySdkCombo.setRenderer(new SdkListCellRenderer("")); + + PackagesNotificationPanel notificationsArea = new PackagesNotificationPanel(myProject); + final JComponent notificationsComponent = notificationsArea.getComponent(); + notificationsComponent.setPreferredSize(new Dimension(500, 29)); + + JButton detailsButton = new JButton(); + detailsButton.setIcon(PythonIcons.Python.InterpreterGear); + detailsButton.setIconTextGap(0); + detailsButton.setPreferredSize(new Dimension(29, 29)); + if (((UIUtil.isUnderAquaLookAndFeel())) || UIUtil.isUnderIntelliJLaF() || UIUtil.isUnderDarcula()) { + detailsButton.putClientProperty("JButton.buttonType", "square"); + } + + myPackagesPanel = new PyInstalledPackagesPanel(myProject, notificationsArea); + mySdkCombo.setPreferredSize(new Dimension(250, 29)); + final GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.HORIZONTAL; + c.insets = new Insets(2,2,2,2); + + c.gridx = 0; + c.gridy = 0; + myPanel.add(label, c); + + c.gridx = 1; + c.gridy = 0; + c.weightx = 0.1; + myPanel.add(mySdkCombo, c); + + c.insets = new Insets(0,5,0,2); + c.gridx = 2; + c.gridy = 0; + c.weightx = 0.0; + myPanel.add(detailsButton, c); + + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 1; + c.gridwidth = 3; + myPanel.add(label1, c); + + c.gridx = 0; + c.gridy = 2; + c.weighty = 0.5; + c.gridwidth = 3; + c.gridheight = GridBagConstraints.RELATIVE; + c.fill = GridBagConstraints.BOTH; + myPanel.add(myPackagesPanel, c); + + c.gridheight = GridBagConstraints.REMAINDER; + c.gridx = 0; + c.gridy = 3; + c.gridwidth = 3; + + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.SOUTH; + + myPanel.add(notificationsComponent, c); } @Override diff --git a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkModuleConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkModuleConfigurable.java index c3c299ef93d6..304424fd8f64 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkModuleConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkModuleConfigurable.java @@ -18,7 +18,6 @@ package com.jetbrains.python.configuration; import com.intellij.application.options.ModuleAwareProjectConfigurable; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; -import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.UnnamedConfigurable; import com.intellij.openapi.project.Project; @@ -28,17 +27,12 @@ import com.jetbrains.python.sdk.PythonSdkUpdater; import com.jetbrains.python.testing.VFSTestFrameworkListener; import org.jetbrains.annotations.NotNull; -/** - * @author yole - */ -public class PyActiveSdkModuleConfigurable extends ModuleAwareProjectConfigurable implements Configurable.Composite { +public class PyActiveSdkModuleConfigurable extends ModuleAwareProjectConfigurable { private final Project myProject; - private final Configurable mySdkConfigurable; public PyActiveSdkModuleConfigurable(Project project) { super(project, "Project Interpreter", "reference.settings.project.interpreter"); myProject = project; - mySdkConfigurable = new PythonSdkConfigurable(project); } @NotNull @@ -67,9 +61,4 @@ public class PyActiveSdkModuleConfigurable extends ModuleAwareProjectConfigurabl } PythonSdkUpdater.getInstance().updateActiveSdks(myProject, 0); } - - @Override - public Configurable[] getConfigurables() { - return new Configurable[] { mySdkConfigurable }; - } } diff --git a/python/resources/icons/com/jetbrains/python/interpreterGear.png b/python/resources/icons/com/jetbrains/python/interpreterGear.png new file mode 100644 index 0000000000000000000000000000000000000000..448474acb643cba62f0077c5fdb9c00e3528a9fb GIT binary patch literal 509 zcmV;H4GWnthxXI0g6dP zK~y-)t&=@Z8$l3;pJ7jO$49Ctg`uDb60XQUNR*_e!F!SgC7%NEBXAcH#c^%P(q2cM z6#N5{hLaLdir7U&g9H^6=Npw%BsQDP zB@q$eBk%^ufnOrhvny->i`MW|ME3JM&ug{XMP%cjmk0y60(v2Ywvh+03%mect7%EL2w|t# z<4T)Xfi){G2%a{tG-@;&*J+ymsOSKg2j=W4&wvHsonc>r-=>deK>Z&bIOjeApMiFg zB%2~~P!idJ<&J<(6h)o?|Cz?vB`{<0-K3%iL$i_wYe3#a00000NkvXXu0mjf1+>vc literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/python/interpreterGear@2x.png b/python/resources/icons/com/jetbrains/python/interpreterGear@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..fe190f2412aa677728acd2bdee5f4bf1f43ab29f GIT binary patch literal 1019 zcmV;HV8GAJ753+1BgjP zK~z}7<(JQETvZguKj+Peku;0MAD{~tPOS-JCW|Ki0a65Q!ocI)Ip=)u zJ>PTBIq-j9@-#}m@0V5eHgIf3{US0IhT+ze+R8sA@MjXo8L}r@URtoYxF`Vg^Yeqg z?_V;;6f^Wrx{(=UipH2rK@bcAEG#TYM*wSUYif)ch~s!hRj&cdK@beP|54SK(t2r` z)ma9vHJidKLX!$BH>TK55RcphAy|cJ@?;l#v*0EmbHg&v&#wImFQ?Y11) z+1W`_r3ehCv&|a&1GozuSott82@Ivk2{0leMc|%e`*HFZW2WqDb^^Qzyq%G101ts% zz$Z}@J+Qj310Mocfaf!GwtzdpVdA5&uWx%}V z(zdeEpWKYgfp@wj;Uw^pF(!+IlPyB<7ztJNQQL;Z_x(jxUF|^{A|gv+7_N2o5RH$I zC(8FTNR{jj0n@hJF5B;+7Npy^wp`n-0qpMXs;%#83&>el18BOoJJy0A2;NZD_knkN z0N?^ZsZ{#DUavpw2*CIKqN=U{@AWX-E&?x%jg9Ts>-EF7AyCyBe*v!gV_h*jq-p>F002ovPDHLkV1lG$)&Bqh literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/python/interpreterGear@2x_dark.png b/python/resources/icons/com/jetbrains/python/interpreterGear@2x_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..2d77aac65fa5ef796f7f7d7fbdbd275ab4d654da GIT binary patch literal 1090 zcmV-I1ikx-P);GBA1gM*08%1J6lB zK~z}7<(ExpTvZguf9K6OL1KkeEV!@>Q*pw$6x|1sjWH4OdPkC7KDI7IT!m8FT`7X= ze5^vuyi6cX+JXt~zOEZHP-kNWp+zf{Ks&>{zneSd_VJpJCJ5r)y!YS z{NIPYj!=>$qreSG`v7Lv3yeAEHjk^T_?nKt;h()Zb0>3PXJ^NThK97UvC-FVw?C8g z&^fpJQrOJelE}{GM5-d`{bI3rZ+v|G$@ccP4G#~$Bp79dhK7ceB*~d}yM0m86-jgT zdc7R(k#sI}KoXM9g?sAtdRfvOaHZ4fTwGsYe=BP|7X!=7%V$faQY`6fpyE$AZ)OW= znwptaB#i;18PQEMyCG>eiXusxku>YqcB3fzq19^DCnqPL9GHSqsr0EAtN;Scf4^sD z{gMW{2M-P)U{unmne9nxN*W2)Dw1YPrP6P}PX{_+W)Fd1C4CY`C{UOey>Q z1b#mf4U;4(1K$K8JQ>%`=7H~>bB*j;lqcYvYe-rEZk>YtTfjn|@mvR{r>6}diXsF0 z&Fmy62l${H>8|brF|fF}D4)v;P|onZ3%tL8yJpt#d&|Hea5e;|mmTnczSq^Ai-B6L zHs)`$Ht;U+MGn<4vp<1#N!P2@>H{zPp_zRPj7xeaCm5T+mYF@4R0LYRy}h?bMn*be z1U7O6l>^kflCD*&)n<31TCF~))oRzwtPi-DqhmC4m=t&$*bgzVf5c+d2#p6$G=at; zI=U(NyZas;7g*UEaMBSv(EExMWHC@)U0vAut$4 z(Ra04Ef0i)uSmfrumwCev!bN7nLRtOAxV;C+FwSmO~W8+GtRliBV9yOQ&Z-J?gNd? zMb!N`3&fJdYy;!d~I#5;zRq@DL25Yg+k$K9LK*L7y(J=feSu=3i5f=%=TVEuW;X< zncd7;yO5^o`9q7*^XJd+_4M>C0B`2CWWdM3n5SuA*S3HgX`0?I6bb_V@co1VyJj}u zYPEhoQbV$`vT~+aEKW$80h)zE;c^_ujew#vlIAm1n|01DgiUFu)42@vM^Q8{=||_> z(?dac=gu9Qn3#BKW(jb~%&vyUy|G6jJ^lNma8De^4Kuq6Tq+ieYtFf+J3BjeT7O34 zK)p**??CLFTR%xHIL>GX6?8u{_pkh#-3HDC2shx_fAa76A7Y}#z!78H2mk;807*qo IM6N<$f}IfmU;qFB literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/python/interpreterGear_dark.png b/python/resources/icons/com/jetbrains/python/interpreterGear_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..44e79af9551d60793d53097c6268ad0a93309e41 GIT binary patch literal 537 zcmV+!0_OdRP);GduS&t}_4t0j5br zK~y-)wUe=H(?Jx+Kkt%|jOrv6+M*5>>ty>E2-+hXq9|UA$V=d-_x@>& zaiy%q7!SPn=fGp&Mo|<12XhTX-8QOV+6RH^9lGWB1akZIdDG%-Wv=C52w><>U27%)jXsxKxGE~2XJJq z-Os}V*j3df;7N>eY>bIO)m&ExRe+SzBY;Y!@=jH^fZM=!2to4`wsQ^IkeWkT42F@-vTx-sq{|vS)k1jLTf>ZzzT3PQ+Wcc0?%^oBk&E_ zP}N(&^1=;jwc2~&1F-L$+cC!MW!^Ey>^bLlMC7fAbQ_IE_n)7s-|w%bl*XCn^>({` b#{aNCAA6e#+2_Nz00000NkvXXu0mjfp;Yg& literal 0 HcmV?d00001 diff --git a/python/src/icons/PythonIcons.java b/python/src/icons/PythonIcons.java index c942e0ca02c6..2d29827aa526 100644 --- a/python/src/icons/PythonIcons.java +++ b/python/src/icons/PythonIcons.java @@ -32,6 +32,7 @@ public class PythonIcons { } public static final Icon Dotnet = load("/icons/com/jetbrains/python/dotnet.png"); // 16x16 + public static final Icon InterpreterGear = load("/icons/com/jetbrains/python/interpreterGear.png"); // 16x16 public static final Icon Jython = load("/icons/com/jetbrains/python/jython.png"); // 16x16 public static class Nodes { From 3787e1efe2fafdcee634485cffb6bae1595d1c08 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Thu, 6 Feb 2014 20:26:17 +0400 Subject: [PATCH 03/39] added proper tooltip for install/uninstall buttons --- .../intellij/webcore/packaging/InstalledPackagesPanel.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/platform/lang-impl/src/com/intellij/webcore/packaging/InstalledPackagesPanel.java b/platform/lang-impl/src/com/intellij/webcore/packaging/InstalledPackagesPanel.java index 4aee4b7c2389..7954aac59b42 100644 --- a/platform/lang-impl/src/com/intellij/webcore/packaging/InstalledPackagesPanel.java +++ b/platform/lang-impl/src/com/intellij/webcore/packaging/InstalledPackagesPanel.java @@ -99,6 +99,10 @@ public class InstalledPackagesPanel extends JPanel { myUninstallButton.setEnabled(false); myUpgradeButton.setEnabled(false); + myInstallButton.getTemplatePresentation().setText("Install"); + myUninstallButton.getTemplatePresentation().setText("Uninstall"); + + myPackagesTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent event) { From 6820fe5453d2fc074aea6dd820f1240ba218b755 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Fri, 7 Feb 2014 18:59:46 +0400 Subject: [PATCH 04/39] added options for the details button --- .../impl/SdkConfigurationUtil.java | 27 +++++- .../PyActiveSdkConfigurable.java | 45 +++++++-- .../configuration/PythonSdkConfigurable.java | 2 +- ...erPathChooser.java => DetailsChooser.java} | 95 ++++++------------- .../jetbrains/python/sdk/PythonSdkType.java | 2 +- 5 files changed, 92 insertions(+), 79 deletions(-) rename python/src/com/jetbrains/python/sdk/{InterpreterPathChooser.java => DetailsChooser.java} (56%) diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/SdkConfigurationUtil.java b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/SdkConfigurationUtil.java index bd3be406ef00..a076101072fa 100644 --- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/SdkConfigurationUtil.java +++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/SdkConfigurationUtil.java @@ -54,7 +54,7 @@ public class SdkConfigurationUtil { public static void createSdk(@Nullable final Project project, final Sdk[] existingSdks, - final NullableConsumer onSdkCreatedCallBack, + final NullableConsumer onSdkCreatedCallBack, final boolean createIfExists, final SdkType... sdkTypes) { if (sdkTypes.length == 0) { onSdkCreatedCallBack.consume(null); @@ -72,8 +72,19 @@ public class SdkConfigurationUtil { @Override public void consume(List selectedFiles) { for (SdkType sdkType : sdkTypes) { - if (sdkType.isValidSdkHome(selectedFiles.get(0).getPath())) { - onSdkCreatedCallBack.consume(setupSdk(existingSdks, selectedFiles.get(0), sdkType, false, null, null)); + final String path = selectedFiles.get(0).getPath(); + if (sdkType.isValidSdkHome(path)) { + Sdk newSdk = null; + if (!createIfExists) { + for (Sdk sdk : existingSdks) { + if (path.equals(sdk.getHomePath())) { + newSdk = sdk; + } + } + } + if (newSdk == null) + newSdk = setupSdk(existingSdks, selectedFiles.get(0), sdkType, false, null, null); + onSdkCreatedCallBack.consume(newSdk); return; } } @@ -85,6 +96,14 @@ public class SdkConfigurationUtil { onSdkCreatedCallBack.consume(null); } }); + + } + + public static void createSdk(@Nullable final Project project, + final Sdk[] existingSdks, + final NullableConsumer onSdkCreatedCallBack, + final SdkType... sdkTypes) { + createSdk(project, existingSdks, onSdkCreatedCallBack, true, sdkTypes); } private static FileChooserDescriptor createCompositeDescriptor(final SdkType... sdkTypes) { @@ -140,7 +159,7 @@ public class SdkConfigurationUtil { final ProjectJdkImpl sdk; try { String sdkPath = sdkType.sdkPath(homeDir); - + final String sdkName = customSdkSuggestedName == null ? createUniqueSdkName(sdkType, sdkPath, sdksList) : createUniqueSdkName(customSdkSuggestedName, sdksList); diff --git a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java index 807c8af0edd6..917dec969476 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java @@ -35,11 +35,14 @@ import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel; import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.CollectionComboBoxModel; +import com.intellij.ui.awt.RelativePoint; +import com.intellij.util.NullableConsumer; import com.intellij.util.ui.UIUtil; import com.intellij.webcore.packaging.PackagesNotificationPanel; import com.jetbrains.python.packaging.ui.PyInstalledPackagesPanel; import com.jetbrains.python.packaging.ui.PyPackageManagementService; import com.jetbrains.python.psi.LanguageLevel; +import com.jetbrains.python.sdk.DetailsChooser; import com.jetbrains.python.sdk.PySdkListCellRenderer; import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; import icons.PythonIcons; @@ -62,6 +65,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { private ProjectSdksModel myProjectSdksModel; private ComboBox mySdkCombo; private PyInstalledPackagesPanel myPackagesPanel; + private JButton myDetailsButton; public PyActiveSdkConfigurable(@NotNull Project project) { myModule = null; @@ -89,10 +93,36 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { @Override public void actionPerformed(ActionEvent e) { final Sdk selectedSdk = (Sdk)mySdkCombo.getSelectedItem(); - myPackagesPanel.updatePackages(selectedSdk == null ? null : new PyPackageManagementService(myProject, selectedSdk)); + if (selectedSdk != null) + myPackagesPanel.updatePackages(new PyPackageManagementService(myProject, selectedSdk)); } }); + myDetailsButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + DetailsChooser.show(myProject, myProjectSdksModel.getSdks(), + RelativePoint.fromScreen(myDetailsButton.getLocationOnScreen()), true, + new NullableConsumer() { + @Override + public void consume(Sdk sdk) { + if (sdk == null) return; + final Sdk existedSdk = myProjectSdksModel.findSdk(sdk.getName()); + if (existedSdk == null) { + myProjectSdksModel.addSdk(sdk); + } + myInterpreterList.setSelectedSdk(sdk); + + mySdkCombo.getModel().setSelectedItem(sdk); + myPackagesPanel + .updatePackages(new PyPackageManagementService(myProject, sdk)); + } + } + ); + } + } + ); + } private void layoutPanel() { @@ -107,12 +137,12 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { final JComponent notificationsComponent = notificationsArea.getComponent(); notificationsComponent.setPreferredSize(new Dimension(500, 29)); - JButton detailsButton = new JButton(); - detailsButton.setIcon(PythonIcons.Python.InterpreterGear); - detailsButton.setIconTextGap(0); - detailsButton.setPreferredSize(new Dimension(29, 29)); + myDetailsButton = new JButton(); + myDetailsButton.setIcon(PythonIcons.Python.InterpreterGear); + myDetailsButton.setIconTextGap(0); + myDetailsButton.setPreferredSize(new Dimension(29, 29)); if (((UIUtil.isUnderAquaLookAndFeel())) || UIUtil.isUnderIntelliJLaF() || UIUtil.isUnderDarcula()) { - detailsButton.putClientProperty("JButton.buttonType", "square"); + myDetailsButton.putClientProperty("JButton.buttonType", "square"); } myPackagesPanel = new PyInstalledPackagesPanel(myProject, notificationsArea); @@ -134,7 +164,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { c.gridx = 2; c.gridy = 0; c.weightx = 0.0; - myPanel.add(detailsButton, c); + myPanel.add(myDetailsButton, c); c.insets = new Insets(2,2,2,2); c.gridx = 0; @@ -183,6 +213,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { @Override public void apply() throws ConfigurationException { + myProjectSdksModel.apply(); final Sdk selectedSdk = myProjectSdksModel.findSdk((Sdk)mySdkCombo.getSelectedItem()); if (myModule == null) { final ProjectRootManager rootManager = ProjectRootManager.getInstance(myProject); diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java index abdfd47e64e3..8f5233712aac 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java @@ -365,7 +365,7 @@ public class PythonSdkConfigurable implements Configurable, Configurable.NoScrol } private void addSdk(AnActionButton button) { - InterpreterPathChooser + DetailsChooser .show(myProject, myProjectSdksModel.getSdks(), button.getPreferredPopupPoint(), false, new NullableConsumer() { @Override public void consume(Sdk sdk) { diff --git a/python/src/com/jetbrains/python/sdk/InterpreterPathChooser.java b/python/src/com/jetbrains/python/sdk/DetailsChooser.java similarity index 56% rename from python/src/com/jetbrains/python/sdk/InterpreterPathChooser.java rename to python/src/com/jetbrains/python/sdk/DetailsChooser.java index ab57e352a5b1..46e4adaa8a3c 100644 --- a/python/src/com/jetbrains/python/sdk/InterpreterPathChooser.java +++ b/python/src/com/jetbrains/python/sdk/DetailsChooser.java @@ -23,100 +23,75 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil; import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.ui.popup.JBPopupFactory; -import com.intellij.openapi.ui.popup.ListPopup; -import com.intellij.openapi.ui.popup.ListPopupStep; -import com.intellij.openapi.ui.popup.PopupStep; +import com.intellij.openapi.ui.popup.*; import com.intellij.openapi.ui.popup.util.BaseListPopupStep; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.ui.awt.RelativePoint; import com.intellij.util.NullableConsumer; -import com.intellij.util.SystemProperties; import com.jetbrains.python.remote.PythonRemoteInterpreterManager; -import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import javax.swing.*; import java.awt.*; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.List; /** * @author yole */ -public class InterpreterPathChooser extends BaseListPopupStep { +public class DetailsChooser extends BaseListPopupStep { private final Project myProject; private final Component myOwnerComponent; private final Sdk[] myExistingSdks; private final NullableConsumer myCallback; - private static final String LOCAL = "Local..."; - private static final String REMOTE = "Remote..."; - private static final String VIRTUALENV = "Create VirtualEnv..."; + private static final String LOCAL = "Add Local"; + private static final String REMOTE = "Add Remote"; + private static final String VIRTUALENV = "Create VirtualEnv"; + private static final String MORE = "More..."; public static void show(final Project project, final Sdk[] existingSdks, final RelativePoint popupPoint, - final boolean showVirtualEnv, + final boolean showMore, final NullableConsumer callback) { - ListPopupStep sdkHomesStep = new InterpreterPathChooser(project, popupPoint.getComponent(), existingSdks, showVirtualEnv, callback); + final ListPopupStep sdkHomesStep = new DetailsChooser(project, popupPoint.getComponent(), existingSdks, showMore, callback); final ListPopup popup = JBPopupFactory.getInstance().createListPopup(sdkHomesStep); popup.show(popupPoint); } - public InterpreterPathChooser(Project project, - Component ownerComponent, - Sdk[] existingSdks, - boolean showVirtualEnv, - NullableConsumer callback) { - super("Select Interpreter Path", getSuggestedPythonSdkPaths(existingSdks, showVirtualEnv)); + public DetailsChooser(Project project, + Component ownerComponent, + Sdk[] existingSdks, + boolean showMore, + NullableConsumer callback) { + super(null, getAvailableOptions(showMore)); myProject = project; myOwnerComponent = ownerComponent; myExistingSdks = existingSdks; myCallback = callback; } - private static List getSuggestedPythonSdkPaths(Sdk[] existingSdks, boolean showVirtualEnv) { - List paths = new ArrayList(); - Collection sdkHomes = PythonSdkType.getInstance().suggestHomePaths(); - for (String sdkHome : SdkConfigurationUtil.filterExistingPaths(PythonSdkType.getInstance(), sdkHomes, existingSdks)) { - paths.add(FileUtil.getLocationRelativeToUserHome(sdkHome)); - } - paths.add(LOCAL); + private static List getAvailableOptions(boolean showMore) { + final List options = new ArrayList(); + options.add(LOCAL); if (PythonRemoteInterpreterManager.getInstance() != null) { - paths.add(REMOTE); + options.add(REMOTE); } - if (showVirtualEnv) { - paths.add(VIRTUALENV); + options.add(VIRTUALENV); + + if (showMore) { + options.add(MORE); } - return paths; + return options; } @Nullable @Override - public Icon getIconFor(String aValue) { - if (LOCAL.equals(aValue) || REMOTE.equals(aValue) || VIRTUALENV.equals(aValue)) return null; - String filePath = aValue; - if (StringUtil.startsWithChar(filePath, '~')) { - String home = SystemProperties.getUserHome(); - filePath = home + filePath.substring(1); - } - final PythonSdkFlavor flavor = PythonSdkFlavor.getPlatformIndependentFlavor(filePath); - return flavor != null ? flavor.getIcon() : PythonSdkType.getInstance().getIcon(); + public ListSeparator getSeparatorAbove(String value) { + return MORE.equals(value) ? new ListSeparator() : null; } - @NotNull - @Override - public String getTextFor(String value) { - return FileUtil.toSystemDependentName(value); - } - - private void sdkSelected(final String selectedValue) { + private void optionSelected(final String selectedValue) { if (LOCAL.equals(selectedValue)) { createLocalSdk(); } @@ -127,7 +102,7 @@ public class InterpreterPathChooser extends BaseListPopupStep { createVirtualEnvSdk(); } else { - createSdkFromPath(selectedValue); + //createSdkFromPath(selectedValue); } } @@ -135,7 +110,7 @@ public class InterpreterPathChooser extends BaseListPopupStep { ApplicationManager.getApplication().invokeLater(new Runnable() { @Override public void run() { - SdkConfigurationUtil.createSdk(myProject, myExistingSdks, myCallback, PythonSdkType.getInstance()); + SdkConfigurationUtil.createSdk(myProject, myExistingSdks, myCallback, false, PythonSdkType.getInstance()); } }, ModalityState.any()); } @@ -152,18 +127,6 @@ public class InterpreterPathChooser extends BaseListPopupStep { } } - private void createSdkFromPath(String selectedPath) { - String filePath = selectedPath; - if (StringUtil.startsWithChar(filePath, '~')) { - String home = SystemProperties.getUserHome(); - filePath = home + filePath.substring(1); - } - Sdk sdk = SdkConfigurationUtil.setupSdk(myExistingSdks, - LocalFileSystem.getInstance().findFileByPath(filePath), - PythonSdkType.getInstance(), false, null, null); - myCallback.consume(sdk); - } - private void createVirtualEnvSdk() { final CreateVirtualEnvDialog dialog; final List allSdks = Arrays.asList(myExistingSdks); @@ -193,7 +156,7 @@ public class InterpreterPathChooser extends BaseListPopupStep { public PopupStep onChosen(final String selectedValue, boolean finalChoice) { return doFinalStep(new Runnable() { public void run() { - sdkSelected(selectedValue); + optionSelected(selectedValue); } }); } diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkType.java b/python/src/com/jetbrains/python/sdk/PythonSdkType.java index cb5f855e309f..d0d910d3b4bb 100644 --- a/python/src/com/jetbrains/python/sdk/PythonSdkType.java +++ b/python/src/com/jetbrains/python/sdk/PythonSdkType.java @@ -277,7 +277,7 @@ public class PythonSdkType extends SdkType { public void showCustomCreateUI(SdkModel sdkModel, final JComponent parentComponent, final Consumer sdkCreatedCallback) { Project project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(parentComponent)); - InterpreterPathChooser.show(project, sdkModel.getSdks(), RelativePoint.getCenterOf(parentComponent), true, new NullableConsumer() { + DetailsChooser.show(project, sdkModel.getSdks(), RelativePoint.getCenterOf(parentComponent), true, new NullableConsumer() { @Override public void consume(@Nullable Sdk sdk) { if (sdk != null) { From 846cd8372decd18d9febf9453a619b824874abda Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Tue, 11 Feb 2014 12:50:34 +0400 Subject: [PATCH 05/39] second iteration for python project interpreters page Added More/Show All buttons filter out symlinks from suggested interpreters homepath Add detected sdk to project Sorting for interpreters combobox Added separators to interpreter combobox --- .../python/PyIdeCommonOptionsForm.java | 2 +- .../PyActiveSdkConfigurable.java | 87 ++++++++++++++++--- .../PyConfigurableInterpreterList.java | 60 +++++++++++-- .../configuration/PythonSdkConfigurable.java | 6 +- .../jetbrains/python/sdk/DetailsChooser.java | 11 ++- .../jetbrains/python/sdk/PyDetectedSdk.java | 11 +++ .../python/sdk/PySdkListCellRenderer.java | 21 +++-- .../jetbrains/python/sdk/PythonSdkType.java | 2 +- .../sdk/flavors/MacPythonSdkFlavor.java | 3 +- .../sdk/flavors/UnixPythonSdkFlavor.java | 6 +- .../sdk/flavors/VirtualEnvSdkFlavor.java | 2 +- 11 files changed, 177 insertions(+), 34 deletions(-) create mode 100644 python/src/com/jetbrains/python/sdk/PyDetectedSdk.java diff --git a/python/ide/src/com/jetbrains/python/PyIdeCommonOptionsForm.java b/python/ide/src/com/jetbrains/python/PyIdeCommonOptionsForm.java index 2636aa50c66f..8f633e359038 100644 --- a/python/ide/src/com/jetbrains/python/PyIdeCommonOptionsForm.java +++ b/python/ide/src/com/jetbrains/python/PyIdeCommonOptionsForm.java @@ -224,7 +224,7 @@ public class PyIdeCommonOptionsForm implements AbstractPyCommonOptionsForm { } public void updateSdkList(boolean preserveSelection, PyConfigurableInterpreterList myInterpreterList) { - myPythonSdks = myInterpreterList.getAllPythonSdks(); + myPythonSdks = myInterpreterList.getAllPythonSdks(myProject); Sdk selection = preserveSelection ? (Sdk)myInterpreterComboBox.getSelectedItem() : null; if (!myPythonSdks.contains(selection)) { selection = null; diff --git a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java index 917dec969476..de63179c64d5 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java @@ -16,6 +16,7 @@ package com.jetbrains.python.configuration; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorFactory; import com.intellij.openapi.editor.ex.EditorEx; @@ -27,12 +28,14 @@ import com.intellij.openapi.options.UnnamedConfigurable; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.SdkModel; +import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil; import com.intellij.openapi.projectRoots.impl.SdkListCellRenderer; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.ModuleRootModificationUtil; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel; import com.intellij.openapi.ui.ComboBox; +import com.intellij.openapi.ui.DialogBuilder; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.CollectionComboBoxModel; import com.intellij.ui.awt.RelativePoint; @@ -42,8 +45,7 @@ import com.intellij.webcore.packaging.PackagesNotificationPanel; import com.jetbrains.python.packaging.ui.PyInstalledPackagesPanel; import com.jetbrains.python.packaging.ui.PyPackageManagementService; import com.jetbrains.python.psi.LanguageLevel; -import com.jetbrains.python.sdk.DetailsChooser; -import com.jetbrains.python.sdk.PySdkListCellRenderer; +import com.jetbrains.python.sdk.*; import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; import icons.PythonIcons; import org.jetbrains.annotations.NotNull; @@ -53,6 +55,7 @@ import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.util.ArrayList; import java.util.List; public class PyActiveSdkConfigurable implements UnnamedConfigurable { @@ -66,6 +69,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { private ComboBox mySdkCombo; private PyInstalledPackagesPanel myPackagesPanel; private JButton myDetailsButton; + private static final String SHOW_ALL = "Show All"; public PyActiveSdkConfigurable(@NotNull Project project) { myModule = null; @@ -101,7 +105,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { myDetailsButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - DetailsChooser.show(myProject, myProjectSdksModel.getSdks(), + DetailsChooser.show(myProject, myProjectSdksModel.getSdks(), new PythonSdkConfigurable(myProject).createComponent(), RelativePoint.fromScreen(myDetailsButton.getLocationOnScreen()), true, new NullableConsumer() { @Override @@ -114,8 +118,8 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { myInterpreterList.setSelectedSdk(sdk); mySdkCombo.getModel().setSelectedItem(sdk); - myPackagesPanel - .updatePackages(new PyPackageManagementService(myProject, sdk)); + myPackagesPanel.updatePackages( + new PyPackageManagementService(myProject, sdk)); } } ); @@ -130,7 +134,22 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { myPanel = new JPanel(layout); final JLabel label = new JLabel("Project Interpreter:"); final JLabel label1 = new JLabel(" "); - mySdkCombo = new ComboBox(); + mySdkCombo = new ComboBox() { + @Override + public void setSelectedItem(Object item) + { + if (SHOW_ALL.equals(item)) { + DialogBuilder dialog = new DialogBuilder(myProject); + dialog.setTitle("Python Interpreters"); + dialog.setCenterPanel(new PythonSdkConfigurable(myProject).createComponent()); + dialog.show(); + return; + } + if (!PySdkListCellRenderer.SEPARATOR.equals(item.toString())) + super.setSelectedItem(item); + } + }; + mySdkCombo.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE); mySdkCombo.setRenderer(new SdkListCellRenderer("")); PackagesNotificationPanel notificationsArea = new PackagesNotificationPanel(myProject); @@ -199,7 +218,8 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { @Override public boolean isModified() { final Sdk sdk = getSdk(); - return sdk != myProjectSdksModel.findSdk((Sdk)mySdkCombo.getSelectedItem()); + final Sdk selectedItem = (Sdk)mySdkCombo.getSelectedItem(); + return selectedItem instanceof PyDetectedSdk || sdk != myProjectSdksModel.findSdk(selectedItem); } @Nullable @@ -213,8 +233,18 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { @Override public void apply() throws ConfigurationException { + final Sdk item = (Sdk)mySdkCombo.getSelectedItem(); + if (item instanceof PyDetectedSdk) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + final Sdk sdk = SdkConfigurationUtil.createAndAddSDK(item.getName(), PythonSdkType.getInstance()); + SdkConfigurationUtil.setDirectoryProjectSdk(myProject, sdk); + } + }, ModalityState.any()); + } myProjectSdksModel.apply(); - final Sdk selectedSdk = myProjectSdksModel.findSdk((Sdk)mySdkCombo.getSelectedItem()); + final Sdk selectedSdk = myProjectSdksModel.findSdk(item); if (myModule == null) { final ProjectRootManager rootManager = ProjectRootManager.getInstance(myProject); ApplicationManager.getApplication().runWriteAction(new Runnable() { @@ -280,7 +310,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { } private void updateSdkList(boolean preserveSelection) { - final List sdkList = myInterpreterList.getAllPythonSdks(); + final List sdkList = myInterpreterList.getAllPythonSdks(myProject); Sdk selection = preserveSelection ? (Sdk)mySdkCombo.getSelectedItem() : null; if (!sdkList.contains(selection)) { selection = null; @@ -290,9 +320,44 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { if (selection != null && !sdkList.contains(selection)) { sdkList.add(0, selection); } - sdkList.add(0, null); + List items = new ArrayList(); + items.add(null); + + boolean remoteSeparator = true; + boolean separator = true; + boolean detectedSeparator = true; + boolean hasAssociationsWithDifferentProject = false; + final String projectBasePath = myProject.getBasePath(); + for (Sdk sdk : sdkList) { + if (!PythonSdkType.isVirtualEnv(sdk) && !PythonSdkType.isRemote(sdk) && + !(sdk instanceof PyDetectedSdk) && separator) { + items.add(PySdkListCellRenderer.SEPARATOR); + separator = false; + } + if (PythonSdkType.isRemote(sdk) && remoteSeparator) { + items.add(PySdkListCellRenderer.SEPARATOR); + remoteSeparator = false; + } + if (sdk instanceof PyDetectedSdk && detectedSeparator) { + items.add(PySdkListCellRenderer.SEPARATOR); + detectedSeparator = false; + } + items.add(sdk); + + final PythonSdkAdditionalData data = (PythonSdkAdditionalData)sdk.getSdkAdditionalData(); + if (data != null) { + final String path = data.getAssociatedProjectPath(); + if (path != null && !path.equals(projectBasePath)) hasAssociationsWithDifferentProject = true; + } + } + + if (hasAssociationsWithDifferentProject) { + items.add(PySdkListCellRenderer.SEPARATOR); + items.add(SHOW_ALL); + } + mySdkCombo.setRenderer(new PySdkListCellRenderer()); - mySdkCombo.setModel(new CollectionComboBoxModel(sdkList, selection)); + mySdkCombo.setModel(new CollectionComboBoxModel(items, selection)); } @Override diff --git a/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java b/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java index fbe1d0dd8d35..f06d751d3596 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java @@ -18,15 +18,18 @@ package com.jetbrains.python.configuration; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil; import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel; import com.intellij.openapi.util.Comparing; +import com.jetbrains.python.psi.LanguageLevel; +import com.jetbrains.python.sdk.PyDetectedSdk; +import com.jetbrains.python.sdk.PySdkUtil; +import com.jetbrains.python.sdk.PythonSdkAdditionalData; import com.jetbrains.python.sdk.PythonSdkType; +import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; import javax.swing.*; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; +import java.util.*; /** * Manages the SDK model shared between PythonSdkConfigurable and PyActiveSdkConfigurable. @@ -65,19 +68,66 @@ public class PyConfigurableInterpreterList { } } - public List getAllPythonSdks() { + public List getAllPythonSdks(final Project project) { List result = new ArrayList(); for (Sdk sdk : getModel().getSdks()) { if (sdk.getSdkType() instanceof PythonSdkType) { result.add(sdk); } } + Collection sdkHomes = PythonSdkType.getInstance().suggestHomePaths(); + Collections.sort(result, new Comparator() { @Override public int compare(Sdk o1, Sdk o2) { + if (!(o1.getSdkType() instanceof PythonSdkType) || + !(o2.getSdkType() instanceof PythonSdkType)) + return -Comparing.compare(o1.getName(), o2.getName()); + + final boolean isVEnv1 = PythonSdkType.isVirtualEnv(o1); + final boolean isVEnv2 = PythonSdkType.isVirtualEnv(o2); + final boolean isRemote1 = PySdkUtil.isRemote(o1); + final boolean isRemote2 = PySdkUtil.isRemote(o2); + final PythonSdkFlavor flavor1 = PythonSdkFlavor.getFlavor(o1); + final PythonSdkFlavor flavor2 = PythonSdkFlavor.getFlavor(o2); + final LanguageLevel level1 = flavor1 != null ? flavor1.getLanguageLevel(o1) : LanguageLevel.getDefault(); + final LanguageLevel level2 = flavor2 != null ? flavor2.getLanguageLevel(o2) : LanguageLevel.getDefault(); + + if (isVEnv1) { + if (associatedWithCurrent(o1, project)) return -1; + if (isVEnv2) { + final int compare = Comparing.compare(level1, level2); + if (compare != 0) return -compare; + return Comparing.compare(o1.getName(), o2.getName()); + } + return -1; + } + if (isVEnv2) { + return 1; + } + if (isRemote1) return 1; + if (isRemote2) return -1; + + final int compare = Comparing.compare(level1, level2); + if (compare != 0) return -compare; return Comparing.compare(o1.getName(), o2.getName()); } }); + for (String sdkHome : SdkConfigurationUtil.filterExistingPaths(PythonSdkType.getInstance(), sdkHomes, getModel().getSdks())) { + result.add(new PyDetectedSdk(sdkHome, PythonSdkType.getInstance())); + } return result; } + + private static boolean associatedWithCurrent(Sdk o1, Project project) { + final PythonSdkAdditionalData data = (PythonSdkAdditionalData)o1.getSdkAdditionalData(); + if (data != null) { + final String path = data.getAssociatedProjectPath(); + final String projectBasePath = project.getBasePath(); + if (path != null && path.equals(projectBasePath)) { + return true; + } + } + return false; + } } diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java index 8f5233712aac..baf335dc10fa 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java @@ -247,7 +247,7 @@ public class PythonSdkConfigurable implements Configurable, Configurable.NoScrol addCreatedSdk(sdk, true); } }; - final List allSdks = PyConfigurableInterpreterList.getInstance(myProject).getAllPythonSdks(); + final List allSdks = PyConfigurableInterpreterList.getInstance(myProject).getAllPythonSdks(myProject); final CreateVirtualEnvDialog dialog = new CreateVirtualEnvDialog(myProject, myNewProject, allSdks, sdk); dialog.show(); if (dialog.isOK()) { @@ -335,7 +335,7 @@ public class PythonSdkConfigurable implements Configurable, Configurable.NoScrol } private void refreshSdkList() { - final List pythonSdks = myInterpreterList.getAllPythonSdks(); + final List pythonSdks = myInterpreterList.getAllPythonSdks(myProject); Sdk projectSdk = myProjectSdksModel.getProjectSdk(); if (!myShowOtherProjectVirtualenvs) { VirtualEnvProjectFilter.removeNotMatching(myProject, pythonSdks); @@ -366,7 +366,7 @@ public class PythonSdkConfigurable implements Configurable, Configurable.NoScrol private void addSdk(AnActionButton button) { DetailsChooser - .show(myProject, myProjectSdksModel.getSdks(), button.getPreferredPopupPoint(), false, new NullableConsumer() { + .show(myProject, myProjectSdksModel.getSdks(), new PythonSdkConfigurable(myProject).createComponent(), button.getPreferredPopupPoint(), false, new NullableConsumer() { @Override public void consume(Sdk sdk) { myMakeActiveAdded = false; diff --git a/python/src/com/jetbrains/python/sdk/DetailsChooser.java b/python/src/com/jetbrains/python/sdk/DetailsChooser.java index 46e4adaa8a3c..10dd82f7360f 100644 --- a/python/src/com/jetbrains/python/sdk/DetailsChooser.java +++ b/python/src/com/jetbrains/python/sdk/DetailsChooser.java @@ -22,6 +22,7 @@ import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil; +import com.intellij.openapi.ui.DialogBuilder; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.popup.*; import com.intellij.openapi.ui.popup.util.BaseListPopupStep; @@ -30,6 +31,7 @@ import com.intellij.util.NullableConsumer; import com.jetbrains.python.remote.PythonRemoteInterpreterManager; import org.jetbrains.annotations.Nullable; +import javax.swing.*; import java.awt.*; import java.util.ArrayList; import java.util.Arrays; @@ -39,6 +41,7 @@ import java.util.List; * @author yole */ public class DetailsChooser extends BaseListPopupStep { + private static JComponent myMore; private final Project myProject; private final Component myOwnerComponent; private final Sdk[] myExistingSdks; @@ -51,9 +54,10 @@ public class DetailsChooser extends BaseListPopupStep { public static void show(final Project project, final Sdk[] existingSdks, - final RelativePoint popupPoint, + JComponent component, final RelativePoint popupPoint, final boolean showMore, final NullableConsumer callback) { + myMore = component; final ListPopupStep sdkHomesStep = new DetailsChooser(project, popupPoint.getComponent(), existingSdks, showMore, callback); final ListPopup popup = JBPopupFactory.getInstance().createListPopup(sdkHomesStep); popup.show(popupPoint); @@ -102,7 +106,10 @@ public class DetailsChooser extends BaseListPopupStep { createVirtualEnvSdk(); } else { - //createSdkFromPath(selectedValue); + DialogBuilder dialog = new DialogBuilder(myProject); + dialog.setTitle("Python Interpreters"); + dialog.setCenterPanel(myMore); + dialog.show(); } } diff --git a/python/src/com/jetbrains/python/sdk/PyDetectedSdk.java b/python/src/com/jetbrains/python/sdk/PyDetectedSdk.java new file mode 100644 index 000000000000..7abc06d68caf --- /dev/null +++ b/python/src/com/jetbrains/python/sdk/PyDetectedSdk.java @@ -0,0 +1,11 @@ +package com.jetbrains.python.sdk; + +import com.intellij.openapi.projectRoots.SdkTypeId; +import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl; + +public class PyDetectedSdk extends ProjectJdkImpl { + public PyDetectedSdk(String name, SdkTypeId sdkType) { + super(name, sdkType); + } + +} diff --git a/python/src/com/jetbrains/python/sdk/PySdkListCellRenderer.java b/python/src/com/jetbrains/python/sdk/PySdkListCellRenderer.java index 9065d371bd94..988622484b97 100644 --- a/python/src/com/jetbrains/python/sdk/PySdkListCellRenderer.java +++ b/python/src/com/jetbrains/python/sdk/PySdkListCellRenderer.java @@ -19,6 +19,7 @@ import com.intellij.icons.AllIcons; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.SdkModificator; import com.intellij.openapi.projectRoots.SdkType; +import com.intellij.openapi.util.IconLoader; import com.intellij.ui.LayeredIcon; import com.intellij.ui.ListCellRendererWrapper; import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; @@ -27,9 +28,10 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.Map; -public class PySdkListCellRenderer extends ListCellRendererWrapper { +public class PySdkListCellRenderer extends ListCellRendererWrapper { private final String myNullText; private final Map mySdkModifiers; + public static final String SEPARATOR = "separator"; public PySdkListCellRenderer() { myNullText = ""; @@ -42,8 +44,9 @@ public class PySdkListCellRenderer extends ListCellRendererWrapper { } @Override - public void customize(JList list, Sdk sdk, int index, boolean selected, boolean hasFocus) { - if (sdk != null) { + public void customize(JList list, Object item, int index, boolean selected, boolean hasFocus) { + if (item instanceof Sdk) { + Sdk sdk = (Sdk)item; final PythonSdkFlavor flavor = PythonSdkFlavor.getPlatformIndependentFlavor(sdk.getHomePath()); final Icon icon = flavor != null ? flavor.getIcon() : ((SdkType)sdk.getSdkType()).getIcon(); @@ -54,7 +57,6 @@ public class PySdkListCellRenderer extends ListCellRendererWrapper { else { name = sdk.getName(); } - if (PythonSdkType.isInvalid(sdk)) { setText("[invalid] " + name); setIcon(wrapIconWithWarningDecorator(icon)); @@ -63,17 +65,22 @@ public class PySdkListCellRenderer extends ListCellRendererWrapper { setText("[incomplete] " + name); setIcon(wrapIconWithWarningDecorator(icon)); } + else if (sdk instanceof PyDetectedSdk){ + setText(name); + setIcon(IconLoader.getTransparentIcon(icon)); + } else { setText(name); setIcon(icon); } } - else { + else if (SEPARATOR.equals(item)) + setSeparator(); + else if (item == null) setText(myNullText); - } } - private LayeredIcon wrapIconWithWarningDecorator(Icon icon) { + private static LayeredIcon wrapIconWithWarningDecorator(Icon icon) { final LayeredIcon layered = new LayeredIcon(2); layered.setIcon(icon, 0); // TODO: Create a separate invalid SDK overlay icon (DSGN-497) diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkType.java b/python/src/com/jetbrains/python/sdk/PythonSdkType.java index d0d910d3b4bb..e3bd6e95927e 100644 --- a/python/src/com/jetbrains/python/sdk/PythonSdkType.java +++ b/python/src/com/jetbrains/python/sdk/PythonSdkType.java @@ -277,7 +277,7 @@ public class PythonSdkType extends SdkType { public void showCustomCreateUI(SdkModel sdkModel, final JComponent parentComponent, final Consumer sdkCreatedCallback) { Project project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(parentComponent)); - DetailsChooser.show(project, sdkModel.getSdks(), RelativePoint.getCenterOf(parentComponent), true, new NullableConsumer() { + DetailsChooser.show(project, sdkModel.getSdks(), null, RelativePoint.getCenterOf(parentComponent), true, new NullableConsumer() { @Override public void consume(@Nullable Sdk sdk) { if (sdk != null) { diff --git a/python/src/com/jetbrains/python/sdk/flavors/MacPythonSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/MacPythonSdkFlavor.java index 780effe67dcb..5d241b668166 100644 --- a/python/src/com/jetbrains/python/sdk/flavors/MacPythonSdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/flavors/MacPythonSdkFlavor.java @@ -16,6 +16,7 @@ package com.jetbrains.python.sdk.flavors; import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VFileProperty; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.newvfs.NewVirtualFile; @@ -57,7 +58,7 @@ public class MacPythonSdkFlavor extends CPythonSdkFlavor { if (binDir != null && binDir.isDirectory()) { for (String name : POSSIBLE_BINARY_NAMES) { final VirtualFile child = binDir.findChild(name); - if (child != null) { + if (child != null && !child.is(VFileProperty.SYMLINK)) { candidates.add(child.getPath()); break; } diff --git a/python/src/com/jetbrains/python/sdk/flavors/UnixPythonSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/UnixPythonSdkFlavor.java index c28587c36ecc..2440661877ff 100644 --- a/python/src/com/jetbrains/python/sdk/flavors/UnixPythonSdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/flavors/UnixPythonSdkFlavor.java @@ -16,6 +16,7 @@ package com.jetbrains.python.sdk.flavors; import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VFileProperty; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.newvfs.NewVirtualFile; @@ -47,14 +48,15 @@ public class UnixPythonSdkFlavor extends CPythonSdkFlavor { if (rootDir instanceof NewVirtualFile) { ((NewVirtualFile)rootDir).markDirty(); } - rootDir.refresh(false, false); + rootDir.refresh(true, false); VirtualFile[] suspects = rootDir.getChildren(); for (VirtualFile child : suspects) { if (!child.isDirectory()) { final String childName = child.getName(); for (String name : NAMES) { if (childName.startsWith(name)) { - if (!childName.endsWith("-config") && !childName.startsWith("pythonw")) { + if (!childName.endsWith("-config") && !childName.startsWith("pythonw") && + !childName.endsWith("m") && !child.is(VFileProperty.SYMLINK)) { candidates.add(child.getPath()); } break; diff --git a/python/src/com/jetbrains/python/sdk/flavors/VirtualEnvSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/VirtualEnvSdkFlavor.java index 5bdecd7a521c..b9de2e2c9003 100644 --- a/python/src/com/jetbrains/python/sdk/flavors/VirtualEnvSdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/flavors/VirtualEnvSdkFlavor.java @@ -83,7 +83,7 @@ public class VirtualEnvSdkFlavor extends CPythonSdkFlavor { public static Collection findInDirectory(VirtualFile rootDir) { List candidates = new ArrayList(); if (rootDir != null) { - rootDir.refresh(false, false); + rootDir.refresh(true, false); VirtualFile[] suspects = rootDir.getChildren(); for (VirtualFile child : suspects) { if (child.isDirectory()) { From e7bd55b7ec223f023d1838ed7599b7351e436463 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Tue, 11 Feb 2014 13:34:11 +0400 Subject: [PATCH 06/39] show packages for detected sdk, fixed NPE if no interpreter selected --- .../jetbrains/python/configuration/PyActiveSdkConfigurable.java | 2 +- python/src/com/jetbrains/python/sdk/PyDetectedSdk.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java index de63179c64d5..16d87e554aa1 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java @@ -145,7 +145,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { dialog.show(); return; } - if (!PySdkListCellRenderer.SEPARATOR.equals(item.toString())) + if (!PySdkListCellRenderer.SEPARATOR.equals(item)) super.setSelectedItem(item); } }; diff --git a/python/src/com/jetbrains/python/sdk/PyDetectedSdk.java b/python/src/com/jetbrains/python/sdk/PyDetectedSdk.java index 7abc06d68caf..4b5d0e2f5529 100644 --- a/python/src/com/jetbrains/python/sdk/PyDetectedSdk.java +++ b/python/src/com/jetbrains/python/sdk/PyDetectedSdk.java @@ -6,6 +6,7 @@ import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl; public class PyDetectedSdk extends ProjectJdkImpl { public PyDetectedSdk(String name, SdkTypeId sdkType) { super(name, sdkType); + setHomePath(name); } } From 038550fbffdb5a3d3d384bd29f20f02722ee3e9f Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Tue, 11 Feb 2014 14:07:12 +0400 Subject: [PATCH 07/39] get rid of make active for selected checkbox in create virtual env --- .../configuration/AddVEnvOptionsDialog.form | 15 ++-------- .../configuration/AddVEnvOptionsDialog.java | 5 ---- .../configuration/PythonSdkConfigurable.java | 29 ++++--------------- .../python/sdk/CreateVirtualEnvDialog.form | 20 ++++--------- .../python/sdk/CreateVirtualEnvDialog.java | 26 ++++------------- .../jetbrains/python/sdk/DetailsChooser.java | 6 ++-- 6 files changed, 24 insertions(+), 77 deletions(-) diff --git a/python/ide/src/com/jetbrains/python/configuration/AddVEnvOptionsDialog.form b/python/ide/src/com/jetbrains/python/configuration/AddVEnvOptionsDialog.form index 78c5657ecc11..5d2cd592e325 100644 --- a/python/ide/src/com/jetbrains/python/configuration/AddVEnvOptionsDialog.form +++ b/python/ide/src/com/jetbrains/python/configuration/AddVEnvOptionsDialog.form @@ -1,6 +1,6 @@
- + @@ -8,23 +8,14 @@ - - - - - - - - - - + - + diff --git a/python/ide/src/com/jetbrains/python/configuration/AddVEnvOptionsDialog.java b/python/ide/src/com/jetbrains/python/configuration/AddVEnvOptionsDialog.java index b4e5b8eac767..d894191369af 100644 --- a/python/ide/src/com/jetbrains/python/configuration/AddVEnvOptionsDialog.java +++ b/python/ide/src/com/jetbrains/python/configuration/AddVEnvOptionsDialog.java @@ -25,7 +25,6 @@ import java.awt.*; * @author yole */ public class AddVEnvOptionsDialog extends DialogWrapper { - private JBCheckBox myUseForThisProjectJBCheckBox; private JBCheckBox myMakeAvailableToAllJBCheckBox; private JPanel myMainPanel; @@ -40,10 +39,6 @@ public class AddVEnvOptionsDialog extends DialogWrapper { return myMainPanel; } - public boolean useForThisProject() { - return myUseForThisProjectJBCheckBox.isSelected(); - } - public boolean makeAvailableToAll() { return myMakeAvailableToAllJBCheckBox.isSelected(); } diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java index baf335dc10fa..e0f173143c55 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java @@ -17,7 +17,6 @@ package com.jetbrains.python.configuration; import com.google.common.collect.Lists; import com.google.common.collect.Sets; -import com.intellij.CommonBundle; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; @@ -35,7 +34,6 @@ import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel; import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.Splitter; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.vfs.VirtualFile; @@ -71,7 +69,6 @@ public class PythonSdkConfigurable implements Configurable, Configurable.NoScrol private JPanel myNotificationsPlaceholder; private PythonPathEditor myPathEditor; private boolean mySdkListChanged = false; - private boolean myMakeActiveAdded = false; private Sdk myAddedSdk; private final PyConfigurableInterpreterList myInterpreterList; private final ProjectSdksModel myProjectSdksModel; @@ -228,7 +225,7 @@ public class PythonSdkConfigurable implements Configurable, Configurable.NoScrol private void createVirtualEnv(Sdk sdk) { CreateVirtualEnvDialog.VirtualEnvCallback callback = new CreateVirtualEnvDialog.VirtualEnvCallback() { @Override - public void virtualEnvCreated(Sdk sdk, boolean associateWithProject, boolean setAsProjectInterpreter) { + public void virtualEnvCreated(Sdk sdk, boolean associateWithProject) { PythonSdkType.setupSdkPaths(sdk, myProject, null); if (associateWithProject) { SdkAdditionalData additionalData = sdk.getSdkAdditionalData(); @@ -243,12 +240,11 @@ public class PythonSdkConfigurable implements Configurable, Configurable.NoScrol ((PythonSdkAdditionalData)additionalData).associateWithProject(myProject); } } - myMakeActiveAdded = setAsProjectInterpreter; addCreatedSdk(sdk, true); } }; final List allSdks = PyConfigurableInterpreterList.getInstance(myProject).getAllPythonSdks(myProject); - final CreateVirtualEnvDialog dialog = new CreateVirtualEnvDialog(myProject, myNewProject, allSdks, sdk); + final CreateVirtualEnvDialog dialog = new CreateVirtualEnvDialog(myProject, allSdks, sdk); dialog.show(); if (dialog.isOK()) { dialog.createVirtualEnv(allSdks, callback); @@ -291,11 +287,9 @@ public class PythonSdkConfigurable implements Configurable, Configurable.NoScrol myModifiedModificators.clear(); myProjectSdksModel.apply(); mySdkListChanged = false; - if (myMakeActiveAdded) { - SdkConfigurationUtil.setDirectoryProjectSdk(myProject, myAddedSdk); - myProjectSdksModel.setProjectSdk(myAddedSdk); - myInterpreterList.setSelectedSdk(myAddedSdk); - } + SdkConfigurationUtil.setDirectoryProjectSdk(myProject, myAddedSdk); + myProjectSdksModel.setProjectSdk(myAddedSdk); + myInterpreterList.setSelectedSdk(myAddedSdk); } /** @@ -369,7 +363,6 @@ public class PythonSdkConfigurable implements Configurable, Configurable.NoScrol .show(myProject, myProjectSdksModel.getSdks(), new PythonSdkConfigurable(myProject).createComponent(), button.getPreferredPopupPoint(), false, new NullableConsumer() { @Override public void consume(Sdk sdk) { - myMakeActiveAdded = false; addCreatedSdk(sdk, false); } }); @@ -379,8 +372,7 @@ public class PythonSdkConfigurable implements Configurable, Configurable.NoScrol if (sdk != null) { myAddedSdk = sdk; boolean isVirtualEnv = PythonSdkType.isVirtualEnv(sdk); - boolean askSetAsProjectInterpreter = !myProject.isDefault() && !myNewProject; - if (askSetAsProjectInterpreter && isVirtualEnv && !newVirtualEnv) { + if (isVirtualEnv && !newVirtualEnv) { AddVEnvOptionsDialog dialog = new AddVEnvOptionsDialog(myPanel); dialog.show(); if (dialog.getExitCode() != DialogWrapper.OK_EXIT_CODE) { @@ -389,20 +381,11 @@ public class PythonSdkConfigurable implements Configurable, Configurable.NoScrol SdkModificator modificator = myModificators.get(sdk); setSdkAssociated(modificator, !dialog.makeAvailableToAll()); myModifiedModificators.add(modificator); - myMakeActiveAdded = dialog.useForThisProject(); } myProjectSdksModel.addSdk(sdk); refreshSdkList(); mySdkList.setSelectedValue(sdk, true); mySdkListChanged = true; - if (askSetAsProjectInterpreter && !isVirtualEnv && !PythonSdkType.isInvalid(sdk) && !PythonSdkType.isIncompleteRemote(sdk)) { - //TODO: make native mac dialog work - myMakeActiveAdded = Messages.showIdeaMessageDialog(myProject, "Do you want to set this interpreter as Project Interpreter?", - "Project Interpreter", - new String[]{CommonBundle.getYesButtonText(), CommonBundle.getNoButtonText()}, 0, null, - null - ) == Messages.YES; - } } } diff --git a/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.form b/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.form index bd84b37f8011..ea6172e1faac 100644 --- a/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.form +++ b/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.form @@ -1,6 +1,6 @@ - + @@ -16,7 +16,7 @@ - + @@ -60,30 +60,22 @@ - + - + - + + - - - - - - - - - diff --git a/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java b/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java index e86fca40be89..7eea8e0aba89 100644 --- a/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java +++ b/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java @@ -67,18 +67,16 @@ public class CreateVirtualEnvDialog extends IdeaDialog { private JTextField myName; private JBCheckBox mySitePackagesCheckBox; private JBCheckBox myMakeAvailableToAllProjectsCheckbox; - private JBCheckBox mySetAsProjectInterpreterCheckbox; @Nullable private Project myProject; private String myInitialPath; public interface VirtualEnvCallback { - void virtualEnvCreated(Sdk sdk, boolean associateWithProject, boolean setAsProjectInterpreter); + void virtualEnvCreated(Sdk sdk, boolean associateWithProject); } private static void setupVirtualEnvSdk(List allSdks, final String path, boolean associateWithProject, - final boolean makeActive, VirtualEnvCallback callback) { final VirtualFile sdkHome = ApplicationManager.getApplication().runWriteAction(new Computable() { @@ -92,27 +90,25 @@ public class CreateVirtualEnvDialog extends IdeaDialog { SdkConfigurationUtil.createUniqueSdkName(PythonSdkType.getInstance(), sdkHome.getPath(), allSdks); final ProjectJdkImpl sdk = new ProjectJdkImpl(name, PythonSdkType.getInstance()); sdk.setHomePath(sdkHome.getPath()); - callback.virtualEnvCreated(sdk, associateWithProject, makeActive); + callback.virtualEnvCreated(sdk, associateWithProject); } } public CreateVirtualEnvDialog(Project project, - boolean isNewProject, final List allSdks, @Nullable Sdk suggestedBaseSdk) { super(project); - setupDialog(project, isNewProject, allSdks, suggestedBaseSdk); + setupDialog(project, allSdks, suggestedBaseSdk); } public CreateVirtualEnvDialog(Component owner, - boolean isNewProject, final List allSdks, @Nullable Sdk suggestedBaseSdk) { super(owner); - setupDialog(null, isNewProject, allSdks, suggestedBaseSdk); + setupDialog(null, allSdks, suggestedBaseSdk); } - private void setupDialog(Project project, boolean isNewProject, List allSdks, @Nullable Sdk suggestedBaseSdk) { + private void setupDialog(Project project, List allSdks, @Nullable Sdk suggestedBaseSdk) { myProject = project; init(); setTitle("Create Virtual Environment"); @@ -123,15 +119,9 @@ public class CreateVirtualEnvDialog extends IdeaDialog { } updateSdkList(allSdks, suggestedBaseSdk); - myMakeAvailableToAllProjectsCheckbox.setBorder(BorderFactory.createEmptyBorder(8, 0, 0, 0)); if (project == null || project.isDefault() || !PlatformUtils.isPyCharm()) { myMakeAvailableToAllProjectsCheckbox.setSelected(true); myMakeAvailableToAllProjectsCheckbox.setVisible(false); - mySetAsProjectInterpreterCheckbox.setSelected(false); - mySetAsProjectInterpreterCheckbox.setVisible(false); - } - else if (isNewProject) { - mySetAsProjectInterpreterCheckbox.setText("Set as project interpreter for the project being created"); } setOKActionEnabled(false); @@ -288,10 +278,6 @@ public class CreateVirtualEnvDialog extends IdeaDialog { return !myMakeAvailableToAllProjectsCheckbox.isSelected(); } - public boolean setAsProjectInterpreter() { - return mySetAsProjectInterpreterCheckbox.isSelected(); - } - @Override public JComponent getPreferredFocusedComponent() { return myName; @@ -326,7 +312,7 @@ public class CreateVirtualEnvDialog extends IdeaDialog { application.invokeLater(new Runnable() { @Override public void run() { - setupVirtualEnvSdk(allSdks, myPath, associateWithProject(), setAsProjectInterpreter(), callback); + setupVirtualEnvSdk(allSdks, myPath, associateWithProject(), callback); } }, ModalityState.any()); } diff --git a/python/src/com/jetbrains/python/sdk/DetailsChooser.java b/python/src/com/jetbrains/python/sdk/DetailsChooser.java index 10dd82f7360f..436c80abfdc4 100644 --- a/python/src/com/jetbrains/python/sdk/DetailsChooser.java +++ b/python/src/com/jetbrains/python/sdk/DetailsChooser.java @@ -138,16 +138,16 @@ public class DetailsChooser extends BaseListPopupStep { final CreateVirtualEnvDialog dialog; final List allSdks = Arrays.asList(myExistingSdks); if (myProject != null) { - dialog = new CreateVirtualEnvDialog(myProject, false, allSdks, null); + dialog = new CreateVirtualEnvDialog(myProject, allSdks, null); } else { - dialog = new CreateVirtualEnvDialog(myOwnerComponent, false, allSdks, null); + dialog = new CreateVirtualEnvDialog(myOwnerComponent, allSdks, null); } dialog.show(); if (dialog.isOK()) { dialog.createVirtualEnv(allSdks, new CreateVirtualEnvDialog.VirtualEnvCallback() { @Override - public void virtualEnvCreated(Sdk sdk, boolean associateWithProject, boolean setAsProjectInterpreter) { + public void virtualEnvCreated(Sdk sdk, boolean associateWithProject) { myCallback.consume(sdk); } }); From d38edf2085ccce7dd002fdb2591b090319e15e4e Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Tue, 11 Feb 2014 17:14:18 +0400 Subject: [PATCH 08/39] all sdks properly added to sdk combobox --- .../PyActiveSdkConfigurable.java | 27 +++++++------------ .../python/sdk/CreateVirtualEnvDialog.java | 3 ++- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java index 16d87e554aa1..da5511de29ae 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java @@ -63,6 +63,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { private final Project myProject; @Nullable private final Module myModule; private MyListener myListener; + boolean mySdkAdded = false; private PyConfigurableInterpreterList myInterpreterList; private ProjectSdksModel myProjectSdksModel; @@ -111,15 +112,10 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { @Override public void consume(Sdk sdk) { if (sdk == null) return; - final Sdk existedSdk = myProjectSdksModel.findSdk(sdk.getName()); - if (existedSdk == null) { - myProjectSdksModel.addSdk(sdk); - } - myInterpreterList.setSelectedSdk(sdk); - + mySdkAdded = true; + updateSdkList(false); mySdkCombo.getModel().setSelectedItem(sdk); - myPackagesPanel.updatePackages( - new PyPackageManagementService(myProject, sdk)); + myPackagesPanel.updatePackages(new PyPackageManagementService(myProject, sdk)); } } ); @@ -219,7 +215,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { public boolean isModified() { final Sdk sdk = getSdk(); final Sdk selectedItem = (Sdk)mySdkCombo.getSelectedItem(); - return selectedItem instanceof PyDetectedSdk || sdk != myProjectSdksModel.findSdk(selectedItem); + return mySdkAdded || selectedItem instanceof PyDetectedSdk || sdk != myProjectSdksModel.findSdk(selectedItem); } @Nullable @@ -243,7 +239,10 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { } }, ModalityState.any()); } - myProjectSdksModel.apply(); + if (mySdkAdded) { + myProjectSdksModel.addSdk(item); + myProjectSdksModel.apply(null, true); + } final Sdk selectedSdk = myProjectSdksModel.findSdk(item); if (myModule == null) { final ProjectRootManager rootManager = ProjectRootManager.getInstance(myProject); @@ -258,14 +257,6 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { ModuleRootModificationUtil.setModuleSdk(myModule, selectedSdk); } final Sdk prevSdk = ProjectRootManager.getInstance(myProject).getProjectSdk(); - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - ProjectRootManager.getInstance(myProject).setProjectSdk(selectedSdk); - } - }); - - myProjectSdksModel.setProjectSdk(selectedSdk); // update string literals if different LanguageLevel was selected if (prevSdk != null && selectedSdk != null) { diff --git a/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java b/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java index 7eea8e0aba89..03331569c0f3 100644 --- a/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java +++ b/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java @@ -74,7 +74,7 @@ public class CreateVirtualEnvDialog extends IdeaDialog { void virtualEnvCreated(Sdk sdk, boolean associateWithProject); } - private static void setupVirtualEnvSdk(List allSdks, + private void setupVirtualEnvSdk(List allSdks, final String path, boolean associateWithProject, VirtualEnvCallback callback) { @@ -91,6 +91,7 @@ public class CreateVirtualEnvDialog extends IdeaDialog { final ProjectJdkImpl sdk = new ProjectJdkImpl(name, PythonSdkType.getInstance()); sdk.setHomePath(sdkHome.getPath()); callback.virtualEnvCreated(sdk, associateWithProject); + PythonSdkType.setupSdkPaths(sdk, myProject, null); } } From 84d7f65df36b3165a37b988c0e16ca6e65522bce Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Wed, 12 Feb 2014 12:38:42 +0400 Subject: [PATCH 09/39] initial version of show all/more actions --- .../PyActiveSdkConfigurable.java | 26 +- .../configuration/PythonSdkConfigurable.java | 2 +- .../configuration/PythonSdkOptions.java | 502 ++++++++++++++++++ .../VirtualEnvProjectFilter.java | 5 +- .../jetbrains/python/sdk/DetailsChooser.java | 12 +- 5 files changed, 519 insertions(+), 28 deletions(-) create mode 100644 python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java diff --git a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java index da5511de29ae..b4af04d96609 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java @@ -35,7 +35,6 @@ import com.intellij.openapi.roots.ModuleRootModificationUtil; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel; import com.intellij.openapi.ui.ComboBox; -import com.intellij.openapi.ui.DialogBuilder; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.CollectionComboBoxModel; import com.intellij.ui.awt.RelativePoint; @@ -45,7 +44,10 @@ import com.intellij.webcore.packaging.PackagesNotificationPanel; import com.jetbrains.python.packaging.ui.PyInstalledPackagesPanel; import com.jetbrains.python.packaging.ui.PyPackageManagementService; import com.jetbrains.python.psi.LanguageLevel; -import com.jetbrains.python.sdk.*; +import com.jetbrains.python.sdk.DetailsChooser; +import com.jetbrains.python.sdk.PyDetectedSdk; +import com.jetbrains.python.sdk.PySdkListCellRenderer; +import com.jetbrains.python.sdk.PythonSdkType; import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; import icons.PythonIcons; import org.jetbrains.annotations.NotNull; @@ -106,7 +108,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { myDetailsButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - DetailsChooser.show(myProject, myProjectSdksModel.getSdks(), new PythonSdkConfigurable(myProject).createComponent(), + DetailsChooser.show(myProject, myProjectSdksModel.getSdks(), new PythonSdkOptions(myProject), RelativePoint.fromScreen(myDetailsButton.getLocationOnScreen()), true, new NullableConsumer() { @Override @@ -135,10 +137,8 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { public void setSelectedItem(Object item) { if (SHOW_ALL.equals(item)) { - DialogBuilder dialog = new DialogBuilder(myProject); - dialog.setTitle("Python Interpreters"); - dialog.setCenterPanel(new PythonSdkConfigurable(myProject).createComponent()); - dialog.show(); + PythonSdkOptions options = new PythonSdkOptions(myProject); + options.show(); return; } if (!PySdkListCellRenderer.SEPARATOR.equals(item)) @@ -306,7 +306,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { if (!sdkList.contains(selection)) { selection = null; } - VirtualEnvProjectFilter.removeNotMatching(myProject, sdkList); + final boolean showAll = VirtualEnvProjectFilter.removeNotMatching(myProject, sdkList); // if the selection is a non-matching virtualenv, show it anyway if (selection != null && !sdkList.contains(selection)) { sdkList.add(0, selection); @@ -317,8 +317,6 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { boolean remoteSeparator = true; boolean separator = true; boolean detectedSeparator = true; - boolean hasAssociationsWithDifferentProject = false; - final String projectBasePath = myProject.getBasePath(); for (Sdk sdk : sdkList) { if (!PythonSdkType.isVirtualEnv(sdk) && !PythonSdkType.isRemote(sdk) && !(sdk instanceof PyDetectedSdk) && separator) { @@ -334,15 +332,9 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { detectedSeparator = false; } items.add(sdk); - - final PythonSdkAdditionalData data = (PythonSdkAdditionalData)sdk.getSdkAdditionalData(); - if (data != null) { - final String path = data.getAssociatedProjectPath(); - if (path != null && !path.equals(projectBasePath)) hasAssociationsWithDifferentProject = true; - } } - if (hasAssociationsWithDifferentProject) { + if (showAll) { items.add(PySdkListCellRenderer.SEPARATOR); items.add(SHOW_ALL); } diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java index e0f173143c55..d90b0e6c3024 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java @@ -360,7 +360,7 @@ public class PythonSdkConfigurable implements Configurable, Configurable.NoScrol private void addSdk(AnActionButton button) { DetailsChooser - .show(myProject, myProjectSdksModel.getSdks(), new PythonSdkConfigurable(myProject).createComponent(), button.getPreferredPopupPoint(), false, new NullableConsumer() { + .show(myProject, myProjectSdksModel.getSdks(), new PythonSdkOptions(myProject), button.getPreferredPopupPoint(), false, new NullableConsumer() { @Override public void consume(Sdk sdk) { addCreatedSdk(sdk, false); diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java new file mode 100644 index 000000000000..68c69d51e6ad --- /dev/null +++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java @@ -0,0 +1,502 @@ +/* + * Copyright 2000-2013 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.configuration; + +import com.google.common.collect.Sets; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.*; +import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl; +import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.OrderRootType; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel; +import com.intellij.openapi.ui.DialogBuilder; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.util.Comparing; +import com.intellij.remotesdk.RemoteCredentials; +import com.intellij.ui.*; +import com.intellij.ui.components.JBList; +import com.intellij.util.NullableConsumer; +import com.intellij.util.NullableFunction; +import com.intellij.util.containers.FactoryMap; +import com.jetbrains.python.remote.PythonRemoteInterpreterManager; +import com.jetbrains.python.sdk.*; +import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; +import icons.PythonIcons; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import java.awt.*; +import java.util.*; +import java.util.List; + +public class PythonSdkOptions extends DialogWrapper { + private JPanel myPanel; + private JList mySdkList; + private boolean mySdkListChanged = false; + private Sdk myAddedSdk; + private final PyConfigurableInterpreterList myInterpreterList; + private final ProjectSdksModel myProjectSdksModel; + + private Map myModificators = new FactoryMap() { + @Override + protected SdkModificator create(Sdk sdk) { + return sdk.getSdkModificator(); + } + }; + private Set myModifiedModificators = new HashSet(); + private boolean myFirstReset; + private final Project myProject; + + private boolean myNewProject = false; + private boolean myShowOtherProjectVirtualenvs = false; + + public void setNewProject(final boolean newProject) { + myNewProject = newProject; + } + + public PythonSdkOptions(Project project) { + super(project); + + setTitle("Project Interpreters"); + myProject = project; + myInterpreterList = PyConfigurableInterpreterList.getInstance(myProject); + myProjectSdksModel = myInterpreterList.getModel(); + myFirstReset = true; + init(); + updateOkButton(); + } + + @Nullable + @Override + protected JComponent createCenterPanel() { + mySdkList = new JBList(); + mySdkList.setCellRenderer(new PySdkListCellRenderer("", myModificators)); + mySdkList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + ToolbarDecorator decorator = ToolbarDecorator.createDecorator(mySdkList).disableUpDownActions() + .setAddAction(new AnActionButtonRunnable() { + @Override + public void run(AnActionButton button) { + addSdk(button); + updateOkButton(); + } + }) + .setEditAction(new AnActionButtonRunnable() { + @Override + public void run(AnActionButton button) { + editSdk(); + updateOkButton(); + } + }) + .setRemoveAction(new AnActionButtonRunnable() { + @Override + public void run(AnActionButton button) { + removeSdk(); + updateOkButton(); + } + }) + .addExtraAction(new CreateVirtualEnvButton()) + .addExtraAction(new ToggleVirtualEnvFilterButton()) + .addExtraAction(new ShowPathButton()); + + decorator.setPreferredSize(new Dimension(600, 500)); + myPanel = decorator.createPanel(); + refreshSdkList(); + addListeners(); + return myPanel; + } + + private void addListeners() { + myProjectSdksModel.addListener(new SdkModel.Listener() { + @Override + public void sdkAdded(Sdk sdk) { + } + + @Override + public void beforeSdkRemove(Sdk sdk) { + } + + @Override + public void sdkChanged(Sdk sdk, String previousName) { + refreshSdkList(); + } + + @Override + public void sdkHomeSelected(Sdk sdk, String newSdkHome) { + } + }); + mySdkList.addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent event) { + updateUI(getSelectedSdk()); + } + }); + } + + private void updateUI(final Sdk selectedSdk) { + myProjectSdksModel.setProjectSdk(selectedSdk); + } + + private void createVirtualEnv(Sdk sdk) { + CreateVirtualEnvDialog.VirtualEnvCallback callback = new CreateVirtualEnvDialog.VirtualEnvCallback() { + @Override + public void virtualEnvCreated(Sdk sdk, boolean associateWithProject) { + PythonSdkType.setupSdkPaths(sdk, myProject, null); + if (associateWithProject) { + SdkAdditionalData additionalData = sdk.getSdkAdditionalData(); + if (additionalData == null) { + additionalData = new PythonSdkAdditionalData(PythonSdkFlavor.getFlavor(sdk.getHomePath())); + ((ProjectJdkImpl)sdk).setSdkAdditionalData(additionalData); + } + if (myNewProject) { + ((PythonSdkAdditionalData)additionalData).associateWithNewProject(); + } + else { + ((PythonSdkAdditionalData)additionalData).associateWithProject(myProject); + } + } + addCreatedSdk(sdk, true); + } + }; + final List allSdks = PyConfigurableInterpreterList.getInstance(myProject).getAllPythonSdks(myProject); + final CreateVirtualEnvDialog dialog = new CreateVirtualEnvDialog(myProject, allSdks, sdk); + dialog.show(); + if (dialog.isOK()) { + dialog.createVirtualEnv(allSdks, callback); + } + } + + public boolean isModified() { + return mySdkListChanged || + myProjectSdksModel.isModified() || + !myModifiedModificators.isEmpty(); + } + + @Nullable + private String getSelectedSdkName() { + final Sdk selectedSdk = (Sdk)mySdkList.getSelectedValue(); + return selectedSdk == null ? null : selectedSdk.getName(); + } + + protected void updateOkButton() { + super.setOKActionEnabled(isModified()); + } + + @Override + protected void doOKAction() { + try { + apply(); + } + catch (ConfigurationException ignored) { + } + super.doOKAction(); + } + + public void apply() throws ConfigurationException { + for (SdkModificator modificator : myModifiedModificators) { + modificator.commitChanges(); + } + myModificators.clear(); + myModifiedModificators.clear(); + myProjectSdksModel.apply(); + mySdkListChanged = false; + SdkConfigurationUtil.setDirectoryProjectSdk(myProject, myAddedSdk); + myProjectSdksModel.setProjectSdk(myAddedSdk); + myInterpreterList.setSelectedSdk(myAddedSdk); + } + + /** + * Returns the stable copy of the SDK currently selected in the SDK table. + * + * @return the selected SDK, or null if there's no selection + */ + @Nullable + public Sdk getRealSelectedSdk() { + return ProjectJdkTable.getInstance().findJdk(getSelectedSdkName()); + } + + @Nullable + public Sdk getSelectedSdk() { + return (Sdk)mySdkList.getSelectedValue(); + } + + public void reset() { + clearModificators(); + if (myFirstReset) { + myFirstReset = false; + } + else { + myProjectSdksModel.reset(null); + } + refreshSdkList(); + } + + private void clearModificators() { + myModificators.clear(); + myModifiedModificators.clear(); + } + + private void refreshSdkList() { + final List pythonSdks = myInterpreterList.getAllPythonSdks(myProject); + Sdk projectSdk = myProjectSdksModel.getProjectSdk(); + if (!myShowOtherProjectVirtualenvs) { + VirtualEnvProjectFilter.removeNotMatching(myProject, pythonSdks); + } + Collections.sort(pythonSdks, new PreferredSdkComparator()); + mySdkList.setModel(new CollectionListModel(pythonSdks)); + + mySdkListChanged = false; + if (projectSdk == null) projectSdk = getSdk(); + if (projectSdk != null) { + projectSdk = myProjectSdksModel.findSdk(projectSdk.getName()); + mySdkList.clearSelection(); + mySdkList.setSelectedValue(projectSdk, true); + mySdkList.updateUI(); + } + } + + @Nullable + private Sdk getSdk() { + final Module[] modules = ModuleManager.getInstance(myProject).getModules(); + if (modules.length > 0) { + final Module module = modules[0]; + final ModuleRootManager rootManager = ModuleRootManager.getInstance(module); + return rootManager.getSdk(); + } + return ProjectRootManager.getInstance(myProject).getProjectSdk(); + } + + private void addSdk(AnActionButton button) { + DetailsChooser + .show(myProject, myProjectSdksModel.getSdks(), this, button.getPreferredPopupPoint(), false, new NullableConsumer() { + @Override + public void consume(Sdk sdk) { + addCreatedSdk(sdk, false); + } + }); + } + + private void addCreatedSdk(@Nullable final Sdk sdk, boolean newVirtualEnv) { + if (sdk != null) { + myAddedSdk = sdk; + boolean isVirtualEnv = PythonSdkType.isVirtualEnv(sdk); + if (isVirtualEnv && !newVirtualEnv) { + AddVEnvOptionsDialog dialog = new AddVEnvOptionsDialog(myPanel); + dialog.show(); + if (dialog.getExitCode() != DialogWrapper.OK_EXIT_CODE) { + return; + } + SdkModificator modificator = myModificators.get(sdk); + setSdkAssociated(modificator, !dialog.makeAvailableToAll()); + myModifiedModificators.add(modificator); + } + myProjectSdksModel.addSdk(sdk); + refreshSdkList(); + mySdkList.setSelectedValue(sdk, true); + mySdkListChanged = true; + } + } + + private void editSdk() { + final Sdk currentSdk = getSelectedSdk(); + if (currentSdk != null) { + if (currentSdk.getSdkAdditionalData() instanceof RemoteCredentials) { + editRemoteSdk(currentSdk); + } + else { + editSdk(currentSdk); + } + updateUI(currentSdk); + } + } + + private void editRemoteSdk(Sdk currentSdk) { + PythonRemoteInterpreterManager remoteInterpreterManager = PythonRemoteInterpreterManager.getInstance(); + if (remoteInterpreterManager != null) { + final SdkModificator modificator = myModificators.get(currentSdk); + Set existingSdks = Sets.newHashSet(myProjectSdksModel.getSdks()); + existingSdks.remove(currentSdk); + if (remoteInterpreterManager.editSdk(myProject, modificator, existingSdks)) { + myModifiedModificators.add(modificator); + } + } + } + + private void editSdk(final Sdk currentSdk) { + final SdkModificator modificator = myModificators.get(currentSdk); + final EditSdkDialog dialog = new EditSdkDialog(myProject, modificator, new NullableFunction() { + @Override + public String fun(String s) { + if (isDuplicateSdkName(s, currentSdk)) { + return "Please specify a unique name for the interpreter"; + } + return null; + } + }); + dialog.show(); + if (dialog.isOK()) { + final boolean pathChanged = !Comparing.equal(currentSdk.getHomePath(), dialog.getHomePath()); + if (!currentSdk.getName().equals(dialog.getName()) || pathChanged || dialog.isAssociateChanged()) { + myModifiedModificators.add(modificator); + modificator.setName(dialog.getName()); + modificator.setHomePath(dialog.getHomePath()); + + if (dialog.isAssociateChanged()) { + setSdkAssociated(modificator, dialog.associateWithProject()); + } + if (pathChanged) { + reloadSdk(currentSdk); + } + } + } + } + + private void setSdkAssociated(SdkModificator modificator, boolean isAssociated) { + PythonSdkAdditionalData additionalData = (PythonSdkAdditionalData)modificator.getSdkAdditionalData(); + if (additionalData == null) { + additionalData = new PythonSdkAdditionalData(PythonSdkFlavor.getFlavor(modificator.getHomePath())); + modificator.setSdkAdditionalData(additionalData); + } + if (isAssociated) { + additionalData.associateWithProject(myProject); + } + else { + additionalData.setAssociatedProjectPath(null); + } + } + + private boolean isDuplicateSdkName(String s, Sdk sdk) { + for (Sdk existingSdk : myProjectSdksModel.getSdks()) { + if (existingSdk == sdk) { + continue; + } + String existingName; + if (myModificators.containsKey(existingSdk)) { + existingName = myModificators.get(existingSdk).getName(); + } + else { + existingName = existingSdk.getName(); + } + if (existingName.equals(s)) { + return true; + } + } + return false; + } + + private void removeSdk() { + final Sdk current_sdk = getSelectedSdk(); + if (current_sdk != null) { + myProjectSdksModel.removeSdk(current_sdk); + if (myModificators.containsKey(current_sdk)) { + SdkModificator modificator = myModificators.get(current_sdk); + myModifiedModificators.remove(modificator); + myModificators.remove(current_sdk); + } + refreshSdkList(); + mySdkListChanged = true; + // TODO select initially selected SDK + if (mySdkList.getSelectedIndex() < 0) { + mySdkList.setSelectedIndex(0); + } + } + } + + private void reloadSdk() { + final Sdk currentSdk = getSelectedSdk(); + if (currentSdk != null) { + myModifiedModificators.add(myModificators.get(currentSdk)); + reloadSdk(currentSdk); + } + } + + private void reloadSdk(Sdk currentSdk) { + PythonSdkType.setupSdkPaths(myProject, null, currentSdk, myModificators.get(currentSdk)); // or must it be a RunWriteAction? + } + + private class CreateVirtualEnvButton extends AnActionButton implements DumbAware { + public CreateVirtualEnvButton() { + super("Create Virtual Environment", PythonIcons.Python.Virtualenv); + } + + @Override + public void actionPerformed(AnActionEvent e) { + Sdk selectedSdk = getSelectedSdk(); + createVirtualEnv(selectedSdk); + updateOkButton(); + } + } + + private class ToggleVirtualEnvFilterButton extends ToggleActionButton implements DumbAware { + public ToggleVirtualEnvFilterButton() { + super("Show virtual environments associated with other projects", AllIcons.General.Filter); + } + + @Override + public boolean isSelected(AnActionEvent e) { + return myShowOtherProjectVirtualenvs; + } + + @Override + public void setSelected(AnActionEvent e, boolean state) { + myShowOtherProjectVirtualenvs = state; + refreshSdkList(); + updateOkButton(); + } + } + private class ShowPathButton extends AnActionButton implements DumbAware { + public ShowPathButton() { + super("Show path for the selected interpreter", AllIcons.Actions.ShowAsTree); + } + + @Override + public boolean isEnabled() { + return !(getSelectedSdk() instanceof PyDetectedSdk); + } + + @Override + public void actionPerformed(AnActionEvent e) { + DialogBuilder dialog = new DialogBuilder(myProject); + + final PythonPathEditor editor = + new PythonPathEditor("Classes", OrderRootType.CLASSES, FileChooserDescriptorFactory.createAllButJarContentsDescriptor()) { + @Override + protected void onReloadButtonClicked() { + reloadSdk(); + } + }; + final JComponent component = editor.createComponent(); + component.setPreferredSize(new Dimension(600, 400)); + component.setBorder(IdeBorderFactory.createBorder(SideBorder.ALL)); + dialog.setCenterPanel(component); + editor.reload(getSelectedSdk().getSdkModificator()); + + dialog.setTitle("Interpreter Paths"); + dialog.show(); + updateOkButton(); + } + } +} diff --git a/python/ide/src/com/jetbrains/python/configuration/VirtualEnvProjectFilter.java b/python/ide/src/com/jetbrains/python/configuration/VirtualEnvProjectFilter.java index 1caf4c31d7e0..c8dc610f9546 100644 --- a/python/ide/src/com/jetbrains/python/configuration/VirtualEnvProjectFilter.java +++ b/python/ide/src/com/jetbrains/python/configuration/VirtualEnvProjectFilter.java @@ -50,13 +50,14 @@ public class VirtualEnvProjectFilter implements Predicate { return false; } - public static void removeNotMatching(Project project, List sdks) { + public static boolean removeNotMatching(Project project, List sdks) { if (project != null) { final String basePath = project.getBasePath(); if (basePath != null) { - Iterables.removeIf(sdks, new VirtualEnvProjectFilter(FileUtil.toSystemIndependentName(basePath))); + return Iterables.removeIf(sdks, new VirtualEnvProjectFilter(FileUtil.toSystemIndependentName(basePath))); } } + return false; } public static void removeAllAssociated(List sdks) { diff --git a/python/src/com/jetbrains/python/sdk/DetailsChooser.java b/python/src/com/jetbrains/python/sdk/DetailsChooser.java index 436c80abfdc4..9cd1f1ec58ef 100644 --- a/python/src/com/jetbrains/python/sdk/DetailsChooser.java +++ b/python/src/com/jetbrains/python/sdk/DetailsChooser.java @@ -22,7 +22,7 @@ import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil; -import com.intellij.openapi.ui.DialogBuilder; +import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.popup.*; import com.intellij.openapi.ui.popup.util.BaseListPopupStep; @@ -31,7 +31,6 @@ import com.intellij.util.NullableConsumer; import com.jetbrains.python.remote.PythonRemoteInterpreterManager; import org.jetbrains.annotations.Nullable; -import javax.swing.*; import java.awt.*; import java.util.ArrayList; import java.util.Arrays; @@ -41,7 +40,7 @@ import java.util.List; * @author yole */ public class DetailsChooser extends BaseListPopupStep { - private static JComponent myMore; + private static DialogWrapper myMore; private final Project myProject; private final Component myOwnerComponent; private final Sdk[] myExistingSdks; @@ -54,7 +53,7 @@ public class DetailsChooser extends BaseListPopupStep { public static void show(final Project project, final Sdk[] existingSdks, - JComponent component, final RelativePoint popupPoint, + DialogWrapper component, final RelativePoint popupPoint, final boolean showMore, final NullableConsumer callback) { myMore = component; @@ -106,10 +105,7 @@ public class DetailsChooser extends BaseListPopupStep { createVirtualEnvSdk(); } else { - DialogBuilder dialog = new DialogBuilder(myProject); - dialog.setTitle("Python Interpreters"); - dialog.setCenterPanel(myMore); - dialog.show(); + myMore.show(); } } From 9356f0b92ef8f8a995ed3d6c99e59434ef87ca0e Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Wed, 12 Feb 2014 12:52:37 +0400 Subject: [PATCH 10/39] don't add already existed sdk --- .../configuration/PythonSdkOptions.java | 56 +++---------------- 1 file changed, 8 insertions(+), 48 deletions(-) diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java index 68c69d51e6ad..a85680d31ea3 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java +++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java @@ -24,8 +24,10 @@ import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; -import com.intellij.openapi.projectRoots.*; -import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl; +import com.intellij.openapi.projectRoots.ProjectJdkTable; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.projectRoots.SdkModel; +import com.intellij.openapi.projectRoots.SdkModificator; import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.OrderRootType; @@ -43,7 +45,6 @@ import com.intellij.util.containers.FactoryMap; import com.jetbrains.python.remote.PythonRemoteInterpreterManager; import com.jetbrains.python.sdk.*; import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; -import icons.PythonIcons; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -72,7 +73,7 @@ public class PythonSdkOptions extends DialogWrapper { private final Project myProject; private boolean myNewProject = false; - private boolean myShowOtherProjectVirtualenvs = false; + private boolean myShowOtherProjectVirtualenvs = true; public void setNewProject(final boolean newProject) { myNewProject = newProject; @@ -119,7 +120,6 @@ public class PythonSdkOptions extends DialogWrapper { updateOkButton(); } }) - .addExtraAction(new CreateVirtualEnvButton()) .addExtraAction(new ToggleVirtualEnvFilterButton()) .addExtraAction(new ShowPathButton()); @@ -160,35 +160,6 @@ public class PythonSdkOptions extends DialogWrapper { myProjectSdksModel.setProjectSdk(selectedSdk); } - private void createVirtualEnv(Sdk sdk) { - CreateVirtualEnvDialog.VirtualEnvCallback callback = new CreateVirtualEnvDialog.VirtualEnvCallback() { - @Override - public void virtualEnvCreated(Sdk sdk, boolean associateWithProject) { - PythonSdkType.setupSdkPaths(sdk, myProject, null); - if (associateWithProject) { - SdkAdditionalData additionalData = sdk.getSdkAdditionalData(); - if (additionalData == null) { - additionalData = new PythonSdkAdditionalData(PythonSdkFlavor.getFlavor(sdk.getHomePath())); - ((ProjectJdkImpl)sdk).setSdkAdditionalData(additionalData); - } - if (myNewProject) { - ((PythonSdkAdditionalData)additionalData).associateWithNewProject(); - } - else { - ((PythonSdkAdditionalData)additionalData).associateWithProject(myProject); - } - } - addCreatedSdk(sdk, true); - } - }; - final List allSdks = PyConfigurableInterpreterList.getInstance(myProject).getAllPythonSdks(myProject); - final CreateVirtualEnvDialog dialog = new CreateVirtualEnvDialog(myProject, allSdks, sdk); - dialog.show(); - if (dialog.isOK()) { - dialog.createVirtualEnv(allSdks, callback); - } - } - public boolean isModified() { return mySdkListChanged || myProjectSdksModel.isModified() || @@ -313,7 +284,9 @@ public class PythonSdkOptions extends DialogWrapper { setSdkAssociated(modificator, !dialog.makeAvailableToAll()); myModifiedModificators.add(modificator); } - myProjectSdksModel.addSdk(sdk); + final Sdk oldSdk = myProjectSdksModel.findSdk(sdk); + if (oldSdk == null) + myProjectSdksModel.addSdk(sdk); refreshSdkList(); mySdkList.setSelectedValue(sdk, true); mySdkListChanged = true; @@ -437,19 +410,6 @@ public class PythonSdkOptions extends DialogWrapper { PythonSdkType.setupSdkPaths(myProject, null, currentSdk, myModificators.get(currentSdk)); // or must it be a RunWriteAction? } - private class CreateVirtualEnvButton extends AnActionButton implements DumbAware { - public CreateVirtualEnvButton() { - super("Create Virtual Environment", PythonIcons.Python.Virtualenv); - } - - @Override - public void actionPerformed(AnActionEvent e) { - Sdk selectedSdk = getSelectedSdk(); - createVirtualEnv(selectedSdk); - updateOkButton(); - } - } - private class ToggleVirtualEnvFilterButton extends ToggleActionButton implements DumbAware { public ToggleVirtualEnvFilterButton() { super("Show virtual environments associated with other projects", AllIcons.General.Filter); From 47f9d569e546cd772637eeb9135229bc05f04623 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Wed, 12 Feb 2014 13:47:48 +0400 Subject: [PATCH 11/39] added generate skeletons action --- .../configuration/PythonSdkOptions.java | 29 +++++++++++++++++- .../icons/com/jetbrains/python/skeleton.png | Bin 0 -> 622 bytes .../com/jetbrains/python/skeleton@2x.png | Bin 0 -> 1352 bytes python/src/icons/PythonIcons.java | 1 + 4 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 python/resources/icons/com/jetbrains/python/skeleton.png create mode 100644 python/resources/icons/com/jetbrains/python/skeleton@2x.png diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java index a85680d31ea3..0fd67b6ff402 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java +++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java @@ -45,6 +45,7 @@ import com.intellij.util.containers.FactoryMap; import com.jetbrains.python.remote.PythonRemoteInterpreterManager; import com.jetbrains.python.sdk.*; import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; +import icons.PythonIcons; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -121,7 +122,8 @@ public class PythonSdkOptions extends DialogWrapper { } }) .addExtraAction(new ToggleVirtualEnvFilterButton()) - .addExtraAction(new ShowPathButton()); + .addExtraAction(new ShowPathButton()) + .addExtraAction(new GenerateSkeletonsButton()); decorator.setPreferredSize(new Dimension(600, 500)); myPanel = decorator.createPanel(); @@ -427,6 +429,7 @@ public class PythonSdkOptions extends DialogWrapper { updateOkButton(); } } + private class ShowPathButton extends AnActionButton implements DumbAware { public ShowPathButton() { super("Show path for the selected interpreter", AllIcons.Actions.ShowAsTree); @@ -459,4 +462,28 @@ public class PythonSdkOptions extends DialogWrapper { updateOkButton(); } } + + private class GenerateSkeletonsButton extends AnActionButton implements DumbAware { + public GenerateSkeletonsButton() { + super("Generate skeletons for the selected interpreter", PythonIcons.Python.Skeleton); + } + + @Override + public boolean isEnabled() { + return (getSelectedSdk() instanceof PyDetectedSdk); + } + + @Override + public void actionPerformed(AnActionEvent e) { + final Sdk sdk = getSelectedSdk(); + if (sdk instanceof PyDetectedSdk) { + + final Sdk addedSdk = SdkConfigurationUtil.createAndAddSDK(sdk.getName(), PythonSdkType.getInstance()); + myProjectSdksModel.addSdk(addedSdk); + myProjectSdksModel.removeSdk(sdk); + refreshSdkList(); + updateOkButton(); + } + } + } } diff --git a/python/resources/icons/com/jetbrains/python/skeleton.png b/python/resources/icons/com/jetbrains/python/skeleton.png new file mode 100644 index 0000000000000000000000000000000000000000..5b50602ef01b61ffca27be2864da983945374a23 GIT binary patch literal 622 zcmV-!0+IcRP)1q7izF!TTb0sBcr zK~y-)t&&TtQc)O&Uyp9hyzEW`MMVff4-Q2fiHAUNA~;f-*&lG=B)A$g$&&T_CJ zokOU&TWHRr_9aJinvBTjo zZtt9J2ea91wApNzo6QENu-R;n+-~=iJ%JzyG|RH0R4P3w==b|qI-Ty}o?t$ok12{; z^m@IeAPCrP!t*@V>-BaKhQr}_PXK^xG#VdRmW9D!fJ&u8v)KdyIGs*twOXXpX%q^D zui0#tIV3VObGcj&Q53;(94r<~8Nf|F*{)zZoqh+fESJmlYPCYQ z+eNKbL$O#yqtSrR=R-Um=T1ISG#Y)?>2!V*LWtMvC4Rr3EEWsGvMiTKBtC^gp^M$T z?6#oQYQ5F#^&z!deLs`QoJplp&@_!yD)mdLRMv92+?U1vrjUOmhGL1l37I zK~z}7?N?t&TUQwW-TX6GlX??1HCxI;F2)6vK;m4X2oo)RC|JRk(H9?l=@eS9I1o%< zWGe_&MA%FFB&81>l+w{goP`dW>e8Szc3YAOF|}(oX>+eJH@(Tc$=O3Y*R*QVJayb%-M99?CRJ5n3$7i?O2LZ@RHtujZzHzx+ zYp-6tBE?`~Vd2lt&d#41hB5EkxYOyJym#+jlI#kTsc19~Vr3VVHV`VW^pznT`7T`jQCf_4>{G_wVys zt+oMY1<|bhnrgCd*t0V%!V32NZZq}vK>1_Z~K?Gv4*n_)w?>;|q;)M3j zojb`=2>5(H%IS2RlO$@ z3Wdnf(9o8{;h5OV$cM7ib~2g#&StYQ8ja??NrfUmpsT8?^7<4-L9f?CqtR?FEiH}i zhX5o=;#4XX+S=Mc)AT<|G8qO32lHfIE>~Xv@ZrO#t*wQ@V5k64y_XHehX^DRi5SoG zS-agXzjf;tE?&F{ilWfp-;a)t4vdV9z-qOkp`ih1&z^-wqrr_EH&9nshtbj3PK%-_ z0m$t47S&$3aN)^r`TgO;hXeo_A0H<+n~mghxn1kPz`(%DhaCO43iWb!cJ{~l`FY{p ziJ6(1o$o*(fJh|rp7QeY^0wda_w1H{iY?7Qb$53^jYgw8Zk{`Lj;K^Ba{2OQ0)TkE z-W{)}rlt}{j~)$MESAZ#{1r7fH@mK1zy7kRsp$#N^MnvWd_Et!efu_%B#DfTjgeF; zMF=5eZf;JnTCKlMOiVllU@A*FRVtM&H*eldO-@cGhlhv7z3P58n1EMF9ZJW-|^RJcvLbfCC2(6ilGt2<15Lg~eh)cXv0|*47}3 zB50b1R;z_lsYD`?fJ`RC`Sa(&aU3{~3zzkA!m{j_SFT)%z8!R_RElsMN7CtZ-UH?2 z$&-EnH7GY)T3Wunbm`LiURf_1jpn+#x_+@(ET0v+CRHp6lgadj&1M^RI-Q@gEL%;} zv?3CT2#br0FT&yQg5U4|8o<_nM&Ruy Date: Wed, 12 Feb 2014 14:12:05 +0400 Subject: [PATCH 12/39] NPE --- .../com/jetbrains/python/configuration/PythonSdkOptions.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java index 0fd67b6ff402..762a77da56dd 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java +++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java @@ -455,7 +455,10 @@ public class PythonSdkOptions extends DialogWrapper { component.setPreferredSize(new Dimension(600, 400)); component.setBorder(IdeBorderFactory.createBorder(SideBorder.ALL)); dialog.setCenterPanel(component); - editor.reload(getSelectedSdk().getSdkModificator()); + final Sdk sdk = getSelectedSdk(); + if (sdk != null) { + editor.reload(sdk.getSdkModificator()); + } dialog.setTitle("Interpreter Paths"); dialog.show(); From 08476e2bebdb4dfdcde42018e27e5232e687e04d Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Wed, 12 Feb 2014 14:17:47 +0400 Subject: [PATCH 13/39] added focus to sdk list --- .../jetbrains/python/configuration/PythonSdkOptions.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java index 762a77da56dd..2d489d03f47a 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java +++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java @@ -162,6 +162,12 @@ public class PythonSdkOptions extends DialogWrapper { myProjectSdksModel.setProjectSdk(selectedSdk); } + @Nullable + @Override + public JComponent getPreferredFocusedComponent() { + return mySdkList; + } + public boolean isModified() { return mySdkListChanged || myProjectSdksModel.isModified() || From d4e77306a7d967f74196b0f5b0a8de7f0da3b527 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Wed, 12 Feb 2014 14:20:16 +0400 Subject: [PATCH 14/39] PythonSdkDetailsStep renamed --- .../PyActiveSdkConfigurable.java | 29 ++++++++++--------- .../configuration/PythonSdkConfigurable.java | 15 +++++----- .../configuration/PythonSdkOptions.java | 2 +- ...Chooser.java => PythonSdkDetailsStep.java} | 17 +++++------ .../jetbrains/python/sdk/PythonSdkType.java | 22 ++++++++------ 5 files changed, 44 insertions(+), 41 deletions(-) rename python/src/com/jetbrains/python/sdk/{DetailsChooser.java => PythonSdkDetailsStep.java} (91%) diff --git a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java index b4af04d96609..d4c9fd13e4b1 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java @@ -44,9 +44,9 @@ import com.intellij.webcore.packaging.PackagesNotificationPanel; import com.jetbrains.python.packaging.ui.PyInstalledPackagesPanel; import com.jetbrains.python.packaging.ui.PyPackageManagementService; import com.jetbrains.python.psi.LanguageLevel; -import com.jetbrains.python.sdk.DetailsChooser; import com.jetbrains.python.sdk.PyDetectedSdk; import com.jetbrains.python.sdk.PySdkListCellRenderer; +import com.jetbrains.python.sdk.PythonSdkDetailsStep; import com.jetbrains.python.sdk.PythonSdkType; import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; import icons.PythonIcons; @@ -108,19 +108,20 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { myDetailsButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - DetailsChooser.show(myProject, myProjectSdksModel.getSdks(), new PythonSdkOptions(myProject), - RelativePoint.fromScreen(myDetailsButton.getLocationOnScreen()), true, - new NullableConsumer() { - @Override - public void consume(Sdk sdk) { - if (sdk == null) return; - mySdkAdded = true; - updateSdkList(false); - mySdkCombo.getModel().setSelectedItem(sdk); - myPackagesPanel.updatePackages(new PyPackageManagementService(myProject, sdk)); - } - } - ); + PythonSdkDetailsStep + .show(myProject, myProjectSdksModel.getSdks(), new PythonSdkOptions(myProject), + RelativePoint.fromScreen(myDetailsButton.getLocationOnScreen()), true, + new NullableConsumer() { + @Override + public void consume(Sdk sdk) { + if (sdk == null) return; + mySdkAdded = true; + updateSdkList(false); + mySdkCombo.getModel().setSelectedItem(sdk); + myPackagesPanel.updatePackages(new PyPackageManagementService(myProject, sdk)); + } + } + ); } } ); diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java index d90b0e6c3024..43468d1d710c 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java @@ -359,13 +359,14 @@ public class PythonSdkConfigurable implements Configurable, Configurable.NoScrol } private void addSdk(AnActionButton button) { - DetailsChooser - .show(myProject, myProjectSdksModel.getSdks(), new PythonSdkOptions(myProject), button.getPreferredPopupPoint(), false, new NullableConsumer() { - @Override - public void consume(Sdk sdk) { - addCreatedSdk(sdk, false); - } - }); + PythonSdkDetailsStep + .show(myProject, myProjectSdksModel.getSdks(), new PythonSdkOptions(myProject), button.getPreferredPopupPoint(), false, + new NullableConsumer() { + @Override + public void consume(Sdk sdk) { + addCreatedSdk(sdk, false); + } + }); } private void addCreatedSdk(@Nullable final Sdk sdk, boolean newVirtualEnv) { diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java index 2d489d03f47a..2b6cfb2b65df 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java +++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java @@ -269,7 +269,7 @@ public class PythonSdkOptions extends DialogWrapper { } private void addSdk(AnActionButton button) { - DetailsChooser + PythonSdkDetailsStep .show(myProject, myProjectSdksModel.getSdks(), this, button.getPreferredPopupPoint(), false, new NullableConsumer() { @Override public void consume(Sdk sdk) { diff --git a/python/src/com/jetbrains/python/sdk/DetailsChooser.java b/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java similarity index 91% rename from python/src/com/jetbrains/python/sdk/DetailsChooser.java rename to python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java index 9cd1f1ec58ef..ea13bc1e692b 100644 --- a/python/src/com/jetbrains/python/sdk/DetailsChooser.java +++ b/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java @@ -36,10 +36,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -/** -* @author yole -*/ -public class DetailsChooser extends BaseListPopupStep { +public class PythonSdkDetailsStep extends BaseListPopupStep { private static DialogWrapper myMore; private final Project myProject; private final Component myOwnerComponent; @@ -57,16 +54,16 @@ public class DetailsChooser extends BaseListPopupStep { final boolean showMore, final NullableConsumer callback) { myMore = component; - final ListPopupStep sdkHomesStep = new DetailsChooser(project, popupPoint.getComponent(), existingSdks, showMore, callback); + final ListPopupStep sdkHomesStep = new PythonSdkDetailsStep(project, popupPoint.getComponent(), existingSdks, showMore, callback); final ListPopup popup = JBPopupFactory.getInstance().createListPopup(sdkHomesStep); popup.show(popupPoint); } - public DetailsChooser(Project project, - Component ownerComponent, - Sdk[] existingSdks, - boolean showMore, - NullableConsumer callback) { + public PythonSdkDetailsStep(Project project, + Component ownerComponent, + Sdk[] existingSdks, + boolean showMore, + NullableConsumer callback) { super(null, getAvailableOptions(showMore)); myProject = project; myOwnerComponent = ownerComponent; diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkType.java b/python/src/com/jetbrains/python/sdk/PythonSdkType.java index e3bd6e95927e..3ad05e039612 100644 --- a/python/src/com/jetbrains/python/sdk/PythonSdkType.java +++ b/python/src/com/jetbrains/python/sdk/PythonSdkType.java @@ -45,7 +45,10 @@ import com.intellij.openapi.util.io.FileSystemUtil; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.CharFilter; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.*; +import com.intellij.openapi.vfs.JarFileSystem; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VfsUtilCore; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.reference.SoftReference; import com.intellij.remotesdk.RemoteSdkData; @@ -277,15 +280,16 @@ public class PythonSdkType extends SdkType { public void showCustomCreateUI(SdkModel sdkModel, final JComponent parentComponent, final Consumer sdkCreatedCallback) { Project project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(parentComponent)); - DetailsChooser.show(project, sdkModel.getSdks(), null, RelativePoint.getCenterOf(parentComponent), true, new NullableConsumer() { - @Override - public void consume(@Nullable Sdk sdk) { - if (sdk != null) { - sdk.putUserData(SDK_CREATOR_COMPONENT_KEY, new WeakReference(parentComponent)); - sdkCreatedCallback.consume(sdk); + PythonSdkDetailsStep + .show(project, sdkModel.getSdks(), null, RelativePoint.getCenterOf(parentComponent), true, new NullableConsumer() { + @Override + public void consume(@Nullable Sdk sdk) { + if (sdk != null) { + sdk.putUserData(SDK_CREATOR_COMPONENT_KEY, new WeakReference(parentComponent)); + sdkCreatedCallback.consume(sdk); + } } - } - }); + }); } public static boolean isVirtualEnv(Sdk sdk) { From 5df90d47ce7ddf8b675fb120a1e3f271a13fcfb7 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Wed, 12 Feb 2014 14:30:34 +0400 Subject: [PATCH 15/39] put detected vEnv in front of other detected vEnvs --- .../configuration/PyConfigurableInterpreterList.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java b/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java index f06d751d3596..ca91a0999e1a 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java @@ -27,6 +27,7 @@ import com.jetbrains.python.sdk.PySdkUtil; import com.jetbrains.python.sdk.PythonSdkAdditionalData; import com.jetbrains.python.sdk.PythonSdkType; import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; +import com.jetbrains.python.sdk.flavors.VirtualEnvSdkFlavor; import javax.swing.*; import java.util.*; @@ -75,7 +76,6 @@ public class PyConfigurableInterpreterList { result.add(sdk); } } - Collection sdkHomes = PythonSdkType.getInstance().suggestHomePaths(); Collections.sort(result, new Comparator() { @Override @@ -113,6 +113,14 @@ public class PyConfigurableInterpreterList { return Comparing.compare(o1.getName(), o2.getName()); } }); + + Collection sdkHomes = new ArrayList(); + sdkHomes.addAll(VirtualEnvSdkFlavor.INSTANCE.suggestHomePaths()); + for (PythonSdkFlavor flavor : PythonSdkFlavor.getApplicableFlavors()) { + if (flavor instanceof VirtualEnvSdkFlavor) continue; + sdkHomes.addAll(flavor.suggestHomePaths()); + } + for (String sdkHome : SdkConfigurationUtil.filterExistingPaths(PythonSdkType.getInstance(), sdkHomes, getModel().getSdks())) { result.add(new PyDetectedSdk(sdkHome, PythonSdkType.getInstance())); } From 9d897149ec9583d1e837b3be27b07fd1980d18a9 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Wed, 12 Feb 2014 15:12:40 +0400 Subject: [PATCH 16/39] apply in case of detected sdk --- .../PyActiveSdkConfigurable.java | 37 ++++++++++++------- .../PyConfigurableInterpreterList.java | 2 +- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java index d4c9fd13e4b1..f1c195b10235 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java @@ -236,7 +236,11 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { @Override public void run() { final Sdk sdk = SdkConfigurationUtil.createAndAddSDK(item.getName(), PythonSdkType.getInstance()); - SdkConfigurationUtil.setDirectoryProjectSdk(myProject, sdk); + myProjectSdksModel.removeSdk(item); + myProjectSdksModel.addSdk(sdk); + updateSdkList(true); + mySdkCombo.setSelectedItem(sdk); + setSdk(sdk); } }, ModalityState.any()); } @@ -244,19 +248,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { myProjectSdksModel.addSdk(item); myProjectSdksModel.apply(null, true); } - final Sdk selectedSdk = myProjectSdksModel.findSdk(item); - if (myModule == null) { - final ProjectRootManager rootManager = ProjectRootManager.getInstance(myProject); - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - rootManager.setProjectSdk(selectedSdk); - } - }); - } - else { - ModuleRootModificationUtil.setModuleSdk(myModule, selectedSdk); - } + final Sdk selectedSdk = setSdk(item); final Sdk prevSdk = ProjectRootManager.getInstance(myProject).getProjectSdk(); // update string literals if different LanguageLevel was selected @@ -275,6 +267,23 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { rehighlightStrings(myProject); } + private Sdk setSdk(Sdk item) { + final Sdk selectedSdk = myProjectSdksModel.findSdk(item); + if (myModule == null) { + final ProjectRootManager rootManager = ProjectRootManager.getInstance(myProject); + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + rootManager.setProjectSdk(selectedSdk); + } + }); + } + else { + ModuleRootModificationUtil.setModuleSdk(myModule, selectedSdk); + } + return selectedSdk; + } + public static void rehighlightStrings(final @NotNull Project project) { ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override diff --git a/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java b/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java index ca91a0999e1a..009c13e76320 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java @@ -114,7 +114,7 @@ public class PyConfigurableInterpreterList { } }); - Collection sdkHomes = new ArrayList(); + final Collection sdkHomes = new ArrayList(); sdkHomes.addAll(VirtualEnvSdkFlavor.INSTANCE.suggestHomePaths()); for (PythonSdkFlavor flavor : PythonSdkFlavor.getApplicableFlavors()) { if (flavor instanceof VirtualEnvSdkFlavor) continue; From 96f6a67225b56002dcd7bdd4a19a526bca10ebfd Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Wed, 12 Feb 2014 15:30:39 +0400 Subject: [PATCH 17/39] update combobox on add local interpreter --- .../openapi/projectRoots/impl/SdkConfigurationUtil.java | 5 +++-- .../python/configuration/PyActiveSdkConfigurable.java | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/SdkConfigurationUtil.java b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/SdkConfigurationUtil.java index a076101072fa..0ff165617df8 100644 --- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/SdkConfigurationUtil.java +++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/SdkConfigurationUtil.java @@ -332,8 +332,9 @@ public class SdkConfigurationUtil { @Nullable private static Sdk findByPath(SdkType sdkType, Sdk[] sdks, String sdkHome) { for (Sdk sdk : sdks) { - if (sdk.getSdkType() == sdkType && - FileUtil.pathsEqual(FileUtil.toSystemIndependentName(sdk.getHomePath()), FileUtil.toSystemIndependentName(sdkHome))) { + final String path = sdk.getHomePath(); + if (sdk.getSdkType() == sdkType && path != null && + FileUtil.pathsEqual(FileUtil.toSystemIndependentName(path), FileUtil.toSystemIndependentName(sdkHome))) { return sdk; } } diff --git a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java index f1c195b10235..ca3855e6ff3c 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java @@ -115,7 +115,10 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { @Override public void consume(Sdk sdk) { if (sdk == null) return; - mySdkAdded = true; + mySdkAdded = myProjectSdksModel.findSdk(sdk) == null; + if (mySdkAdded) { + myProjectSdksModel.addSdk(sdk); + } updateSdkList(false); mySdkCombo.getModel().setSelectedItem(sdk); myPackagesPanel.updatePackages(new PyPackageManagementService(myProject, sdk)); From 5111f9dfbbadc83ae96e01a8f139da34b6e9ec6f Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Wed, 12 Feb 2014 18:21:12 +0400 Subject: [PATCH 18/39] proper reset in case sdk added --- .../PyActiveSdkConfigurable.java | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java index ca3855e6ff3c..21d1614c8acb 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java @@ -65,7 +65,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { private final Project myProject; @Nullable private final Module myModule; private MyListener myListener; - boolean mySdkAdded = false; + Sdk myAddedSdk = null; private PyConfigurableInterpreterList myInterpreterList; private ProjectSdksModel myProjectSdksModel; @@ -115,9 +115,9 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { @Override public void consume(Sdk sdk) { if (sdk == null) return; - mySdkAdded = myProjectSdksModel.findSdk(sdk) == null; - if (mySdkAdded) { + if (myProjectSdksModel.findSdk(sdk) == null) { myProjectSdksModel.addSdk(sdk); + myAddedSdk = sdk; } updateSdkList(false); mySdkCombo.getModel().setSelectedItem(sdk); @@ -219,7 +219,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { public boolean isModified() { final Sdk sdk = getSdk(); final Sdk selectedItem = (Sdk)mySdkCombo.getSelectedItem(); - return mySdkAdded || selectedItem instanceof PyDetectedSdk || sdk != myProjectSdksModel.findSdk(selectedItem); + return myAddedSdk != null || selectedItem instanceof PyDetectedSdk || sdk != myProjectSdksModel.findSdk(selectedItem); } @Nullable @@ -247,12 +247,13 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { } }, ModalityState.any()); } - if (mySdkAdded) { + if (myAddedSdk != null) { myProjectSdksModel.addSdk(item); myProjectSdksModel.apply(null, true); + mySdkCombo.setSelectedItem(item); } - final Sdk selectedSdk = setSdk(item); final Sdk prevSdk = ProjectRootManager.getInstance(myProject).getProjectSdk(); + final Sdk selectedSdk = setSdk(item); // update string literals if different LanguageLevel was selected if (prevSdk != null && selectedSdk != null) { @@ -271,6 +272,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { } private Sdk setSdk(Sdk item) { + myAddedSdk = null; final Sdk selectedSdk = myProjectSdksModel.findSdk(item); if (myModule == null) { final ProjectRootManager rootManager = ProjectRootManager.getInstance(myProject); @@ -307,6 +309,14 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { @Override public void reset() { + if (myAddedSdk != null) { + myProjectSdksModel.removeSdk(myAddedSdk); + myAddedSdk = null; + } + resetSdkList(); + } + + private void resetSdkList() { updateSdkList(false); final Sdk sdk = getSdk(); @@ -371,7 +381,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { @Override public void sdkAdded(Sdk sdk) { - myConfigurable.reset(); + myConfigurable.resetSdkList(); } @Override From 6942f6f5c225f0740a95829d94c0267ddd1a9789 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Wed, 12 Feb 2014 18:34:48 +0400 Subject: [PATCH 19/39] fixed uninstall action availability --- .../com/intellij/webcore/packaging/InstalledPackagesPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/webcore/packaging/InstalledPackagesPanel.java b/platform/lang-impl/src/com/intellij/webcore/packaging/InstalledPackagesPanel.java index 7954aac59b42..56a6f38c2a16 100644 --- a/platform/lang-impl/src/com/intellij/webcore/packaging/InstalledPackagesPanel.java +++ b/platform/lang-impl/src/com/intellij/webcore/packaging/InstalledPackagesPanel.java @@ -271,7 +271,7 @@ public class InstalledPackagesPanel extends JPanel { public void run() { final int[] selected = myPackagesTable.getSelectedRows(); boolean upgradeAvailable = false; - boolean canUninstall = true; + boolean canUninstall = selected.length != 0; boolean canUpgrade = true; if (myPackageManagementService != null && selected.length != 0) { for (int i = 0; i != selected.length; ++i) { From a65b69b39de968e05f9ae374df0fb24f378b85d1 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Wed, 12 Feb 2014 19:15:02 +0400 Subject: [PATCH 20/39] fixed create virtual environment --- .../python/sdk/PythonSdkDetailsStep.java | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java b/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java index ea13bc1e692b..a930baf95f48 100644 --- a/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java +++ b/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java @@ -21,6 +21,8 @@ import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.projectRoots.SdkAdditionalData; +import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl; import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; @@ -29,6 +31,7 @@ import com.intellij.openapi.ui.popup.util.BaseListPopupStep; import com.intellij.ui.awt.RelativePoint; import com.intellij.util.NullableConsumer; import com.jetbrains.python.remote.PythonRemoteInterpreterManager; +import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; import org.jetbrains.annotations.Nullable; import java.awt.*; @@ -128,6 +131,22 @@ public class PythonSdkDetailsStep extends BaseListPopupStep { } private void createVirtualEnvSdk() { + CreateVirtualEnvDialog.VirtualEnvCallback callback = new CreateVirtualEnvDialog.VirtualEnvCallback() { + @Override + public void virtualEnvCreated(Sdk sdk, boolean associateWithProject) { + PythonSdkType.setupSdkPaths(sdk, myProject, null); + if (associateWithProject) { + SdkAdditionalData additionalData = sdk.getSdkAdditionalData(); + if (additionalData == null) { + additionalData = new PythonSdkAdditionalData(PythonSdkFlavor.getFlavor(sdk.getHomePath())); + ((ProjectJdkImpl)sdk).setSdkAdditionalData(additionalData); + } + ((PythonSdkAdditionalData)additionalData).associateWithProject(myProject); + } + myCallback.consume(sdk); + } + }; + final CreateVirtualEnvDialog dialog; final List allSdks = Arrays.asList(myExistingSdks); if (myProject != null) { @@ -138,12 +157,7 @@ public class PythonSdkDetailsStep extends BaseListPopupStep { } dialog.show(); if (dialog.isOK()) { - dialog.createVirtualEnv(allSdks, new CreateVirtualEnvDialog.VirtualEnvCallback() { - @Override - public void virtualEnvCreated(Sdk sdk, boolean associateWithProject) { - myCallback.consume(sdk); - } - }); + dialog.createVirtualEnv(allSdks, callback); } } From dd5098d38d191710eb43f9182a3168bfaea9016e Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Wed, 12 Feb 2014 19:18:34 +0400 Subject: [PATCH 21/39] reload python paths list --- .../com/jetbrains/python/configuration/PythonSdkOptions.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java index 2b6cfb2b65df..677438035e4b 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java +++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java @@ -462,9 +462,7 @@ public class PythonSdkOptions extends DialogWrapper { component.setBorder(IdeBorderFactory.createBorder(SideBorder.ALL)); dialog.setCenterPanel(component); final Sdk sdk = getSelectedSdk(); - if (sdk != null) { - editor.reload(sdk.getSdkModificator()); - } + editor.reload(sdk != null ? sdk.getSdkModificator(): null); dialog.setTitle("Interpreter Paths"); dialog.show(); From aba8055a71be3aa98fe18d2f11b10e50889facfa Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Wed, 12 Feb 2014 19:20:35 +0400 Subject: [PATCH 22/39] renamed PythonSdkDetailsDialog --- .../python/configuration/PyActiveSdkConfigurable.java | 4 ++-- .../jetbrains/python/configuration/PythonSdkConfigurable.java | 2 +- .../{PythonSdkOptions.java => PythonSdkDetailsDialog.java} | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) rename python/ide/src/com/jetbrains/python/configuration/{PythonSdkOptions.java => PythonSdkDetailsDialog.java} (99%) diff --git a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java index 21d1614c8acb..86267416f5a9 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java @@ -109,7 +109,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { @Override public void actionPerformed(ActionEvent e) { PythonSdkDetailsStep - .show(myProject, myProjectSdksModel.getSdks(), new PythonSdkOptions(myProject), + .show(myProject, myProjectSdksModel.getSdks(), new PythonSdkDetailsDialog(myProject), RelativePoint.fromScreen(myDetailsButton.getLocationOnScreen()), true, new NullableConsumer() { @Override @@ -141,7 +141,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { public void setSelectedItem(Object item) { if (SHOW_ALL.equals(item)) { - PythonSdkOptions options = new PythonSdkOptions(myProject); + PythonSdkDetailsDialog options = new PythonSdkDetailsDialog(myProject); options.show(); return; } diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java index 43468d1d710c..022b2a5aa31c 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java @@ -360,7 +360,7 @@ public class PythonSdkConfigurable implements Configurable, Configurable.NoScrol private void addSdk(AnActionButton button) { PythonSdkDetailsStep - .show(myProject, myProjectSdksModel.getSdks(), new PythonSdkOptions(myProject), button.getPreferredPopupPoint(), false, + .show(myProject, myProjectSdksModel.getSdks(), new PythonSdkDetailsDialog(myProject), button.getPreferredPopupPoint(), false, new NullableConsumer() { @Override public void consume(Sdk sdk) { diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java similarity index 99% rename from python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java rename to python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java index 677438035e4b..e72bed5bc491 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkOptions.java +++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java @@ -55,7 +55,7 @@ import java.awt.*; import java.util.*; import java.util.List; -public class PythonSdkOptions extends DialogWrapper { +public class PythonSdkDetailsDialog extends DialogWrapper { private JPanel myPanel; private JList mySdkList; private boolean mySdkListChanged = false; @@ -80,7 +80,7 @@ public class PythonSdkOptions extends DialogWrapper { myNewProject = newProject; } - public PythonSdkOptions(Project project) { + public PythonSdkDetailsDialog(Project project) { super(project); setTitle("Project Interpreters"); From 77ff70dce4bb5ee0541345bf973039baee8a63e9 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Wed, 12 Feb 2014 19:22:43 +0400 Subject: [PATCH 23/39] remove upused methods --- .../configuration/PythonSdkDetailsDialog.java | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java index e72bed5bc491..0c57ca2607b3 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java +++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java @@ -70,7 +70,6 @@ public class PythonSdkDetailsDialog extends DialogWrapper { } }; private Set myModifiedModificators = new HashSet(); - private boolean myFirstReset; private final Project myProject; private boolean myNewProject = false; @@ -87,7 +86,6 @@ public class PythonSdkDetailsDialog extends DialogWrapper { myProject = project; myInterpreterList = PyConfigurableInterpreterList.getInstance(myProject); myProjectSdksModel = myInterpreterList.getModel(); - myFirstReset = true; init(); updateOkButton(); } @@ -222,22 +220,6 @@ public class PythonSdkDetailsDialog extends DialogWrapper { return (Sdk)mySdkList.getSelectedValue(); } - public void reset() { - clearModificators(); - if (myFirstReset) { - myFirstReset = false; - } - else { - myProjectSdksModel.reset(null); - } - refreshSdkList(); - } - - private void clearModificators() { - myModificators.clear(); - myModifiedModificators.clear(); - } - private void refreshSdkList() { final List pythonSdks = myInterpreterList.getAllPythonSdks(myProject); Sdk projectSdk = myProjectSdksModel.getProjectSdk(); From fb03522bb84fd98de6499e236ece5d1515c113e1 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Wed, 12 Feb 2014 20:19:43 +0400 Subject: [PATCH 24/39] select in combobox interpreter selected in details --- .../PyActiveSdkConfigurable.java | 17 ++++++- .../configuration/PythonSdkConfigurable.java | 2 +- .../configuration/PythonSdkDetailsDialog.java | 48 +++++++++++++------ 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java index 86267416f5a9..ba89a444c3d7 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java @@ -73,6 +73,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { private PyInstalledPackagesPanel myPackagesPanel; private JButton myDetailsButton; private static final String SHOW_ALL = "Show All"; + private NullableConsumer myDetailsCallback; public PyActiveSdkConfigurable(@NotNull Project project) { myModule = null; @@ -104,12 +105,23 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { myPackagesPanel.updatePackages(new PyPackageManagementService(myProject, selectedSdk)); } }); + myDetailsCallback = new NullableConsumer() { + + @Override + public void consume(@Nullable Sdk sdk) { + if (getSdk() != sdk) { + mySdkCombo.setSelectedItem(sdk); + } + } + }; myDetailsButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { PythonSdkDetailsStep - .show(myProject, myProjectSdksModel.getSdks(), new PythonSdkDetailsDialog(myProject), + .show(myProject, myProjectSdksModel.getSdks(), + myModule == null ? new PythonSdkDetailsDialog(myProject, myDetailsCallback) : + new PythonSdkDetailsDialog(myModule, myDetailsCallback), RelativePoint.fromScreen(myDetailsButton.getLocationOnScreen()), true, new NullableConsumer() { @Override @@ -141,7 +153,8 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { public void setSelectedItem(Object item) { if (SHOW_ALL.equals(item)) { - PythonSdkDetailsDialog options = new PythonSdkDetailsDialog(myProject); + PythonSdkDetailsDialog options = myModule == null ? new PythonSdkDetailsDialog(myProject, myDetailsCallback) : + new PythonSdkDetailsDialog(myModule, myDetailsCallback); options.show(); return; } diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java index 022b2a5aa31c..ccfd0f588971 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java @@ -360,7 +360,7 @@ public class PythonSdkConfigurable implements Configurable, Configurable.NoScrol private void addSdk(AnActionButton button) { PythonSdkDetailsStep - .show(myProject, myProjectSdksModel.getSdks(), new PythonSdkDetailsDialog(myProject), button.getPreferredPopupPoint(), false, + .show(myProject, myProjectSdksModel.getSdks(), new PythonSdkDetailsDialog(myProject, null), button.getPreferredPopupPoint(), false, new NullableConsumer() { @Override public void consume(Sdk sdk) { diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java index 0c57ca2607b3..4728331ba206 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java +++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java @@ -20,7 +20,6 @@ import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; @@ -74,15 +73,19 @@ public class PythonSdkDetailsDialog extends DialogWrapper { private boolean myNewProject = false; private boolean myShowOtherProjectVirtualenvs = true; + private final Module myModule; + private NullableConsumer myShowMoreCallback; public void setNewProject(final boolean newProject) { myNewProject = newProject; } - public PythonSdkDetailsDialog(Project project) { + public PythonSdkDetailsDialog(Project project, NullableConsumer showMoreCallback) { super(project); + myModule = null; setTitle("Project Interpreters"); + myShowMoreCallback = showMoreCallback; myProject = project; myInterpreterList = PyConfigurableInterpreterList.getInstance(myProject); myProjectSdksModel = myInterpreterList.getModel(); @@ -90,6 +93,19 @@ public class PythonSdkDetailsDialog extends DialogWrapper { updateOkButton(); } + public PythonSdkDetailsDialog(Module module, NullableConsumer showMoreCallback) { + super(module.getProject()); + myModule = module; + + setTitle("Project Interpreters"); + myShowMoreCallback = showMoreCallback; + myProject = module.getProject(); + myInterpreterList = PyConfigurableInterpreterList.getInstance(myProject); + myProjectSdksModel = myInterpreterList.getModel(); + init(); + updateOkButton(); + } + @Nullable @Override protected JComponent createCenterPanel() { @@ -151,6 +167,7 @@ public class PythonSdkDetailsDialog extends DialogWrapper { }); mySdkList.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent event) { + updateOkButton(); updateUI(getSelectedSdk()); } }); @@ -167,7 +184,11 @@ public class PythonSdkDetailsDialog extends DialogWrapper { } public boolean isModified() { - return mySdkListChanged || + Sdk projectSdk = getSdk(); + if (projectSdk != null) { + projectSdk = myProjectSdksModel.findSdk(projectSdk.getName()); + } + return getSelectedSdk() != projectSdk || mySdkListChanged || myProjectSdksModel.isModified() || !myModifiedModificators.isEmpty(); } @@ -200,9 +221,10 @@ public class PythonSdkDetailsDialog extends DialogWrapper { myModifiedModificators.clear(); myProjectSdksModel.apply(); mySdkListChanged = false; - SdkConfigurationUtil.setDirectoryProjectSdk(myProject, myAddedSdk); - myProjectSdksModel.setProjectSdk(myAddedSdk); - myInterpreterList.setSelectedSdk(myAddedSdk); + if (myAddedSdk != null) { + myInterpreterList.setSelectedSdk(myAddedSdk); + } + myShowMoreCallback.consume(getSelectedSdk()); } /** @@ -222,7 +244,7 @@ public class PythonSdkDetailsDialog extends DialogWrapper { private void refreshSdkList() { final List pythonSdks = myInterpreterList.getAllPythonSdks(myProject); - Sdk projectSdk = myProjectSdksModel.getProjectSdk(); + Sdk projectSdk = getSdk(); if (!myShowOtherProjectVirtualenvs) { VirtualEnvProjectFilter.removeNotMatching(myProject, pythonSdks); } @@ -230,7 +252,6 @@ public class PythonSdkDetailsDialog extends DialogWrapper { mySdkList.setModel(new CollectionListModel(pythonSdks)); mySdkListChanged = false; - if (projectSdk == null) projectSdk = getSdk(); if (projectSdk != null) { projectSdk = myProjectSdksModel.findSdk(projectSdk.getName()); mySdkList.clearSelection(); @@ -238,16 +259,13 @@ public class PythonSdkDetailsDialog extends DialogWrapper { mySdkList.updateUI(); } } - @Nullable private Sdk getSdk() { - final Module[] modules = ModuleManager.getInstance(myProject).getModules(); - if (modules.length > 0) { - final Module module = modules[0]; - final ModuleRootManager rootManager = ModuleRootManager.getInstance(module); - return rootManager.getSdk(); + if (myModule == null) { + return ProjectRootManager.getInstance(myProject).getProjectSdk(); } - return ProjectRootManager.getInstance(myProject).getProjectSdk(); + final ModuleRootManager rootManager = ModuleRootManager.getInstance(myModule); + return rootManager.getSdk(); } private void addSdk(AnActionButton button) { From 1a437f5efd59d8fd330b42fa186f2a16dff1d0ce Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Wed, 12 Feb 2014 21:04:16 +0400 Subject: [PATCH 25/39] selection fix --- .../python/configuration/PythonSdkDetailsDialog.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java index 4728331ba206..73240c81d4ea 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java +++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java @@ -221,9 +221,6 @@ public class PythonSdkDetailsDialog extends DialogWrapper { myModifiedModificators.clear(); myProjectSdksModel.apply(); mySdkListChanged = false; - if (myAddedSdk != null) { - myInterpreterList.setSelectedSdk(myAddedSdk); - } myShowMoreCallback.consume(getSelectedSdk()); } @@ -484,11 +481,17 @@ public class PythonSdkDetailsDialog extends DialogWrapper { public void actionPerformed(AnActionEvent e) { final Sdk sdk = getSelectedSdk(); if (sdk instanceof PyDetectedSdk) { + try { + myProjectSdksModel.apply(); + } + catch (ConfigurationException ignored) { + } final Sdk addedSdk = SdkConfigurationUtil.createAndAddSDK(sdk.getName(), PythonSdkType.getInstance()); myProjectSdksModel.addSdk(addedSdk); myProjectSdksModel.removeSdk(sdk); refreshSdkList(); + mySdkList.setSelectedValue(addedSdk, true); updateOkButton(); } } From 807a713a363f014ac8df5d382a7e73c49ed18e28 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Wed, 12 Feb 2014 21:35:48 +0400 Subject: [PATCH 26/39] used setup sdk properly --- .../python/configuration/PythonSdkDetailsDialog.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java index 73240c81d4ea..6ec5178b68d7 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java +++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java @@ -487,7 +487,9 @@ public class PythonSdkDetailsDialog extends DialogWrapper { catch (ConfigurationException ignored) { } - final Sdk addedSdk = SdkConfigurationUtil.createAndAddSDK(sdk.getName(), PythonSdkType.getInstance()); + final Sdk addedSdk = SdkConfigurationUtil.setupSdk(myProjectSdksModel.getSdks(), sdk.getHomeDirectory(), + PythonSdkType.getInstance(), true, + null, null); myProjectSdksModel.addSdk(addedSdk); myProjectSdksModel.removeSdk(sdk); refreshSdkList(); From b3cae01c8c31850c167e12f31c5e88791b22ac3a Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Wed, 12 Feb 2014 21:41:31 +0400 Subject: [PATCH 27/39] used proper sorting in details list --- .../com/jetbrains/python/sdk/PreferredSdkComparator.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/python/src/com/jetbrains/python/sdk/PreferredSdkComparator.java b/python/src/com/jetbrains/python/sdk/PreferredSdkComparator.java index 50bc771cfb8a..ff1cea915df4 100644 --- a/python/src/com/jetbrains/python/sdk/PreferredSdkComparator.java +++ b/python/src/com/jetbrains/python/sdk/PreferredSdkComparator.java @@ -37,6 +37,12 @@ public class PreferredSdkComparator implements Comparator { if (remote1Weight != remote2Weight) { return remote2Weight - remote1Weight; } + int detectedWeight1 = o1 instanceof PyDetectedSdk ? 0 : 1; + int detectedWeight2 = o2 instanceof PyDetectedSdk ? 0 : 1; + if (detectedWeight1 != detectedWeight2) { + return detectedWeight2 - detectedWeight1; + } + int venv1weight = PythonSdkType.isVirtualEnv(o1) ? 0 : 1; int venv2weight = PythonSdkType.isVirtualEnv(o2) ? 0 : 1; if (venv1weight != venv2weight) { @@ -47,6 +53,7 @@ public class PreferredSdkComparator implements Comparator { if (flavor1weight != flavor2weight) { return flavor2weight - flavor1weight; } + return -Comparing.compare(o1.getVersionString(), o2.getVersionString()); } } From aa98747043a6097e7541eb29e1e10642ce6c4039 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Wed, 12 Feb 2014 21:49:07 +0400 Subject: [PATCH 28/39] add detected sdk from details dialog --- .../python/configuration/PyActiveSdkConfigurable.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java index ba89a444c3d7..d8ffa0146ad1 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java @@ -109,7 +109,16 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { @Override public void consume(@Nullable Sdk sdk) { - if (getSdk() != sdk) { + if (sdk instanceof PyDetectedSdk) { + final Sdk addedSdk = SdkConfigurationUtil.setupSdk(myProjectSdksModel.getSdks(), sdk.getHomeDirectory(), + PythonSdkType.getInstance(), true, + null, null); + myAddedSdk = addedSdk; + myProjectSdksModel.addSdk(addedSdk); + myProjectSdksModel.removeSdk(sdk); + mySdkCombo.setSelectedItem(addedSdk); + } + else if (getSdk() != sdk) { mySdkCombo.setSelectedItem(sdk); } } From ed6ff89722e96b2ee5cdc2368f2479a46aafcdcd Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Wed, 12 Feb 2014 22:06:41 +0400 Subject: [PATCH 29/39] added detected sdks to create virtual env --- .../PyConfigurableInterpreterList.java | 2 +- .../python/sdk/CreateVirtualEnvDialog.java | 20 +++++++++---------- .../jetbrains/python/sdk/PyDetectedSdk.java | 5 ++--- .../python/sdk/PythonSdkDetailsStep.java | 13 ++++++++++-- .../python/sdk/flavors/PythonSdkFlavor.java | 7 ++++++- 5 files changed, 29 insertions(+), 18 deletions(-) diff --git a/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java b/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java index 009c13e76320..0260c8e7edc2 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java @@ -122,7 +122,7 @@ public class PyConfigurableInterpreterList { } for (String sdkHome : SdkConfigurationUtil.filterExistingPaths(PythonSdkType.getInstance(), sdkHomes, getModel().getSdks())) { - result.add(new PyDetectedSdk(sdkHome, PythonSdkType.getInstance())); + result.add(new PyDetectedSdk(sdkHome)); } return result; } diff --git a/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java b/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java index 03331569c0f3..165d73732043 100644 --- a/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java +++ b/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java @@ -15,6 +15,8 @@ */ package com.jetbrains.python.sdk; +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; import com.intellij.facet.ui.FacetEditorValidator; import com.intellij.facet.ui.FacetValidatorsManager; import com.intellij.openapi.application.Application; @@ -114,6 +116,12 @@ public class CreateVirtualEnvDialog extends IdeaDialog { init(); setTitle("Create Virtual Environment"); if (suggestedBaseSdk == null && allSdks.size() > 0) { + Iterables.removeIf(allSdks, new Predicate() { + @Override + public boolean apply(Sdk s) { + return PythonSdkType.isInvalid(s) || PythonSdkType.isVirtualEnv(s) || RemoteSdkDataHolder.isRemoteSdk(s.getHomePath()); + } + }); List sortedSdks = new ArrayList(allSdks); Collections.sort(sortedSdks, new PreferredSdkComparator()); suggestedBaseSdk = sortedSdks.get(0); @@ -229,17 +237,7 @@ public class CreateVirtualEnvDialog extends IdeaDialog { private void updateSdkList(final List allSdks, @Nullable Sdk initialSelection) { mySdkCombo.setRenderer(new PySdkListCellRenderer()); - List baseSdks = new ArrayList(); - for (Sdk s : allSdks) { - if (!PythonSdkType.isInvalid(s) && !PythonSdkType.isVirtualEnv(s) && !RemoteSdkDataHolder.isRemoteSdk(s.getHomePath())) { - baseSdks.add(s); - } - else if (s.equals(initialSelection)){ - initialSelection = null; - } - } - - mySdkCombo.setModel(new CollectionComboBoxModel(baseSdks, initialSelection)); + mySdkCombo.setModel(new CollectionComboBoxModel(allSdks, initialSelection)); } @Override diff --git a/python/src/com/jetbrains/python/sdk/PyDetectedSdk.java b/python/src/com/jetbrains/python/sdk/PyDetectedSdk.java index 4b5d0e2f5529..098462ef44fb 100644 --- a/python/src/com/jetbrains/python/sdk/PyDetectedSdk.java +++ b/python/src/com/jetbrains/python/sdk/PyDetectedSdk.java @@ -1,11 +1,10 @@ package com.jetbrains.python.sdk; -import com.intellij.openapi.projectRoots.SdkTypeId; import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl; public class PyDetectedSdk extends ProjectJdkImpl { - public PyDetectedSdk(String name, SdkTypeId sdkType) { - super(name, sdkType); + public PyDetectedSdk(String name) { + super(name, PythonSdkType.getInstance()); setHomePath(name); } diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java b/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java index a930baf95f48..8e3f18a9ee13 100644 --- a/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java +++ b/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java @@ -36,7 +36,7 @@ import org.jetbrains.annotations.Nullable; import java.awt.*; import java.util.ArrayList; -import java.util.Arrays; +import java.util.Collection; import java.util.List; public class PythonSdkDetailsStep extends BaseListPopupStep { @@ -148,7 +148,16 @@ public class PythonSdkDetailsStep extends BaseListPopupStep { }; final CreateVirtualEnvDialog dialog; - final List allSdks = Arrays.asList(myExistingSdks); + final List allSdks = Lists.newArrayList(myExistingSdks); + + final List flavors = PythonSdkFlavor.getApplicableFlavors(false); + for (PythonSdkFlavor flavor : flavors) { + final Collection strings = flavor.suggestHomePaths(); + for (String string : strings) { + allSdks.add(new PyDetectedSdk(string)); + } + } + if (myProject != null) { dialog = new CreateVirtualEnvDialog(myProject, allSdks, null); } diff --git a/python/src/com/jetbrains/python/sdk/flavors/PythonSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/PythonSdkFlavor.java index 60fa8025a8a6..07c8e1c30c60 100644 --- a/python/src/com/jetbrains/python/sdk/flavors/PythonSdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/flavors/PythonSdkFlavor.java @@ -72,6 +72,10 @@ public abstract class PythonSdkFlavor { } public static List getApplicableFlavors() { + return getApplicableFlavors(true); + } + + public static List getApplicableFlavors(boolean addPlatformIndependent) { List result = new ArrayList(); if (SystemInfo.isWindows) { @@ -84,7 +88,8 @@ public abstract class PythonSdkFlavor { result.add(UnixPythonSdkFlavor.INSTANCE); } - result.addAll(getPlatformIndependentFlavors()); + if (addPlatformIndependent) + result.addAll(getPlatformIndependentFlavors()); return result; } From 0a13f6c4db31a7dca0a76260476674c83c87bde9 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Thu, 13 Feb 2014 13:20:59 +0400 Subject: [PATCH 30/39] console options always modified --- python/ide/src/com/jetbrains/python/PyIdeCommonOptionsForm.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ide/src/com/jetbrains/python/PyIdeCommonOptionsForm.java b/python/ide/src/com/jetbrains/python/PyIdeCommonOptionsForm.java index 8f633e359038..94e991240001 100644 --- a/python/ide/src/com/jetbrains/python/PyIdeCommonOptionsForm.java +++ b/python/ide/src/com/jetbrains/python/PyIdeCommonOptionsForm.java @@ -266,7 +266,7 @@ public class PyIdeCommonOptionsForm implements AbstractPyCommonOptionsForm { return myPathMappingsComponent.getMappingSettings(); } else { - return null; + return new PathMappingSettings(); } } From 59f8dbb6d622ad111b11f05cccda6dc84fe91f08 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Thu, 13 Feb 2014 13:31:34 +0400 Subject: [PATCH 31/39] use proper configurable in configure interpreters link --- .../python/configuration/PyConfigureInterpretersLinkPanel.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/ide/src/com/jetbrains/python/configuration/PyConfigureInterpretersLinkPanel.java b/python/ide/src/com/jetbrains/python/configuration/PyConfigureInterpretersLinkPanel.java index 41c2ebe53a40..1523cfc25b2c 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyConfigureInterpretersLinkPanel.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyConfigureInterpretersLinkPanel.java @@ -16,6 +16,7 @@ package com.jetbrains.python.configuration; import com.intellij.ide.DataManager; +import com.intellij.openapi.options.SearchableConfigurable; import com.intellij.openapi.options.newEditor.OptionsEditor; import com.intellij.ui.ClickListener; import com.intellij.ui.components.JBLabel; @@ -40,7 +41,7 @@ public class PyConfigureInterpretersLinkPanel extends JPanel { if (clickCount == 1) { final OptionsEditor optionsEditor = OptionsEditor.KEY.getData(DataManager.getInstance().getDataContext(parentPanel)); if (optionsEditor != null) { - PythonSdkConfigurable configurable = optionsEditor.findConfigurable(PythonSdkConfigurable.class); + SearchableConfigurable configurable = optionsEditor.findConfigurableById(PyActiveSdkModuleConfigurable.class.getName()); if (configurable != null) { optionsEditor.clearSearchAndSelect(configurable); } From e419749651ea12091bd2ceaf4a1ee50c7ec3aac9 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Fri, 14 Feb 2014 18:25:48 +0400 Subject: [PATCH 32/39] fixed package list update + cleanup --- .../PyActiveSdkConfigurable.java | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java index d8ffa0146ad1..561c1e40479d 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java @@ -61,11 +61,11 @@ import java.util.ArrayList; import java.util.List; public class PyActiveSdkConfigurable implements UnnamedConfigurable { - private JPanel myPanel; + private JPanel myMainPanel; private final Project myProject; @Nullable private final Module myModule; - private MyListener myListener; - Sdk myAddedSdk = null; + private MySdkModelListener mySdkModelListener; + private Sdk myAddedSdk = null; private PyConfigurableInterpreterList myInterpreterList; private ProjectSdksModel myProjectSdksModel; @@ -94,15 +94,14 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { myInterpreterList.setSdkCombo(mySdkCombo); myProjectSdksModel = myInterpreterList.getModel(); - myListener = new MyListener(this); - myProjectSdksModel.addListener(myListener); + mySdkModelListener = new MySdkModelListener(this); + myProjectSdksModel.addListener(mySdkModelListener); mySdkCombo.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { final Sdk selectedSdk = (Sdk)mySdkCombo.getSelectedItem(); - if (selectedSdk != null) - myPackagesPanel.updatePackages(new PyPackageManagementService(myProject, selectedSdk)); + myPackagesPanel.updatePackages(selectedSdk != null ? new PyPackageManagementService(myProject, selectedSdk) : null); } }); myDetailsCallback = new NullableConsumer() { @@ -154,7 +153,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { private void layoutPanel() { final GridBagLayout layout = new GridBagLayout(); - myPanel = new JPanel(layout); + myMainPanel = new JPanel(layout); final JLabel label = new JLabel("Project Interpreter:"); final JLabel label1 = new JLabel(" "); mySdkCombo = new ComboBox() { @@ -194,24 +193,24 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { c.gridx = 0; c.gridy = 0; - myPanel.add(label, c); + myMainPanel.add(label, c); c.gridx = 1; c.gridy = 0; c.weightx = 0.1; - myPanel.add(mySdkCombo, c); + myMainPanel.add(mySdkCombo, c); c.insets = new Insets(0,5,0,2); c.gridx = 2; c.gridy = 0; c.weightx = 0.0; - myPanel.add(myDetailsButton, c); + myMainPanel.add(myDetailsButton, c); c.insets = new Insets(2,2,2,2); c.gridx = 0; c.gridy = 1; c.gridwidth = 3; - myPanel.add(label1, c); + myMainPanel.add(label1, c); c.gridx = 0; c.gridy = 2; @@ -219,7 +218,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { c.gridwidth = 3; c.gridheight = GridBagConstraints.RELATIVE; c.fill = GridBagConstraints.BOTH; - myPanel.add(myPackagesPanel, c); + myMainPanel.add(myPackagesPanel, c); c.gridheight = GridBagConstraints.REMAINDER; c.gridx = 0; @@ -229,12 +228,12 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.SOUTH; - myPanel.add(notificationsComponent, c); + myMainPanel.add(notificationsComponent, c); } @Override public JComponent createComponent() { - return myPanel; + return myMainPanel; } @Override @@ -390,14 +389,14 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { @Override public void disposeUIResources() { - myProjectSdksModel.removeListener(myListener); + myProjectSdksModel.removeListener(mySdkModelListener); myInterpreterList.disposeModel(); } - private static class MyListener implements SdkModel.Listener { + private static class MySdkModelListener implements SdkModel.Listener { private final PyActiveSdkConfigurable myConfigurable; - public MyListener(PyActiveSdkConfigurable configurable) { + public MySdkModelListener(PyActiveSdkConfigurable configurable) { myConfigurable = configurable; } From 73c644ca7cbaecbbec041e3f7be9ca827d81cdd1 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Fri, 14 Feb 2014 18:46:42 +0400 Subject: [PATCH 33/39] cleanup --- .../configuration/PyActiveSdkConfigurable.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java index 561c1e40479d..c8091a1fe3f1 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java @@ -154,12 +154,11 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { private void layoutPanel() { final GridBagLayout layout = new GridBagLayout(); myMainPanel = new JPanel(layout); - final JLabel label = new JLabel("Project Interpreter:"); - final JLabel label1 = new JLabel(" "); + final JLabel interpreterLabel = new JLabel("Project Interpreter:"); + final JLabel emptyLabel = new JLabel(" "); mySdkCombo = new ComboBox() { @Override - public void setSelectedItem(Object item) - { + public void setSelectedItem(Object item) { if (SHOW_ALL.equals(item)) { PythonSdkDetailsDialog options = myModule == null ? new PythonSdkDetailsDialog(myProject, myDetailsCallback) : new PythonSdkDetailsDialog(myModule, myDetailsCallback); @@ -173,7 +172,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { mySdkCombo.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE); mySdkCombo.setRenderer(new SdkListCellRenderer("")); - PackagesNotificationPanel notificationsArea = new PackagesNotificationPanel(myProject); + final PackagesNotificationPanel notificationsArea = new PackagesNotificationPanel(myProject); final JComponent notificationsComponent = notificationsArea.getComponent(); notificationsComponent.setPreferredSize(new Dimension(500, 29)); @@ -193,7 +192,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { c.gridx = 0; c.gridy = 0; - myMainPanel.add(label, c); + myMainPanel.add(interpreterLabel, c); c.gridx = 1; c.gridy = 0; @@ -210,7 +209,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { c.gridx = 0; c.gridy = 1; c.gridwidth = 3; - myMainPanel.add(label1, c); + myMainPanel.add(emptyLabel, c); c.gridx = 0; c.gridy = 2; @@ -362,8 +361,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { boolean separator = true; boolean detectedSeparator = true; for (Sdk sdk : sdkList) { - if (!PythonSdkType.isVirtualEnv(sdk) && !PythonSdkType.isRemote(sdk) && - !(sdk instanceof PyDetectedSdk) && separator) { + if (!PythonSdkType.isVirtualEnv(sdk) && !PythonSdkType.isRemote(sdk) && !(sdk instanceof PyDetectedSdk) && separator) { items.add(PySdkListCellRenderer.SEPARATOR); separator = false; } @@ -384,6 +382,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { } mySdkCombo.setRenderer(new PySdkListCellRenderer()); + //noinspection unchecked mySdkCombo.setModel(new CollectionComboBoxModel(items, selection)); } From 5b60bc55ca52240b48a9c755b9499bd247a9c012 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Fri, 14 Feb 2014 18:50:23 +0400 Subject: [PATCH 34/39] cleanup --- .../configuration/PythonSdkDetailsDialog.java | 34 ++++--------------- 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java index 6ec5178b68d7..96d6000573b3 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java +++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java @@ -23,7 +23,6 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; -import com.intellij.openapi.projectRoots.ProjectJdkTable; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.SdkModel; import com.intellij.openapi.projectRoots.SdkModificator; @@ -55,10 +54,9 @@ import java.util.*; import java.util.List; public class PythonSdkDetailsDialog extends DialogWrapper { - private JPanel myPanel; + private JPanel myMainPanel; private JList mySdkList; private boolean mySdkListChanged = false; - private Sdk myAddedSdk; private final PyConfigurableInterpreterList myInterpreterList; private final ProjectSdksModel myProjectSdksModel; @@ -71,15 +69,10 @@ public class PythonSdkDetailsDialog extends DialogWrapper { private Set myModifiedModificators = new HashSet(); private final Project myProject; - private boolean myNewProject = false; private boolean myShowOtherProjectVirtualenvs = true; private final Module myModule; private NullableConsumer myShowMoreCallback; - public void setNewProject(final boolean newProject) { - myNewProject = newProject; - } - public PythonSdkDetailsDialog(Project project, NullableConsumer showMoreCallback) { super(project); myModule = null; @@ -110,6 +103,7 @@ public class PythonSdkDetailsDialog extends DialogWrapper { @Override protected JComponent createCenterPanel() { mySdkList = new JBList(); + //noinspection unchecked mySdkList.setCellRenderer(new PySdkListCellRenderer("", myModificators)); mySdkList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); @@ -140,10 +134,10 @@ public class PythonSdkDetailsDialog extends DialogWrapper { .addExtraAction(new GenerateSkeletonsButton()); decorator.setPreferredSize(new Dimension(600, 500)); - myPanel = decorator.createPanel(); + myMainPanel = decorator.createPanel(); refreshSdkList(); addListeners(); - return myPanel; + return myMainPanel; } private void addListeners() { @@ -193,12 +187,6 @@ public class PythonSdkDetailsDialog extends DialogWrapper { !myModifiedModificators.isEmpty(); } - @Nullable - private String getSelectedSdkName() { - final Sdk selectedSdk = (Sdk)mySdkList.getSelectedValue(); - return selectedSdk == null ? null : selectedSdk.getName(); - } - protected void updateOkButton() { super.setOKActionEnabled(isModified()); } @@ -224,16 +212,6 @@ public class PythonSdkDetailsDialog extends DialogWrapper { myShowMoreCallback.consume(getSelectedSdk()); } - /** - * Returns the stable copy of the SDK currently selected in the SDK table. - * - * @return the selected SDK, or null if there's no selection - */ - @Nullable - public Sdk getRealSelectedSdk() { - return ProjectJdkTable.getInstance().findJdk(getSelectedSdkName()); - } - @Nullable public Sdk getSelectedSdk() { return (Sdk)mySdkList.getSelectedValue(); @@ -246,6 +224,7 @@ public class PythonSdkDetailsDialog extends DialogWrapper { VirtualEnvProjectFilter.removeNotMatching(myProject, pythonSdks); } Collections.sort(pythonSdks, new PreferredSdkComparator()); + //noinspection unchecked mySdkList.setModel(new CollectionListModel(pythonSdks)); mySdkListChanged = false; @@ -277,10 +256,9 @@ public class PythonSdkDetailsDialog extends DialogWrapper { private void addCreatedSdk(@Nullable final Sdk sdk, boolean newVirtualEnv) { if (sdk != null) { - myAddedSdk = sdk; boolean isVirtualEnv = PythonSdkType.isVirtualEnv(sdk); if (isVirtualEnv && !newVirtualEnv) { - AddVEnvOptionsDialog dialog = new AddVEnvOptionsDialog(myPanel); + AddVEnvOptionsDialog dialog = new AddVEnvOptionsDialog(myMainPanel); dialog.show(); if (dialog.getExitCode() != DialogWrapper.OK_EXIT_CODE) { return; From d861a3ef8676d689c4a064ebb5d29a1dcac44742 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Fri, 14 Feb 2014 19:00:53 +0400 Subject: [PATCH 35/39] new project creation --- .../python/PythonSdkChooserCombo.java | 37 +++++++++++-------- .../PythonNewDirectoryProjectDialog.java | 9 +++++ 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/python/ide/src/com/jetbrains/python/PythonSdkChooserCombo.java b/python/ide/src/com/jetbrains/python/PythonSdkChooserCombo.java index a0d2fd08312b..b0790146e6f6 100644 --- a/python/ide/src/com/jetbrains/python/PythonSdkChooserCombo.java +++ b/python/ide/src/com/jetbrains/python/PythonSdkChooserCombo.java @@ -15,18 +15,21 @@ */ package com.jetbrains.python; -import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.SdkType; import com.intellij.openapi.projectRoots.impl.SdkListCellRenderer; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.IconLoader; import com.intellij.ui.CollectionComboBoxModel; import com.intellij.ui.ComboboxWithBrowseButton; +import com.intellij.util.NullableConsumer; import com.intellij.util.containers.ContainerUtil; -import com.jetbrains.python.configuration.PythonSdkConfigurable; -import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; +import com.jetbrains.python.configuration.PythonSdkDetailsDialog; +import com.jetbrains.python.sdk.PyDetectedSdk; import com.jetbrains.python.sdk.PythonSdkType; +import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.event.ActionEvent; @@ -39,10 +42,7 @@ import java.util.List; public class PythonSdkChooserCombo extends ComboboxWithBrowseButton { private final List myChangedListeners = ContainerUtil.createLockFreeCopyOnWriteList(); - //public PythonSdkChooserCombo(final Condition acceptableSdkCondition) { - // this(PythonSdkType.getAllSdks(), acceptableSdkCondition); - //} - + @SuppressWarnings("unchecked") public PythonSdkChooserCombo(final Project project, List sdks, final Condition acceptableSdkCondition) { Sdk initialSelection = null; for (Sdk sdk : sdks) { @@ -51,26 +51,30 @@ public class PythonSdkChooserCombo extends ComboboxWithBrowseButton { break; } } - getComboBox().setModel(new CollectionComboBoxModel(sdks, initialSelection)); - getComboBox().setRenderer(new SdkListCellRenderer("") { + final JComboBox comboBox = getComboBox(); + comboBox.setModel(new CollectionComboBoxModel(sdks, initialSelection)); + comboBox.setRenderer(new SdkListCellRenderer("") { @Override protected Icon getSdkIcon(Sdk sdk) { final PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(sdk); - return flavor != null ? flavor.getIcon() : ((SdkType)sdk.getSdkType()).getIcon(); + final Icon icon = flavor != null ? flavor.getIcon() : ((SdkType)sdk.getSdkType()).getIcon(); + return sdk instanceof PyDetectedSdk ? IconLoader.getTransparentIcon(icon) : icon; } }); addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - final PythonSdkConfigurable configurable = new PythonSdkConfigurable(project); - configurable.setNewProject(true); - ShowSettingsUtil.getInstance().editConfigurable(PythonSdkChooserCombo.this, configurable); - Sdk selection = configurable.getRealSelectedSdk(); final List sdks = PythonSdkType.getAllSdks(); - getComboBox().setModel(new CollectionComboBoxModel(sdks, selection)); + PythonSdkDetailsDialog dialog = new PythonSdkDetailsDialog(project, new NullableConsumer() { + @Override + public void consume(@Nullable Sdk sdk) { + comboBox.setModel(new CollectionComboBoxModel(sdks, sdk)); + } + }); + dialog.show(); notifyChanged(e); } }); - getComboBox().addActionListener(new ActionListener() { + comboBox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { notifyChanged(e); } @@ -83,6 +87,7 @@ public class PythonSdkChooserCombo extends ComboboxWithBrowseButton { } } + @SuppressWarnings("UnusedDeclaration") public void addChangedListener(ActionListener listener) { myChangedListeners.add(listener); } diff --git a/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectDialog.java b/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectDialog.java index 4b05b73434e1..d0b02f3c21bd 100644 --- a/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectDialog.java +++ b/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectDialog.java @@ -39,6 +39,7 @@ import com.jetbrains.python.packaging.PyPackageManagerImpl; import com.jetbrains.python.remote.PythonRemoteInterpreterManager; import com.jetbrains.python.remote.RemoteProjectSettings; import com.jetbrains.python.sdk.PreferredSdkComparator; +import com.jetbrains.python.sdk.PyDetectedSdk; import com.jetbrains.python.sdk.PythonSdkType; import com.jetbrains.python.sdk.flavors.JythonSdkFlavor; import com.jetbrains.python.sdk.flavors.PyPySdkFlavor; @@ -53,6 +54,7 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.Collection; import java.util.Collections; import java.util.List; @@ -70,6 +72,13 @@ public class PythonNewDirectoryProjectDialog extends NewDirectoryProjectDialog { myProject = project; final List sdks = PythonSdkType.getAllSdks(); + final List flavors = PythonSdkFlavor.getApplicableFlavors(); + for (PythonSdkFlavor flavor : flavors) { + final Collection strings = flavor.suggestHomePaths(); + for (String string : strings) { + sdks.add(new PyDetectedSdk(string)); + } + } VirtualEnvProjectFilter.removeAllAssociated(sdks); Collections.sort(sdks, PreferredSdkComparator.INSTANCE); final Sdk preferred = sdks.isEmpty() ? null : sdks.iterator().next(); From c57dbf5abc3209c1e21d7c3440446927f76a1c6c Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Fri, 14 Feb 2014 19:39:04 +0400 Subject: [PATCH 36/39] do call projectOpened callback in case of project exists but we want to create new on it's place Serves create project from existing sources->No. See NewDirectoryProjectAction --- .../com/intellij/platform/PlatformProjectOpenProcessor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/platform/PlatformProjectOpenProcessor.java b/platform/platform-impl/src/com/intellij/platform/PlatformProjectOpenProcessor.java index 1a655b8d1929..0e1087592934 100644 --- a/platform/platform-impl/src/com/intellij/platform/PlatformProjectOpenProcessor.java +++ b/platform/platform-impl/src/com/intellij/platform/PlatformProjectOpenProcessor.java @@ -189,7 +189,7 @@ public class PlatformProjectOpenProcessor extends ProjectOpenProcessor { if (project == null) return null; ProjectBaseDirectory.getInstance(project).setBaseDir(baseDir); - final Module module = runConfigurators ? runDirectoryProjectConfigurators(baseDir, project) : null; + final Module module = runConfigurators ? runDirectoryProjectConfigurators(baseDir, project) : ModuleManager.getInstance(project).getModules()[0]; openFileFromCommandLine(project, virtualFile, line); if (!projectManager.openProject(project)) { @@ -204,7 +204,7 @@ public class PlatformProjectOpenProcessor extends ProjectOpenProcessor { return project; } - if (callback != null && runConfigurators) { + if (callback != null) { callback.projectOpened(project, module); } From 3bb055a0eb924d5786bedcb5359e658fbc59f6f2 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Fri, 14 Feb 2014 19:56:46 +0400 Subject: [PATCH 37/39] create nwe project with detected sdk, get rid of PythonSdkConfigurable, create fixed isDjangoInstalled in create new django project --- .../configuration/PythonSdkConfigurable.form | 32 - .../configuration/PythonSdkConfigurable.java | 575 ------------------ .../PythonNewDirectoryProjectAction.java | 4 + python/src/META-INF/pycharm-core.xml | 1 - 4 files changed, 4 insertions(+), 608 deletions(-) delete mode 100644 python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.form delete mode 100644 python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.form b/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.form deleted file mode 100644 index b1a81e8c2a8a..000000000000 --- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.form +++ /dev/null @@ -1,32 +0,0 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java deleted file mode 100644 index ccfd0f588971..000000000000 --- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java +++ /dev/null @@ -1,575 +0,0 @@ -/* - * Copyright 2000-2013 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.configuration; - -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import com.intellij.icons.AllIcons; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; -import com.intellij.openapi.options.Configurable; -import com.intellij.openapi.options.ConfigurationException; -import com.intellij.openapi.project.DumbAware; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.projectRoots.*; -import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl; -import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil; -import com.intellij.openapi.roots.ModuleRootManager; -import com.intellij.openapi.roots.OrderRootType; -import com.intellij.openapi.roots.ProjectRootManager; -import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.ui.Splitter; -import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.remotesdk.RemoteCredentials; -import com.intellij.ui.*; -import com.intellij.ui.components.JBList; -import com.intellij.ui.components.JBTabbedPane; -import com.intellij.util.Consumer; -import com.intellij.util.NullableConsumer; -import com.intellij.util.NullableFunction; -import com.intellij.util.containers.FactoryMap; -import com.intellij.webcore.packaging.PackagesNotificationPanel; -import com.jetbrains.python.packaging.ui.PyInstalledPackagesPanel; -import com.jetbrains.python.packaging.ui.PyPackageManagementService; -import com.jetbrains.python.remote.PythonRemoteInterpreterManager; -import com.jetbrains.python.sdk.*; -import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; -import icons.PythonIcons; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; -import java.awt.*; -import java.util.*; -import java.util.List; - -public class PythonSdkConfigurable implements Configurable, Configurable.NoScroll { - private JPanel myPanel; - private JList mySdkList; - private JPanel mySplitterHolder; - private PackagesNotificationPanel myNotificationsArea; - private JPanel myNotificationsPlaceholder; - private PythonPathEditor myPathEditor; - private boolean mySdkListChanged = false; - private Sdk myAddedSdk; - private final PyConfigurableInterpreterList myInterpreterList; - private final ProjectSdksModel myProjectSdksModel; - private final PyInstalledPackagesPanel myPackagesPanel; - - private Map myModificators = new FactoryMap() { - @Override - protected SdkModificator create(Sdk sdk) { - return sdk.getSdkModificator(); - } - }; - private Set myModifiedModificators = new HashSet(); - private Sdk myPreviousSelection; - private boolean myFirstReset; - private final Project myProject; - - private boolean myNewProject = false; - private boolean myShowOtherProjectVirtualenvs = false; - - public void setNewProject(final boolean newProject) { - myNewProject = newProject; - } - - public PythonSdkConfigurable(Project project) { - myProject = project; - myInterpreterList = PyConfigurableInterpreterList.getInstance(myProject); - myProjectSdksModel = myInterpreterList.getModel(); - myFirstReset = true; - - - mySdkList = new JBList(); - mySdkList.setCellRenderer(new PySdkListCellRenderer("", myModificators)); - mySdkList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - - ToolbarDecorator decorator = ToolbarDecorator.createDecorator(mySdkList).disableUpDownActions() - .setAddAction(new AnActionButtonRunnable() { - @Override - public void run(AnActionButton button) { - addSdk(button); - } - }) - .setEditAction(new AnActionButtonRunnable() { - @Override - public void run(AnActionButton button) { - editSdk(); - } - }) - .setRemoveAction(new AnActionButtonRunnable() { - @Override - public void run(AnActionButton button) { - removeSdk(); - } - }) - .addExtraAction(new CreateVirtualEnvButton()) - .addExtraAction(new ToggleVirtualEnvFilterButton()); - - - final Splitter splitter = new Splitter(true); - /* - final JScrollPane sdkListPane = ScrollPaneFactory.createScrollPane(mySdkList, - ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, - ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); - sdkListPane.setPreferredSize(new Dimension(10, 10)); - */ - splitter.setFirstComponent(decorator.createPanel()); - - myPathEditor = - new PythonPathEditor("Classes", OrderRootType.CLASSES, FileChooserDescriptorFactory.createAllButJarContentsDescriptor()) { - @Override - protected void onReloadButtonClicked() { - reloadSdk(); - } - }; - - myNotificationsArea = new PackagesNotificationPanel(project); - myNotificationsPlaceholder.add(myNotificationsArea.getComponent(), BorderLayout.CENTER); - - final JBTabbedPane tabbedPane = new JBTabbedPane(SwingConstants.TOP); - myPackagesPanel = new PyInstalledPackagesPanel(project, myNotificationsArea); - tabbedPane.addTab("Packages", myPackagesPanel); - - JPanel panel1 = new JPanel(new GridBagLayout()); - Insets anInsets1 = new Insets(2, 2, 2, 2); - JScrollPane scrollPane1 = ScrollPaneFactory.createScrollPane(myPathEditor.createComponent(), - ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, - ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); - scrollPane1.setPreferredSize(new Dimension(500, 500)); - panel1.add(scrollPane1, new GridBagConstraints(0, 0, 1, 8, 1.0, 1.0, - GridBagConstraints.CENTER, - GridBagConstraints.BOTH, - anInsets1, 0, 0)); - - tabbedPane.addTab("Paths", panel1); - - splitter.setSecondComponent(tabbedPane); - mySplitterHolder.add(splitter, BorderLayout.CENTER); - - addListeners(); - } - - private void addListeners() { - myProjectSdksModel.addListener(new SdkModel.Listener() { - @Override - public void sdkAdded(Sdk sdk) { - } - - @Override - public void beforeSdkRemove(Sdk sdk) { - } - - @Override - public void sdkChanged(Sdk sdk, String previousName) { - refreshSdkList(); - } - - @Override - public void sdkHomeSelected(Sdk sdk, String newSdkHome) { - } - }); - myPackagesPanel.addPathChangedListener(new Consumer() { - @Override - public void consume(Sdk sdk) { - updateSdkPaths(sdk); - } - }); - - myNotificationsArea.addLinkHandler(PyInstalledPackagesPanel.CREATE_VENV, new Runnable() { - @Override - public void run() { - createVirtualEnv(getSelectedSdk()); - } - }); - mySdkList.addListSelectionListener(new ListSelectionListener() { - public void valueChanged(ListSelectionEvent event) { - updateUI(getSelectedSdk()); - } - }); - } - - private void updateUI(final Sdk selectedSdk) { - if (myPreviousSelection != null) { - saveSdkPaths(myPreviousSelection); - } - myProjectSdksModel.setProjectSdk(selectedSdk); - updateSdkPaths(selectedSdk); - myPreviousSelection = selectedSdk; - myPackagesPanel.updatePackages(selectedSdk == null ? null : new PyPackageManagementService(myProject, selectedSdk)); - - if (selectedSdk != null) { - myPackagesPanel.updateNotifications(selectedSdk); - } - } - - private void createVirtualEnv(Sdk sdk) { - CreateVirtualEnvDialog.VirtualEnvCallback callback = new CreateVirtualEnvDialog.VirtualEnvCallback() { - @Override - public void virtualEnvCreated(Sdk sdk, boolean associateWithProject) { - PythonSdkType.setupSdkPaths(sdk, myProject, null); - if (associateWithProject) { - SdkAdditionalData additionalData = sdk.getSdkAdditionalData(); - if (additionalData == null) { - additionalData = new PythonSdkAdditionalData(PythonSdkFlavor.getFlavor(sdk.getHomePath())); - ((ProjectJdkImpl)sdk).setSdkAdditionalData(additionalData); - } - if (myNewProject) { - ((PythonSdkAdditionalData)additionalData).associateWithNewProject(); - } - else { - ((PythonSdkAdditionalData)additionalData).associateWithProject(myProject); - } - } - addCreatedSdk(sdk, true); - } - }; - final List allSdks = PyConfigurableInterpreterList.getInstance(myProject).getAllPythonSdks(myProject); - final CreateVirtualEnvDialog dialog = new CreateVirtualEnvDialog(myProject, allSdks, sdk); - dialog.show(); - if (dialog.isOK()) { - dialog.createVirtualEnv(allSdks, callback); - } - } - - public String getDisplayName() { - return "Python Interpreters"; - } - - public String getHelpTopic() { - return "python_interpreter"; - } - - public JComponent createComponent() { - return myPanel; - } - - public boolean isModified() { - return mySdkListChanged || - myProjectSdksModel.isModified() || - myPathEditor.isModified() || - !myModifiedModificators.isEmpty(); - } - - @Nullable - private String getSelectedSdkName() { - final Sdk selectedSdk = (Sdk)mySdkList.getSelectedValue(); - return selectedSdk == null ? null : selectedSdk.getName(); - } - - public void apply() throws ConfigurationException { - if (myPreviousSelection != null) { - saveSdkPaths(myPreviousSelection); - } - for (SdkModificator modificator : myModifiedModificators) { - modificator.commitChanges(); - } - myModificators.clear(); - myModifiedModificators.clear(); - myProjectSdksModel.apply(); - mySdkListChanged = false; - SdkConfigurationUtil.setDirectoryProjectSdk(myProject, myAddedSdk); - myProjectSdksModel.setProjectSdk(myAddedSdk); - myInterpreterList.setSelectedSdk(myAddedSdk); - } - - /** - * Returns the stable copy of the SDK currently selected in the SDK table. - * - * @return the selected SDK, or null if there's no selection - */ - @Nullable - public Sdk getRealSelectedSdk() { - return ProjectJdkTable.getInstance().findJdk(getSelectedSdkName()); - } - - @Nullable - public Sdk getSelectedSdk() { - return (Sdk)mySdkList.getSelectedValue(); - } - - public void reset() { - clearModificators(); - if (myFirstReset) { - myFirstReset = false; - } - else { - myProjectSdksModel.reset(null); - } - refreshSdkList(); - final Sdk selectedSdk = getRealSelectedSdk(); - if (selectedSdk != null) { - myPackagesPanel.updateNotifications(selectedSdk); - } - } - - private void clearModificators() { - myModificators.clear(); - myModifiedModificators.clear(); - myPreviousSelection = null; - } - - private void refreshSdkList() { - final List pythonSdks = myInterpreterList.getAllPythonSdks(myProject); - Sdk projectSdk = myProjectSdksModel.getProjectSdk(); - if (!myShowOtherProjectVirtualenvs) { - VirtualEnvProjectFilter.removeNotMatching(myProject, pythonSdks); - } - Collections.sort(pythonSdks, new PreferredSdkComparator()); - mySdkList.setModel(new CollectionListModel(pythonSdks)); - - mySdkListChanged = false; - if (projectSdk == null) projectSdk = getSdk(); - if (projectSdk != null) { - projectSdk = myProjectSdksModel.findSdk(projectSdk.getName()); - mySdkList.clearSelection(); - mySdkList.setSelectedValue(projectSdk, true); - mySdkList.updateUI(); - } - } - - @Nullable - private Sdk getSdk() { - final Module[] modules = ModuleManager.getInstance(myProject).getModules(); - if (modules.length > 0) { - final Module module = modules[0]; - final ModuleRootManager rootManager = ModuleRootManager.getInstance(module); - return rootManager.getSdk(); - } - return ProjectRootManager.getInstance(myProject).getProjectSdk(); - } - - private void addSdk(AnActionButton button) { - PythonSdkDetailsStep - .show(myProject, myProjectSdksModel.getSdks(), new PythonSdkDetailsDialog(myProject, null), button.getPreferredPopupPoint(), false, - new NullableConsumer() { - @Override - public void consume(Sdk sdk) { - addCreatedSdk(sdk, false); - } - }); - } - - private void addCreatedSdk(@Nullable final Sdk sdk, boolean newVirtualEnv) { - if (sdk != null) { - myAddedSdk = sdk; - boolean isVirtualEnv = PythonSdkType.isVirtualEnv(sdk); - if (isVirtualEnv && !newVirtualEnv) { - AddVEnvOptionsDialog dialog = new AddVEnvOptionsDialog(myPanel); - dialog.show(); - if (dialog.getExitCode() != DialogWrapper.OK_EXIT_CODE) { - return; - } - SdkModificator modificator = myModificators.get(sdk); - setSdkAssociated(modificator, !dialog.makeAvailableToAll()); - myModifiedModificators.add(modificator); - } - myProjectSdksModel.addSdk(sdk); - refreshSdkList(); - mySdkList.setSelectedValue(sdk, true); - mySdkListChanged = true; - } - } - - private void editSdk() { - final Sdk currentSdk = getSelectedSdk(); - if (currentSdk != null) { - if (currentSdk.getSdkAdditionalData() instanceof RemoteCredentials) { - editRemoteSdk(currentSdk); - } - else { - editSdk(currentSdk); - } - updateUI(currentSdk); - } - } - - private void editRemoteSdk(Sdk currentSdk) { - PythonRemoteInterpreterManager remoteInterpreterManager = PythonRemoteInterpreterManager.getInstance(); - if (remoteInterpreterManager != null) { - final SdkModificator modificator = myModificators.get(currentSdk); - Set existingSdks = Sets.newHashSet(myProjectSdksModel.getSdks()); - existingSdks.remove(currentSdk); - if (remoteInterpreterManager.editSdk(myProject, modificator, existingSdks)) { - myModifiedModificators.add(modificator); - } - } - } - - private void editSdk(final Sdk currentSdk) { - final SdkModificator modificator = myModificators.get(currentSdk); - final EditSdkDialog dialog = new EditSdkDialog(myProject, modificator, new NullableFunction() { - @Override - public String fun(String s) { - if (isDuplicateSdkName(s, currentSdk)) { - return "Please specify a unique name for the interpreter"; - } - return null; - } - }); - dialog.show(); - if (dialog.isOK()) { - final boolean pathChanged = !Comparing.equal(currentSdk.getHomePath(), dialog.getHomePath()); - if (!currentSdk.getName().equals(dialog.getName()) || pathChanged || dialog.isAssociateChanged()) { - myModifiedModificators.add(modificator); - modificator.setName(dialog.getName()); - modificator.setHomePath(dialog.getHomePath()); - - if (dialog.isAssociateChanged()) { - setSdkAssociated(modificator, dialog.associateWithProject()); - } - if (pathChanged) { - reloadSdk(currentSdk); - } - } - } - } - - private void setSdkAssociated(SdkModificator modificator, boolean isAssociated) { - PythonSdkAdditionalData additionalData = (PythonSdkAdditionalData)modificator.getSdkAdditionalData(); - if (additionalData == null) { - additionalData = new PythonSdkAdditionalData(PythonSdkFlavor.getFlavor(modificator.getHomePath())); - modificator.setSdkAdditionalData(additionalData); - } - if (isAssociated) { - additionalData.associateWithProject(myProject); - } - else { - additionalData.setAssociatedProjectPath(null); - } - } - - private boolean isDuplicateSdkName(String s, Sdk sdk) { - for (Sdk existingSdk : myProjectSdksModel.getSdks()) { - if (existingSdk == sdk) { - continue; - } - String existingName; - if (myModificators.containsKey(existingSdk)) { - existingName = myModificators.get(existingSdk).getName(); - } - else { - existingName = existingSdk.getName(); - } - if (existingName.equals(s)) { - return true; - } - } - return false; - } - - private void removeSdk() { - final Sdk current_sdk = getSelectedSdk(); - if (current_sdk != null) { - myProjectSdksModel.removeSdk(current_sdk); - if (myModificators.containsKey(current_sdk)) { - SdkModificator modificator = myModificators.get(current_sdk); - myModifiedModificators.remove(modificator); - myModificators.remove(current_sdk); - } - refreshSdkList(); - mySdkListChanged = true; - // TODO select initially selected SDK - if (mySdkList.getSelectedIndex() < 0) { - mySdkList.setSelectedIndex(0); - } - } - } - - private void reloadSdk() { - final Sdk currentSdk = getSelectedSdk(); - if (currentSdk != null) { - myModifiedModificators.add(myModificators.get(currentSdk)); - reloadSdk(currentSdk); - } - } - - private void reloadSdk(Sdk currentSdk) { - PythonSdkType.setupSdkPaths(myProject, null, currentSdk, myModificators.get(currentSdk)); // or must it be a RunWriteAction? - reloadSdkPaths(currentSdk); - } - - public void disposeUIResources() { - myInterpreterList.disposeModel(); - clearModificators(); - myFirstReset = true; - } - - private void saveSdkPaths(Sdk selection) { - SdkModificator modificator = myModificators.get(selection); - if (myPathEditor.isModified()) { - myPathEditor.apply(modificator); - myModifiedModificators.add(modificator); - } - } - - private void reloadSdkPaths(Sdk selection) { - List rootPaths = Lists.newArrayList(); - if (selection != null) { - Collections.addAll(rootPaths, selection.getRootProvider().getFiles(OrderRootType.CLASSES)); - myPathEditor.reload(myModificators.get(selection)); - } - else { - myPathEditor.reload(null); - } - } - - private void updateSdkPaths(final Sdk selection) { - final List rootPaths = Lists.newArrayList(); - if (selection != null) { - Collections.addAll(rootPaths, selection.getRootProvider().getFiles(OrderRootType.CLASSES)); - myPathEditor.reset(myModificators.get(selection)); - } - else { - myPathEditor.reset(null); - } - } - - private class CreateVirtualEnvButton extends AnActionButton implements DumbAware { - public CreateVirtualEnvButton() { - super("Create Virtual Environment", PythonIcons.Python.Virtualenv); - } - - @Override - public void actionPerformed(AnActionEvent e) { - Sdk selectedSdk = getSelectedSdk(); - createVirtualEnv(selectedSdk); - } - } - - private class ToggleVirtualEnvFilterButton extends ToggleActionButton implements DumbAware { - public ToggleVirtualEnvFilterButton() { - super("Show virtual environments associated with other projects", AllIcons.General.Filter); - } - - @Override - public boolean isSelected(AnActionEvent e) { - return myShowOtherProjectVirtualenvs; - } - - @Override - public void setSelected(AnActionEvent e, boolean state) { - myShowOtherProjectVirtualenvs = state; - refreshSdkList(); - } - } -} diff --git a/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectAction.java b/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectAction.java index 4496b6d4d854..4d638eee4101 100644 --- a/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectAction.java +++ b/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectAction.java @@ -27,6 +27,7 @@ import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.platform.DirectoryProjectGenerator; import com.intellij.platform.NewDirectoryProjectAction; +import com.jetbrains.python.sdk.PyDetectedSdk; import com.jetbrains.python.sdk.PythonSdkAdditionalData; import com.jetbrains.python.sdk.PythonSdkType; @@ -48,6 +49,9 @@ public class PythonNewDirectoryProjectAction extends NewDirectoryProjectAction { dlg.show(); if (dlg.getExitCode() != DialogWrapper.OK_EXIT_CODE) return; mySdk = dlg.getSdk(); + if (mySdk instanceof PyDetectedSdk) { + mySdk = SdkConfigurationUtil.createAndAddSDK(mySdk.getName(), PythonSdkType.getInstance()); + } myInstallFramework = dlg.installFramework(); Project newProject = generateProject(project, dlg); if (newProject != null) { diff --git a/python/src/META-INF/pycharm-core.xml b/python/src/META-INF/pycharm-core.xml index 7a4a9c694cda..0c1457d48049 100644 --- a/python/src/META-INF/pycharm-core.xml +++ b/python/src/META-INF/pycharm-core.xml @@ -31,7 +31,6 @@ - From c67953e08212983d36bd8a6d761ff7bc43f20fd8 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Fri, 14 Feb 2014 20:05:45 +0400 Subject: [PATCH 38/39] don't add nulls to project sdks --- .../python/configuration/PyActiveSdkConfigurable.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java index c8091a1fe3f1..0b04517dadba 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java @@ -267,11 +267,15 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { } }, ModalityState.any()); } - if (myAddedSdk != null) { + if (item != null) { myProjectSdksModel.addSdk(item); myProjectSdksModel.apply(null, true); mySdkCombo.setSelectedItem(item); } + else if (myAddedSdk != null) { + myProjectSdksModel.apply(null, true); + } + final Sdk prevSdk = ProjectRootManager.getInstance(myProject).getProjectSdk(); final Sdk selectedSdk = setSdk(item); From bb44a3d8a7d71d77ec425ee1533a690f4af0b1d5 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Fri, 14 Feb 2014 20:32:57 +0400 Subject: [PATCH 39/39] put sdks to create new project interpreter combobox properly --- .../PyConfigurableInterpreterList.java | 9 +++++++-- .../PythonNewDirectoryProjectDialog.java | 15 ++------------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java b/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java index 0260c8e7edc2..87b9163eb824 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java @@ -28,6 +28,7 @@ import com.jetbrains.python.sdk.PythonSdkAdditionalData; import com.jetbrains.python.sdk.PythonSdkType; import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; import com.jetbrains.python.sdk.flavors.VirtualEnvSdkFlavor; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.*; @@ -69,7 +70,7 @@ public class PyConfigurableInterpreterList { } } - public List getAllPythonSdks(final Project project) { + public List getAllPythonSdks(@Nullable final Project project) { List result = new ArrayList(); for (Sdk sdk : getModel().getSdks()) { if (sdk.getSdkType() instanceof PythonSdkType) { @@ -94,7 +95,7 @@ public class PyConfigurableInterpreterList { final LanguageLevel level2 = flavor2 != null ? flavor2.getLanguageLevel(o2) : LanguageLevel.getDefault(); if (isVEnv1) { - if (associatedWithCurrent(o1, project)) return -1; + if (project != null && associatedWithCurrent(o1, project)) return -1; if (isVEnv2) { final int compare = Comparing.compare(level1, level2); if (compare != 0) return -compare; @@ -138,4 +139,8 @@ public class PyConfigurableInterpreterList { } return false; } + + public List getAllPythonSdks() { + return getAllPythonSdks(null); + } } diff --git a/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectDialog.java b/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectDialog.java index d0b02f3c21bd..8db6add9d056 100644 --- a/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectDialog.java +++ b/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectDialog.java @@ -31,6 +31,7 @@ import com.intellij.ui.ComboboxWithBrowseButton; import com.intellij.ui.components.JBCheckBox; import com.intellij.ui.components.JBLabel; import com.jetbrains.python.PythonSdkChooserCombo; +import com.jetbrains.python.configuration.PyConfigurableInterpreterList; import com.jetbrains.python.configuration.VirtualEnvProjectFilter; import com.jetbrains.python.packaging.PyExternalProcessException; import com.jetbrains.python.packaging.PyPackage; @@ -38,8 +39,6 @@ import com.jetbrains.python.packaging.PyPackageManager; import com.jetbrains.python.packaging.PyPackageManagerImpl; import com.jetbrains.python.remote.PythonRemoteInterpreterManager; import com.jetbrains.python.remote.RemoteProjectSettings; -import com.jetbrains.python.sdk.PreferredSdkComparator; -import com.jetbrains.python.sdk.PyDetectedSdk; import com.jetbrains.python.sdk.PythonSdkType; import com.jetbrains.python.sdk.flavors.JythonSdkFlavor; import com.jetbrains.python.sdk.flavors.PyPySdkFlavor; @@ -54,8 +53,6 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.util.Collection; -import java.util.Collections; import java.util.List; /** @@ -71,16 +68,8 @@ public class PythonNewDirectoryProjectDialog extends NewDirectoryProjectDialog { super(project); myProject = project; - final List sdks = PythonSdkType.getAllSdks(); - final List flavors = PythonSdkFlavor.getApplicableFlavors(); - for (PythonSdkFlavor flavor : flavors) { - final Collection strings = flavor.suggestHomePaths(); - for (String string : strings) { - sdks.add(new PyDetectedSdk(string)); - } - } + final List sdks = PyConfigurableInterpreterList.getInstance(myProject).getAllPythonSdks(); VirtualEnvProjectFilter.removeAllAssociated(sdks); - Collections.sort(sdks, PreferredSdkComparator.INSTANCE); final Sdk preferred = sdks.isEmpty() ? null : sdks.iterator().next(); mySdkCombo = new PythonSdkChooserCombo(project, sdks, new Condition() { @Override