mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-11166 Ability to create new projects without selecting Python interpreter
Extracted python interpreter combobox
This commit is contained in:
-103
@@ -1,103 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.edu.learning.ui.StudyNewProjectPanel">
|
||||
<grid id="27dc6" binding="myContentPanel" layout-manager="GridLayoutManager" row-count="3" column-count="4" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<xy x="20" y="20" width="610" height="422"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<grid id="54488" binding="myInfoPanel" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<grid row="2" column="1" row-span="1" col-span="3" vsize-policy="2" hsize-policy="4" anchor="0" fill="3" indent="2" use-parent-layout="false">
|
||||
<minimum-size width="-1" height="60"/>
|
||||
<preferred-size width="-1" height="170"/>
|
||||
</grid>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="line">
|
||||
<color color="-6709600"/>
|
||||
</border>
|
||||
<children>
|
||||
<component id="213f6" class="javax.swing.JLabel" binding="myAuthorLabel">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value=""/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="50229" class="javax.swing.JTextPane" binding="myDescriptionLabel">
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="2" vsize-policy="6" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false">
|
||||
<preferred-size width="150" height="100"/>
|
||||
</grid>
|
||||
</constraints>
|
||||
<properties>
|
||||
<alignmentX value="0.0"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
<component id="6c40c" class="javax.swing.JLabel" binding="myLabel">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="2" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false">
|
||||
<preferred-size width="58" height="20"/>
|
||||
<maximum-size width="70" height="-1"/>
|
||||
</grid>
|
||||
</constraints>
|
||||
<properties>
|
||||
<font/>
|
||||
<horizontalAlignment value="10"/>
|
||||
<horizontalTextPosition value="10"/>
|
||||
<iconTextGap value="0"/>
|
||||
<labelFor value=""/>
|
||||
<text value="Courses:"/>
|
||||
</properties>
|
||||
</component>
|
||||
<grid id="e4f37" layout-manager="GridLayoutManager" row-count="1" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="0" vgap="-1">
|
||||
<margin top="0" left="20" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<grid row="0" column="1" row-span="2" col-span="3" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="21ac6" class="javax.swing.JComboBox" binding="myCoursesComboBox">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false">
|
||||
<preferred-size width="120" height="-1"/>
|
||||
</grid>
|
||||
</constraints>
|
||||
<properties>
|
||||
<alignmentX value="0.0"/>
|
||||
<alignmentY value="0.0"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="b24e4" class="com.intellij.openapi.ui.FixedSizeButton" binding="myBrowseButton">
|
||||
<constraints>
|
||||
<grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<horizontalTextPosition value="0"/>
|
||||
<text value=""/>
|
||||
<toolTipText value="Select local course"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="7834e" class="com.intellij.openapi.ui.FixedSizeButton" binding="myRefreshButton">
|
||||
<constraints>
|
||||
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<horizontalTextPosition value="0"/>
|
||||
<text value=""/>
|
||||
<toolTipText value="Refresh course list"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
</children>
|
||||
</grid>
|
||||
</form>
|
||||
+92
-36
@@ -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<CourseInfo> myAvailableCourses = new ArrayList<CourseInfo>();
|
||||
private JButton myBrowseButton;
|
||||
private JComboBox<CourseInfo> myCoursesComboBox;
|
||||
private ComboBox<CourseInfo> 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 = "<html>Failed to download courses.<br>Check your Internet connection.</html>";
|
||||
private static final String INVALID_COURSE = "Selected course is invalid";
|
||||
private FacetValidatorsManager myValidationManager;
|
||||
private boolean isComboboxInitialized;
|
||||
private String LOGIN_TO_STEPIC_MESSAGE = "<html><u>Login to Stepic</u> to open the adaptive course </html>";;
|
||||
private static final String LOGIN_TO_STEPIC_MESSAGE = "<html><u>Login to Stepic</u> to open the adaptive course </html>";
|
||||
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<CourseInfo>();
|
||||
final LabeledComponent<ComboBox> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+26
-20
@@ -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 = "<html><u>Add</u> python interpreter.</html>";
|
||||
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<Sdk> 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<CourseInfo> getCourses() {
|
||||
@@ -144,26 +151,25 @@ public class PyStudyDirectoryProjectGenerator extends PythonProjectGenerator imp
|
||||
return myGenerator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hideInterpreter() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public BooleanFunction<PythonProjectGenerator> beforeProjectGenerated(@NotNull Sdk sdk) {
|
||||
return new BooleanFunction<PythonProjectGenerator>() {
|
||||
@Override
|
||||
public boolean fun(PythonProjectGenerator generator) {
|
||||
final List<Integer> enrolledCoursesIds = myGenerator.getEnrolledCoursesIds();
|
||||
final CourseInfo course = (CourseInfo)mySettingsPanel.getCoursesComboBox().getSelectedItem();
|
||||
if (course.isAdaptive() && !enrolledCoursesIds.contains(course.getId())) {
|
||||
ProgressManager.getInstance().runProcessWithProgressSynchronously(new ThrowableComputable<Boolean, RuntimeException>() {
|
||||
@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<PythonProjectGenerator> beforeProjectGenerated(@Nullable Sdk sdk) {
|
||||
return generator -> {
|
||||
final List<Integer> 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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
-8
@@ -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<Sdk> sdks = PyConfigurableInterpreterList.getInstance(project).getAllPythonSdks();
|
||||
Sdk sdk = sdks.isEmpty() ? null : sdks.iterator().next();
|
||||
step.setSdk(sdk);
|
||||
callback.consume(step);
|
||||
}
|
||||
}
|
||||
|
||||
+75
-28
@@ -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<ProjectSettingsStepBase> {
|
||||
@@ -50,34 +54,17 @@ public class GenerateProjectCallback implements NullableConsumer<ProjectSettings
|
||||
if (!(step instanceof ProjectSpecificSettingsStep)) return;
|
||||
|
||||
final ProjectSpecificSettingsStep settingsStep = (ProjectSpecificSettingsStep)step;
|
||||
|
||||
Sdk sdk = settingsStep.getSdk();
|
||||
final Project project = ProjectManager.getInstance().getDefaultProject();
|
||||
final ProjectSdksModel model = PyConfigurableInterpreterList.getInstance(project).getModel();
|
||||
if (sdk instanceof PyDetectedSdk) {
|
||||
final String name = sdk.getName();
|
||||
VirtualFile sdkHome = ApplicationManager.getApplication().runWriteAction(new Computable<VirtualFile>() {
|
||||
@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<Sdk> sdks = PythonSdkType.getAllSdks();
|
||||
@@ -90,12 +77,72 @@ public class GenerateProjectCallback implements NullableConsumer<ProjectSettings
|
||||
}
|
||||
}
|
||||
|
||||
private static void addDetectedSdk(ProjectSpecificSettingsStep settingsStep, Sdk sdk) {
|
||||
final Project project = ProjectManager.getInstance().getDefaultProject();
|
||||
final ProjectSdksModel model = PyConfigurableInterpreterList.getInstance(project).getModel();
|
||||
final String name = sdk.getName();
|
||||
VirtualFile sdkHome = ApplicationManager.getApplication().runWriteAction(new Computable<VirtualFile>() {
|
||||
@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<PythonSdkFlavor> flavors = PythonSdkFlavor.getApplicableFlavors(false);
|
||||
String baseSdk = null;
|
||||
for (PythonSdkFlavor flavor : flavors) {
|
||||
final Collection<String> 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));
|
||||
}
|
||||
|
||||
|
||||
+76
-39
@@ -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<Sdk> 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<TextFieldWithBrowseButton> location = createLocationComponent();
|
||||
location.setLabelLocation(BorderLayout.WEST);
|
||||
|
||||
locationPanel.add(location, BorderLayout.CENTER);
|
||||
panel.add(locationPanel);
|
||||
if (((PythonProjectGenerator)myProjectGenerator).hideInterpreter()) {
|
||||
addInterpreterButton(locationPanel, location);
|
||||
}
|
||||
else {
|
||||
final LabeledComponent<PythonSdkChooserCombo> 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<PythonSdkChooserCombo> 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<TextFieldWithBrowseButton> 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<PythonSdkChooserCombo> 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<PythonSdkChooserCombo> createInterpreterCombo() {
|
||||
final Project project = ProjectManager.getInstance().getDefaultProject();
|
||||
final List<Sdk> 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
|
||||
|
||||
@@ -67,10 +67,14 @@ public abstract class PythonProjectGenerator {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public BooleanFunction<PythonProjectGenerator> beforeProjectGenerated(@NotNull final Sdk sdk) {
|
||||
public BooleanFunction<PythonProjectGenerator> beforeProjectGenerated(@Nullable final Sdk sdk) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean hideInterpreter() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void addErrorLabelMouseListener(@NotNull final MouseListener mouseListener) {
|
||||
myErrorLabelMouseListener = mouseListener;
|
||||
}
|
||||
|
||||
@@ -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 =
|
||||
|
||||
Reference in New Issue
Block a user