diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyNewProjectPanel.form b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyNewProjectPanel.form
deleted file mode 100644
index c13bc229b973..000000000000
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyNewProjectPanel.form
+++ /dev/null
@@ -1,103 +0,0 @@
-
-
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyNewProjectPanel.java b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyNewProjectPanel.java
index 352a9613d9a1..2ef3e8d152f5 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyNewProjectPanel.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyNewProjectPanel.java
@@ -4,7 +4,6 @@ import com.intellij.facet.ui.FacetValidatorsManager;
import com.intellij.facet.ui.ValidationResult;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.progress.ProgressManager;
@@ -12,6 +11,7 @@ import com.intellij.openapi.project.DefaultProjectFactory;
import com.intellij.openapi.project.DefaultProjectFactoryImpl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
+import com.intellij.openapi.ui.*;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.openapi.ui.popup.PopupStep;
@@ -19,15 +19,17 @@ import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.AncestorListenerAdapter;
+import com.intellij.ui.JBColor;
+import com.intellij.ui.PanelWithAnchor;
import com.jetbrains.edu.learning.StudyUtils;
import com.jetbrains.edu.learning.courseFormat.Course;
import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator;
import com.jetbrains.edu.learning.stepic.CourseInfo;
import com.jetbrains.edu.learning.stepic.EduStepicConnector;
-import com.jetbrains.edu.learning.stepic.LoginDialog;
import com.jetbrains.edu.learning.stepic.StepicUser;
import icons.InteractiveLearningIcons;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.AncestorEvent;
@@ -41,39 +43,38 @@ import java.util.List;
* author: liana
* data: 7/31/14.
*/
-public class StudyNewProjectPanel {
- private static final Logger LOG = Logger.getInstance(StudyNewProjectPanel.class);
- private final String LOGIN_TO_STEPIC = "Login to Stepic";
+public class StudyNewProjectPanel extends JPanel implements PanelWithAnchor {
private List myAvailableCourses = new ArrayList();
private JButton myBrowseButton;
- private JComboBox myCoursesComboBox;
+ private ComboBox myCoursesComboBox;
private JButton myRefreshButton;
- private JPanel myContentPanel;
private JLabel myAuthorLabel;
- private JLabel myLabel;
private JPanel myInfoPanel;
- private JTextPane myDescriptionLabel;
+ private JTextPane myDescriptionPane;
+ private JComponent myAnchor;
private final StudyProjectGenerator myGenerator;
private static final String CONNECTION_ERROR = "Failed to download courses.
Check your Internet connection.";
private static final String INVALID_COURSE = "Selected course is invalid";
private FacetValidatorsManager myValidationManager;
private boolean isComboboxInitialized;
- private String LOGIN_TO_STEPIC_MESSAGE = "Login to Stepic to open the adaptive course ";;
+ private static final String LOGIN_TO_STEPIC_MESSAGE = "Login to Stepic to open the adaptive course ";
+ private static final String LOGIN_TO_STEPIC = "Login to Stepic";
public StudyNewProjectPanel(@NotNull final StudyProjectGenerator generator) {
+ super(new VerticalFlowLayout());
+ layoutPanel();
+
+ myAnchor = myCoursesComboBox;
myGenerator = generator;
- myBrowseButton.setPreferredSize(new Dimension(28, 28));
- myRefreshButton.setPreferredSize(new Dimension(28, 28));
initListeners();
myRefreshButton.setVisible(true);
- myRefreshButton.putClientProperty("JButton.buttonType", "null");
+
myRefreshButton.setIcon(AllIcons.Actions.Refresh);
- myLabel.setPreferredSize(new JLabel("Project name").getPreferredSize());
- myContentPanel.addAncestorListener(new AncestorListenerAdapter() {
+ addAncestorListener(new AncestorListenerAdapter() {
@Override
public void ancestorMoved(AncestorEvent event) {
- if (!isComboboxInitialized && myContentPanel.isVisible()) {
+ if (!isComboboxInitialized && isVisible()) {
isComboboxInitialized = true;
initCoursesCombobox();
}
@@ -81,6 +82,34 @@ public class StudyNewProjectPanel {
});
}
+ private void layoutPanel() {
+ myCoursesComboBox = new ComboBox();
+ final LabeledComponent coursesCombo = LabeledComponent.create(myCoursesComboBox, "Courses:", BorderLayout.WEST);
+ add(coursesCombo);
+
+ myRefreshButton = new FixedSizeButton(coursesCombo);
+ myBrowseButton = new FixedSizeButton(coursesCombo);
+
+ final JPanel panel = new JPanel(new BorderLayout());
+ final JLabel invisibleLabel = new JLabel();
+ invisibleLabel.setPreferredSize(new JLabel("Location: ").getPreferredSize());
+ panel.add(invisibleLabel, BorderLayout.WEST);
+
+ myInfoPanel = new JPanel(new VerticalFlowLayout());
+ myAuthorLabel = new JLabel();
+ myDescriptionPane = new JTextPane();
+ myDescriptionPane.setEditable(true);
+ myDescriptionPane.setEnabled(true);
+ myAuthorLabel.setEnabled(true);
+ myDescriptionPane.setPreferredSize(new Dimension(150, 100));
+ myInfoPanel.add(myAuthorLabel);
+ myInfoPanel.add(myDescriptionPane);
+ myInfoPanel.setBorder(BorderFactory.createLineBorder(new JBColor(10067616, 10067616)));
+
+ panel.add(myInfoPanel, BorderLayout.CENTER);
+ add(panel);
+ }
+
private void initCoursesCombobox() {
myAvailableCourses =
myGenerator.getCoursesUnderProgress(false, "Getting Available Courses", ProjectManager.getInstance().getDefaultProject());
@@ -92,11 +121,11 @@ public class StudyNewProjectPanel {
final CourseInfo selectedCourse = StudyUtils.getFirst(myAvailableCourses);
final String authorsString = Course.getAuthorsString(selectedCourse.getAuthors());
myAuthorLabel.setText(!StringUtil.isEmptyOrSpaces(authorsString) ? "Author: " + authorsString : "");
- myDescriptionLabel.setText(selectedCourse.getDescription());
- myDescriptionLabel.setEditable(false);
+ myDescriptionPane.setText(selectedCourse.getDescription());
+ myDescriptionPane.setEditable(false);
//setting the first course in list as selected
myGenerator.setSelectedCourse(selectedCourse);
-
+
if (selectedCourse.isAdaptive() && !myGenerator.isLoggedIn()) {
setError(LOGIN_TO_STEPIC_MESSAGE);
}
@@ -107,7 +136,6 @@ public class StudyNewProjectPanel {
}
private void setupBrowseButton() {
- myBrowseButton.putClientProperty("JButton.buttonType", "null");
myBrowseButton.setIcon(InteractiveLearningIcons.InterpreterGear);
final FileChooserDescriptor fileChooser = new FileChooserDescriptor(true, false, false, true, false, false) {
@Override
@@ -188,15 +216,19 @@ public class StudyNewProjectPanel {
myValidationManager.validate();
}
}
-
- public JPanel getContentPanel() {
- return myContentPanel;
- }
-
public void registerValidators(final FacetValidatorsManager manager) {
myValidationManager = manager;
}
+ @Override
+ public JComponent getAnchor() {
+ return myAnchor;
+ }
+
+ @Override
+ public void setAnchor(@Nullable JComponent anchor) {
+ myAnchor = anchor;
+ }
/**
* Handles refreshing courses
@@ -248,14 +280,14 @@ public class StudyNewProjectPanel {
CourseInfo selectedCourse = (CourseInfo)cb.getSelectedItem();
if (selectedCourse == null || selectedCourse.equals(CourseInfo.INVALID_COURSE)) {
myAuthorLabel.setText("");
- myDescriptionLabel.setText("");
+ myDescriptionPane.setText("");
setError(INVALID_COURSE);
return;
}
final String authorsString = Course.getAuthorsString(selectedCourse.getAuthors());
myAuthorLabel.setText(!StringUtil.isEmptyOrSpaces(authorsString) ? "Author: " + authorsString : "");
myCoursesComboBox.removeItem(CourseInfo.INVALID_COURSE);
- myDescriptionLabel.setText(selectedCourse.getDescription());
+ myDescriptionPane.setText(selectedCourse.getDescription());
myGenerator.setSelectedCourse(selectedCourse);
setOK();
@@ -275,25 +307,49 @@ public class StudyNewProjectPanel {
return myInfoPanel;
}
- private class AddRemoteDialog extends LoginDialog {
+ private class AddRemoteDialog extends DialogWrapper {
+
+ private final StudyAddRemoteCourse myRemoteCourse;
protected AddRemoteDialog() {
- super();
+ super(null);
+ setTitle("Login To Stepic");
+ myRemoteCourse = new StudyAddRemoteCourse();
+ init();
+ }
+
+ @Nullable
+ @Override
+ protected JComponent createCenterPanel() {
+ return myRemoteCourse.getContentPanel();
+ }
+
+ @Nullable
+ @Override
+ public JComponent getPreferredFocusedComponent() {
+ return myRemoteCourse.getLoginField();
}
@Override
protected void doOKAction() {
- if (!validateLoginAndPasswordFields()) return;
- super.doJustOkAction();
+ super.doOKAction();
+ if (StringUtil.isEmptyOrSpaces(myRemoteCourse.getLogin())) {
+ myRemoteCourse.setError("Please, enter your login");
+ return;
+ }
+ if (StringUtil.isEmptyOrSpaces(myRemoteCourse.getPassword())) {
+ myRemoteCourse.setError("Please, enter your password");
+ return;
+ }
ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> {
ProgressManager.getInstance().getProgressIndicator().setIndeterminate(true);
- final StepicUser stepicUser = StudyUtils.execCancelable(() -> EduStepicConnector.login(myLoginPanel.getLogin(),
- myLoginPanel.getPassword()));
+ final StepicUser stepicUser = StudyUtils.execCancelable(() -> EduStepicConnector.login(myRemoteCourse.getLogin(),
+ myRemoteCourse.getPassword()));
if (stepicUser != null) {
- stepicUser.setEmail(myLoginPanel.getLogin());
- stepicUser.setPassword(myLoginPanel.getPassword());
+ stepicUser.setEmail(myRemoteCourse.getLogin());
+ stepicUser.setPassword(myRemoteCourse.getPassword());
myGenerator.myUser = stepicUser;
myGenerator.setEnrolledCoursesIds(EduStepicConnector.getEnrolledCoursesIds());
@@ -306,6 +362,6 @@ public class StudyNewProjectPanel {
setError("Failed to login");
}
}, "Signing In And Getting Stepic Course List", true, new DefaultProjectFactoryImpl().getDefaultProject());
- }
+ }
}
}
diff --git a/python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyDirectoryProjectGenerator.java b/python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyDirectoryProjectGenerator.java
index be783451faab..5c302e4247f5 100644
--- a/python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyDirectoryProjectGenerator.java
+++ b/python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyDirectoryProjectGenerator.java
@@ -14,7 +14,6 @@ import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.projectRoots.Sdk;
-import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.platform.DirectoryProjectGenerator;
import com.intellij.psi.PsiDirectory;
@@ -24,6 +23,7 @@ import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator;
import com.jetbrains.edu.learning.stepic.CourseInfo;
import com.jetbrains.edu.learning.stepic.EduStepicConnector;
import com.jetbrains.edu.learning.ui.StudyNewProjectPanel;
+import com.jetbrains.python.configuration.PyConfigurableInterpreterList;
import com.jetbrains.python.newProject.PythonProjectGenerator;
import icons.InteractiveLearningPythonIcons;
import org.jetbrains.annotations.Nls;
@@ -40,6 +40,7 @@ import java.util.List;
public class PyStudyDirectoryProjectGenerator extends PythonProjectGenerator implements DirectoryProjectGenerator {
private static final Logger LOG = Logger.getInstance(PyStudyDirectoryProjectGenerator.class.getName());
private final StudyProjectGenerator myGenerator;
+ private static final String NO_PYTHON_INTERPRETER = "Add python interpreter.";
public ValidationResult myValidationResult = new ValidationResult("selected course is not valid");
private StudyNewProjectPanel mySettingsPanel;
@@ -115,10 +116,16 @@ public class PyStudyDirectoryProjectGenerator extends PythonProjectGenerator imp
LOG.error("Can't copy test_helper.py " + exception.getMessage());
}
}
-
+
@NotNull
@Override
public ValidationResult validate(@NotNull String s) {
+ final Project project = ProjectManager.getInstance().getDefaultProject();
+ final List sdks = PyConfigurableInterpreterList.getInstance(project).getAllPythonSdks();
+ if (sdks.isEmpty()) {
+ myValidationResult = new ValidationResult(NO_PYTHON_INTERPRETER);
+ }
+
return myValidationResult;
}
@@ -129,7 +136,7 @@ public class PyStudyDirectoryProjectGenerator extends PythonProjectGenerator imp
@Nullable
@Override
public JPanel extendBasePanel() throws ProcessCanceledException {
- return mySettingsPanel.getContentPanel();
+ return mySettingsPanel;
}
public List getCourses() {
@@ -144,26 +151,25 @@ public class PyStudyDirectoryProjectGenerator extends PythonProjectGenerator imp
return myGenerator;
}
+ @Override
+ public boolean hideInterpreter() {
+ return true;
+ }
+
@Nullable
@Override
- public BooleanFunction beforeProjectGenerated(@NotNull Sdk sdk) {
- return new BooleanFunction() {
- @Override
- public boolean fun(PythonProjectGenerator generator) {
- final List enrolledCoursesIds = myGenerator.getEnrolledCoursesIds();
- final CourseInfo course = (CourseInfo)mySettingsPanel.getCoursesComboBox().getSelectedItem();
- if (course.isAdaptive() && !enrolledCoursesIds.contains(course.getId())) {
- ProgressManager.getInstance().runProcessWithProgressSynchronously(new ThrowableComputable() {
- @Override
- public Boolean compute() throws RuntimeException {
- ProgressManager.getInstance().getProgressIndicator().setIndeterminate(true);
- return StudyUtils.execCancelable(() -> EduStepicConnector.enrollToCourse(course.getId()));
- }
- }, "Creating Course", true, ProjectManager.getInstance().getDefaultProject());
-
- }
- return true;
+ public BooleanFunction beforeProjectGenerated(@Nullable Sdk sdk) {
+ return generator -> {
+ final List enrolledCoursesIds = myGenerator.getEnrolledCoursesIds();
+ final CourseInfo course = (CourseInfo)mySettingsPanel.getCoursesComboBox().getSelectedItem();
+ if (course.isAdaptive() && !enrolledCoursesIds.contains(course.getId())) {
+ ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> {
+ ProgressManager.getInstance().getProgressIndicator().setIndeterminate(true);
+ return StudyUtils.execCancelable(() -> EduStepicConnector.enrollToCourse(course.getId()));
+ }, "Creating Course", true, ProjectManager.getInstance().getDefaultProject());
+
}
+ return true;
};
}
}
diff --git a/python/educational-python/student-python/src/com/jetbrains/edu/learning/actions/PyStudyIntroductionCourseAction.java b/python/educational-python/student-python/src/com/jetbrains/edu/learning/actions/PyStudyIntroductionCourseAction.java
index eb936e082c51..de28c8314560 100644
--- a/python/educational-python/student-python/src/com/jetbrains/edu/learning/actions/PyStudyIntroductionCourseAction.java
+++ b/python/educational-python/student-python/src/com/jetbrains/edu/learning/actions/PyStudyIntroductionCourseAction.java
@@ -19,12 +19,8 @@ import com.intellij.ide.impl.ProjectUtil;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.Presentation;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.project.ProjectManager;
-import com.intellij.openapi.projectRoots.Sdk;
import com.jetbrains.edu.learning.PyStudyDirectoryProjectGenerator;
import com.jetbrains.edu.learning.stepic.CourseInfo;
-import com.jetbrains.python.configuration.PyConfigurableInterpreterList;
import com.jetbrains.python.newProject.actions.GenerateProjectCallback;
import com.jetbrains.python.newProject.actions.ProjectSpecificSettingsStep;
import icons.InteractiveLearningPythonIcons;
@@ -76,10 +72,6 @@ public class PyStudyIntroductionCourseAction extends AnAction {
step.setLocation(projectDir.toString());
generator.setSelectedCourse(introCourse);
- final Project project = ProjectManager.getInstance().getDefaultProject();
- final List sdks = PyConfigurableInterpreterList.getInstance(project).getAllPythonSdks();
- Sdk sdk = sdks.isEmpty() ? null : sdks.iterator().next();
- step.setSdk(sdk);
callback.consume(step);
}
}
diff --git a/python/ide/src/com/jetbrains/python/newProject/actions/GenerateProjectCallback.java b/python/ide/src/com/jetbrains/python/newProject/actions/GenerateProjectCallback.java
index 51285a044a78..fdac01bed22d 100644
--- a/python/ide/src/com/jetbrains/python/newProject/actions/GenerateProjectCallback.java
+++ b/python/ide/src/com/jetbrains/python/newProject/actions/GenerateProjectCallback.java
@@ -15,6 +15,7 @@
*/
package com.jetbrains.python.newProject.actions;
+import com.intellij.execution.ExecutionException;
import com.intellij.ide.util.projectWizard.AbstractNewProjectStep;
import com.intellij.ide.util.projectWizard.ProjectSettingsStepBase;
import com.intellij.ide.util.projectWizard.WebProjectTemplate;
@@ -36,10 +37,13 @@ import com.intellij.util.NullableConsumer;
import com.jetbrains.python.configuration.PyConfigurableInterpreterList;
import com.jetbrains.python.newProject.PyNewProjectSettings;
import com.jetbrains.python.newProject.PythonProjectGenerator;
+import com.jetbrains.python.packaging.PyPackageManager;
import com.jetbrains.python.sdk.*;
+import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.util.Collection;
import java.util.List;
public class GenerateProjectCallback implements NullableConsumer {
@@ -50,34 +54,17 @@ public class GenerateProjectCallback implements NullableConsumer() {
- @Override
- public VirtualFile compute() {
- return LocalFileSystem.getInstance().refreshAndFindFileByPath(name);
- }
- });
- PySdkService.getInstance().solidifySdk(sdk);
- sdk = SdkConfigurationUtil.createAndAddSDK(sdkHome.getPath(), PythonSdkType.getInstance());
- if (sdk != null) {
- PythonSdkUpdater.updateOrShowError(sdk, null, project, null);
- }
- model.addSdk(sdk);
- settingsStep.setSdk(sdk);
- try {
- model.apply();
- }
- catch (ConfigurationException exception) {
- LOG.error("Error adding detected python interpreter " + exception.getMessage());
- }
+ if (sdk instanceof PyDetectedSdk) {
+ addDetectedSdk(settingsStep, sdk);
}
- Project newProject = generateProject(project, settingsStep);
+ else if (sdk == null) {
+ createAndAddVirtualEnv(settingsStep);
+ }
+ sdk = settingsStep.getSdk();
+
+ final Project newProject = generateProject(settingsStep);
if (newProject != null) {
SdkConfigurationUtil.setDirectoryProjectSdk(newProject, sdk);
final List sdks = PythonSdkType.getAllSdks();
@@ -90,12 +77,72 @@ public class GenerateProjectCallback implements NullableConsumer() {
+ @Override
+ public VirtualFile compute() {
+ return LocalFileSystem.getInstance().refreshAndFindFileByPath(name);
+ }
+ });
+ PySdkService.getInstance().solidifySdk(sdk);
+ sdk = SdkConfigurationUtil.createAndAddSDK(sdkHome.getPath(), PythonSdkType.getInstance());
+ if (sdk != null) {
+ PythonSdkUpdater.updateOrShowError(sdk, null, project, null);
+ }
+
+ model.addSdk(sdk);
+ settingsStep.setSdk(sdk);
+ try {
+ model.apply();
+ }
+ catch (ConfigurationException exception) {
+ LOG.error("Error adding detected python interpreter " + exception.getMessage());
+ }
+ }
+
+ private static void createAndAddVirtualEnv(final ProjectSpecificSettingsStep settingsStep) {
+ final Project project = ProjectManager.getInstance().getDefaultProject();
+ final ProjectSdksModel model = PyConfigurableInterpreterList.getInstance(project).getModel();
+ final List flavors = PythonSdkFlavor.getApplicableFlavors(false);
+ String baseSdk = null;
+ for (PythonSdkFlavor flavor : flavors) {
+ final Collection baseSdks = flavor.suggestHomePaths();
+ if (!baseSdks.isEmpty()) {
+ baseSdk = baseSdks.iterator().next();
+ }
+ }
+ if (baseSdk != null) {
+ final PyPackageManager packageManager = PyPackageManager.getInstance(new PyDetectedSdk(baseSdk));
+ try {
+ final String path = packageManager.createVirtualEnv(settingsStep.getProjectLocation() + "/.idea/VirtualEnvironment", false);
+ AbstractCreateVirtualEnvDialog.setupVirtualEnvSdk(path, true, new AbstractCreateVirtualEnvDialog.VirtualEnvCallback() {
+ @Override
+ public void virtualEnvCreated(Sdk createdSdk, boolean associateWithProject) {
+ settingsStep.setSdk(createdSdk);
+ model.addSdk(createdSdk);
+ try {
+ model.apply();
+ }
+ catch (ConfigurationException exception) {
+ LOG.error("Error adding created virtual env " + exception.getMessage());
+ }
+ }
+ });
+ }
+ catch (ExecutionException e) {
+ LOG.warn("Failed to create virtual env " + e.getMessage());
+ }
+ }
+ }
+
@Nullable
- private static Project generateProject(@NotNull final Project project,
- @NotNull final ProjectSettingsStepBase settings) {
+ private static Project generateProject(@NotNull final ProjectSettingsStepBase settings) {
final DirectoryProjectGenerator generator = settings.getProjectGenerator();
final String location = FileUtil.expandUserHome(settings.getProjectLocation());
- return AbstractNewProjectStep.doGenerateProject(project, location, generator,
+ return AbstractNewProjectStep.doGenerateProject(ProjectManager.getInstance().getDefaultProject(), location, generator,
file -> computeProjectSettings(generator, (ProjectSpecificSettingsStep)settings));
}
diff --git a/python/ide/src/com/jetbrains/python/newProject/actions/ProjectSpecificSettingsStep.java b/python/ide/src/com/jetbrains/python/newProject/actions/ProjectSpecificSettingsStep.java
index 3ff75c66f91a..09a7a0d78210 100644
--- a/python/ide/src/com/jetbrains/python/newProject/actions/ProjectSpecificSettingsStep.java
+++ b/python/ide/src/com/jetbrains/python/newProject/actions/ProjectSpecificSettingsStep.java
@@ -23,8 +23,7 @@ import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.projectRoots.Sdk;
-import com.intellij.openapi.ui.LabeledComponent;
-import com.intellij.openapi.ui.VerticalFlowLayout;
+import com.intellij.openapi.ui.*;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.platform.DirectoryProjectGenerator;
import com.intellij.ui.DocumentAdapter;
@@ -103,7 +102,9 @@ public class ProjectSpecificSettingsStep extends ProjectSettingsStepBase impleme
}
public Sdk getSdk() {
+ if (!(myProjectGenerator instanceof PythonProjectGenerator)) return null;
if (mySdk != null) return mySdk;
+ if (((PythonProjectGenerator)myProjectGenerator).hideInterpreter()) return null;
return (Sdk)mySdkCombo.getComboBox().getSelectedItem();
}
@@ -118,7 +119,7 @@ public class ProjectSpecificSettingsStep extends ProjectSettingsStepBase impleme
@Override
protected void registerValidators() {
super.registerValidators();
- if (myProjectGenerator instanceof PythonProjectGenerator) {
+ if (myProjectGenerator instanceof PythonProjectGenerator && !((PythonProjectGenerator)myProjectGenerator).hideInterpreter()) {
mySdkCombo.getComboBox().addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent event) {
@@ -136,13 +137,6 @@ public class ProjectSpecificSettingsStep extends ProjectSettingsStepBase impleme
}
}
- @Nullable
- protected JPanel extendBasePanel() {
- if (myProjectGenerator instanceof PythonProjectGenerator)
- return ((PythonProjectGenerator)myProjectGenerator).extendBasePanel();
- return null;
- }
-
@Override
public boolean checkValid() {
myInstallFramework = false;
@@ -150,11 +144,12 @@ public class ProjectSpecificSettingsStep extends ProjectSettingsStepBase impleme
return false;
}
- if ((myProjectGenerator instanceof PythonProjectGenerator)) {
+ if (myProjectGenerator instanceof PythonProjectGenerator) {
final Sdk sdk = getSdk();
-
if (sdk == null) {
- setErrorText("No Python interpreter selected");
+ if (!((PythonProjectGenerator)myProjectGenerator).hideInterpreter()) {
+ setErrorText("No Python interpreter selected");
+ }
return false;
}
else if (PythonSdkType.isInvalid(sdk)) {
@@ -213,39 +208,81 @@ public class ProjectSpecificSettingsStep extends ProjectSettingsStepBase impleme
@Override
protected JPanel createBasePanel() {
- final JPanel panel = super.createBasePanel();
-
if (myProjectGenerator instanceof PythonProjectGenerator) {
- final Project project = ProjectManager.getInstance().getDefaultProject();
- final List sdks = PyConfigurableInterpreterList.getInstance(project).getAllPythonSdks();
- VirtualEnvProjectFilter.removeAllAssociated(sdks);
- Sdk compatibleSdk = sdks.isEmpty() ? null : sdks.iterator().next();
- DirectoryProjectGenerator generator = getProjectGenerator();
- if (generator instanceof PyFrameworkProjectGenerator && !((PyFrameworkProjectGenerator)generator).supportsPython3()) {
- if (compatibleSdk != null && PythonSdkType.getLanguageLevelForSdk(compatibleSdk).isPy3K()) {
- Sdk python2Sdk = PythonSdkType.findPython2Sdk(sdks);
- if (python2Sdk != null) {
- compatibleSdk = python2Sdk;
- }
- }
+ final BorderLayout layout = new BorderLayout();
+
+ final JPanel locationPanel = new JPanel(layout);
+
+ final JPanel panel = new JPanel(new VerticalFlowLayout(0, 2));
+ final LabeledComponent location = createLocationComponent();
+ location.setLabelLocation(BorderLayout.WEST);
+
+ locationPanel.add(location, BorderLayout.CENTER);
+ panel.add(locationPanel);
+ if (((PythonProjectGenerator)myProjectGenerator).hideInterpreter()) {
+ addInterpreterButton(locationPanel, location);
+ }
+ else {
+ final LabeledComponent labeled = createInterpreterCombo();
+ UIUtil.mergeComponentsWithAnchor(labeled, location);
+ panel.add(labeled);
}
- final Sdk preferred = compatibleSdk;
- mySdkCombo = new PythonSdkChooserCombo(project, sdks, sdk -> sdk == preferred);
- mySdkCombo.setButtonIcon(PythonIcons.Python.InterpreterGear);
-
- final LabeledComponent labeled = LabeledComponent.create(mySdkCombo, "Interpreter");
- labeled.setLabelLocation(BorderLayout.WEST);
- UIUtil.mergeComponentsWithAnchor(labeled, (PanelWithAnchor)panel.getComponent(0));
- panel.add(labeled);
+ final JPanel basePanelExtension = ((PythonProjectGenerator)myProjectGenerator).extendBasePanel();
+ if (basePanelExtension != null) {
+ UIUtil.mergeComponentsWithAnchor((PanelWithAnchor)basePanelExtension, location);
+ panel.add(basePanelExtension);
+ }
+ return panel;
}
- final JPanel basePanelExtension = extendBasePanel();
- if (basePanelExtension != null) {
- panel.add(basePanelExtension);
+ return super.createBasePanel();
+ }
+
+ private void addInterpreterButton(final JPanel locationPanel, final LabeledComponent location) {
+ final JButton interpreterButton = new FixedSizeButton(location);
+ interpreterButton.setIcon(PythonIcons.Python.Python);
+ interpreterButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ final DialogBuilder builder = new DialogBuilder();
+ final JPanel panel = new JPanel();
+ final LabeledComponent interpreterCombo = createInterpreterCombo();
+ if (mySdk != null) {
+ mySdkCombo.getComboBox().setSelectedItem(mySdk);
+ }
+ panel.add(interpreterCombo);
+ builder.setCenterPanel(panel);
+ builder.setTitle("Select Python Interpreter");
+ if (builder.showAndGet()) {
+ mySdk = (Sdk)mySdkCombo.getComboBox().getSelectedItem();
+ }
+ }
+ });
+ locationPanel.add(interpreterButton, BorderLayout.EAST);
+ }
+
+ @NotNull
+ private LabeledComponent createInterpreterCombo() {
+ final Project project = ProjectManager.getInstance().getDefaultProject();
+ final List sdks = PyConfigurableInterpreterList.getInstance(project).getAllPythonSdks();
+ VirtualEnvProjectFilter.removeAllAssociated(sdks);
+ Sdk compatibleSdk = sdks.isEmpty() ? null : sdks.iterator().next();
+ DirectoryProjectGenerator generator = getProjectGenerator();
+ if (generator instanceof PyFrameworkProjectGenerator && !((PyFrameworkProjectGenerator)generator).supportsPython3()) {
+ if (compatibleSdk != null && PythonSdkType.getLanguageLevelForSdk(compatibleSdk).isPy3K()) {
+ Sdk python2Sdk = PythonSdkType.findPython2Sdk(sdks);
+ if (python2Sdk != null) {
+ compatibleSdk = python2Sdk;
+ }
+ }
}
- return panel;
+ final Sdk preferred = compatibleSdk;
+ mySdkCombo = new PythonSdkChooserCombo(project, sdks, sdk -> sdk == preferred);
+ mySdkCombo.setButtonIcon(PythonIcons.Python.InterpreterGear);
+
+ return LabeledComponent.create(mySdkCombo, "Interpreter", BorderLayout.WEST);
}
@Override
diff --git a/python/openapi/src/com/jetbrains/python/newProject/PythonProjectGenerator.java b/python/openapi/src/com/jetbrains/python/newProject/PythonProjectGenerator.java
index 945149868e47..ba2723ad8c32 100644
--- a/python/openapi/src/com/jetbrains/python/newProject/PythonProjectGenerator.java
+++ b/python/openapi/src/com/jetbrains/python/newProject/PythonProjectGenerator.java
@@ -67,10 +67,14 @@ public abstract class PythonProjectGenerator {
}
@Nullable
- public BooleanFunction beforeProjectGenerated(@NotNull final Sdk sdk) {
+ public BooleanFunction beforeProjectGenerated(@Nullable final Sdk sdk) {
return null;
}
+ public boolean hideInterpreter() {
+ return false;
+ }
+
public void addErrorLabelMouseListener(@NotNull final MouseListener mouseListener) {
myErrorLabelMouseListener = mouseListener;
}
diff --git a/python/src/com/jetbrains/python/sdk/AbstractCreateVirtualEnvDialog.java b/python/src/com/jetbrains/python/sdk/AbstractCreateVirtualEnvDialog.java
index da5b3779871e..af2757ee2e07 100644
--- a/python/src/com/jetbrains/python/sdk/AbstractCreateVirtualEnvDialog.java
+++ b/python/src/com/jetbrains/python/sdk/AbstractCreateVirtualEnvDialog.java
@@ -72,7 +72,7 @@ public abstract class AbstractCreateVirtualEnvDialog extends IdeaDialog {
void virtualEnvCreated(Sdk sdk, boolean associateWithProject);
}
- protected static void setupVirtualEnvSdk(final String path,
+ public static void setupVirtualEnvSdk(final String path,
boolean associateWithProject,
VirtualEnvCallback callback) {
final VirtualFile sdkHome =