diff --git a/python/educational-core/student/resources/META-INF/edu-intellij.xml b/python/educational-core/student/resources/META-INF/edu-intellij.xml index 7bb472051b3c..4430d18b2802 100644 --- a/python/educational-core/student/resources/META-INF/edu-intellij.xml +++ b/python/educational-core/student/resources/META-INF/edu-intellij.xml @@ -2,5 +2,8 @@ + + + diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/intellij/EduCourseConfigurator.java b/python/educational-core/student/src/com/jetbrains/edu/learning/intellij/EduCourseConfigurator.java index 0eb7fa75f7a7..1e091b2b97ac 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/intellij/EduCourseConfigurator.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/intellij/EduCourseConfigurator.java @@ -1,8 +1,12 @@ package com.jetbrains.edu.learning.intellij; import com.intellij.lang.LanguageExtension; +import com.intellij.openapi.module.ModifiableModuleModel; import com.intellij.openapi.project.Project; +import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator; +import com.jetbrains.edu.learning.stepic.CourseInfo; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; @SuppressWarnings("unused") //used in other educational plugins that are stored in separate repository public interface EduCourseConfigurator { @@ -10,4 +14,10 @@ public interface EduCourseConfigurator { LanguageExtension INSTANCE = new LanguageExtension<>(EP_NAME); default void configureModule(@NotNull final Project project) {} + + default void createCourseFromCourseInfo(@NotNull ModifiableModuleModel moduleModel, + @NotNull Project project, + @NotNull StudyProjectGenerator generator, + @NotNull CourseInfo selectedCourse, + @Nullable String moduleDir) {} } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/intellij/generation/EduProjectGenerator.java b/python/educational-core/student/src/com/jetbrains/edu/learning/intellij/generation/EduProjectGenerator.java new file mode 100644 index 000000000000..fe98b766ea7a --- /dev/null +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/intellij/generation/EduProjectGenerator.java @@ -0,0 +1,26 @@ +package com.jetbrains.edu.learning.intellij.generation; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.jetbrains.edu.learning.StudyTaskManager; +import com.jetbrains.edu.learning.courseFormat.Course; +import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +public class EduProjectGenerator extends StudyProjectGenerator { + private static final Logger LOG = Logger.getInstance(EduProjectGenerator.class); + + @Override + public void generateProject(@NotNull Project project, @NotNull VirtualFile baseDir) { + final Course course = getCourse(project); + if (course == null) { + LOG.warn("Failed to get course"); + return; + } + StudyTaskManager.getInstance(project).setCourse(course); + course.setCourseDirectory(new File(OUR_COURSES_DIR, mySelectedCourseInfo.getName()).getAbsolutePath()); + } +} diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/intellij/localCourses/EduCustomCourseModuleBuilder.java b/python/educational-core/student/src/com/jetbrains/edu/learning/intellij/localCourses/EduCustomCourseModuleBuilder.java new file mode 100644 index 000000000000..5a80f2c6089a --- /dev/null +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/intellij/localCourses/EduCustomCourseModuleBuilder.java @@ -0,0 +1,102 @@ +package com.jetbrains.edu.learning.intellij.localCourses; + +import com.intellij.ide.util.projectWizard.*; +import com.intellij.lang.Language; +import com.intellij.openapi.module.ModifiableModuleModel; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleWithNameAlreadyExists; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ui.configuration.ModulesProvider; +import com.intellij.openapi.util.Conditions; +import com.intellij.openapi.util.InvalidDataException; +import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator; +import com.jetbrains.edu.learning.intellij.EduCourseConfigurator; +import com.jetbrains.edu.learning.intellij.generation.EduProjectGenerator; +import com.jetbrains.edu.learning.stepic.CourseInfo; +import org.jdom.JDOMException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.io.IOException; + +class EduCustomCourseModuleBuilder extends JavaModuleBuilder { + private EduProjectGenerator myGenerator = new EduProjectGenerator(); + private CourseInfo mySelectedCourse; + + @Nullable + @Override + public Module commitModule(@NotNull Project project, @Nullable ModifiableModuleModel model) { + String type = mySelectedCourse.getType(); + String languageName = type.substring("pycharm ".length()); + Language language = Language.findLanguageByID(languageName); + if (language != null) { + EduCourseConfigurator configurator = EduCourseConfigurator.INSTANCE.forLanguage(language); + if (configurator != null) { + configurator.configureModule(project); + } + } + return super.commitModule(project, model); + } + + + @Nullable + @Override + public String getBuilderId() { + return "custom.course.builder"; + } + + @Override + public ModuleWizardStep[] createWizardSteps(@NotNull WizardContext wizardContext, @NotNull ModulesProvider modulesProvider) { + return new ModuleWizardStep[]{new EduCourseSelectionSettingsStep(myGenerator)}; + } + + + private class EduCourseSelectionSettingsStep extends ModuleWizardStep { + + private final StudyProjectGenerator myGenerator; + + EduCourseSelectionSettingsStep(StudyProjectGenerator generator) { + myGenerator = generator; + } + + @Override + public JComponent getComponent() { + return new EduLocalCoursePanel(myGenerator, EduCustomCourseModuleBuilder.this).getContentPanel(); + } + + @Override + public void updateDataModel() { + } + } + + @Nullable + @Override + public ModuleWizardStep modifySettingsStep(@NotNull SettingsStep settingsStep) { + return ProjectWizardStepFactory.getInstance().createJavaSettingsStep(settingsStep, this, Conditions.alwaysTrue()); + } + + void setSelectedCourse(CourseInfo selectedCourse) { + mySelectedCourse = selectedCourse; + } + + @NotNull + @Override + public Module createModule(@NotNull ModifiableModuleModel moduleModel) + throws InvalidDataException, IOException, ModuleWithNameAlreadyExists, JDOMException, ConfigurationException { + Module baseModule = super.createModule(moduleModel); + if (mySelectedCourse != null) { + String type = mySelectedCourse.getType(); + String languageName = type.substring("pycharm ".length()); + Language language = Language.findLanguageByID(languageName); + if (language != null) { + EduCourseConfigurator configurator = EduCourseConfigurator.INSTANCE.forLanguage(language); + if (configurator != null) { + configurator.createCourseFromCourseInfo(moduleModel, baseModule.getProject(), myGenerator, mySelectedCourse, getModuleFileDirectory()); + } + } + } + return baseModule; + } +} diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/intellij/localCourses/EduCustomCourseProjectTemplate.java b/python/educational-core/student/src/com/jetbrains/edu/learning/intellij/localCourses/EduCustomCourseProjectTemplate.java new file mode 100644 index 000000000000..c80e8f4bc686 --- /dev/null +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/intellij/localCourses/EduCustomCourseProjectTemplate.java @@ -0,0 +1,41 @@ +package com.jetbrains.edu.learning.intellij.localCourses; + +import com.intellij.icons.AllIcons; +import com.intellij.ide.util.projectWizard.AbstractModuleBuilder; +import com.intellij.openapi.ui.ValidationInfo; +import com.jetbrains.edu.learning.intellij.EduIntelliJProjectTemplate; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +class EduCustomCourseProjectTemplate implements EduIntelliJProjectTemplate { + @NotNull + @Override + public String getName() { + return "Load an existing course"; + } + + @Nullable + @Override + public String getDescription() { + return "Custom Course Addition"; + } + + @Override + public Icon getIcon() { + return AllIcons.General.SecondaryGroup; + } + + @NotNull + @Override + public AbstractModuleBuilder createModuleBuilder() { + return new EduCustomCourseModuleBuilder(); + } + + @Nullable + @Override + public ValidationInfo validateSettings() { + return null; + } +} diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/intellij/localCourses/EduLocalCoursePanel.form b/python/educational-core/student/src/com/jetbrains/edu/learning/intellij/localCourses/EduLocalCoursePanel.form new file mode 100644 index 000000000000..19b885d3a4c6 --- /dev/null +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/intellij/localCourses/EduLocalCoursePanel.form @@ -0,0 +1,53 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/intellij/localCourses/EduLocalCoursePanel.java b/python/educational-core/student/src/com/jetbrains/edu/learning/intellij/localCourses/EduLocalCoursePanel.java new file mode 100644 index 000000000000..0fc56d48a2ab --- /dev/null +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/intellij/localCourses/EduLocalCoursePanel.java @@ -0,0 +1,56 @@ +package com.jetbrains.edu.learning.intellij.localCourses; + +import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; +import com.intellij.openapi.ui.TextFieldWithBrowseButton; +import com.intellij.openapi.util.text.StringUtil; +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.ui.StudyNewProjectPanel; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class EduLocalCoursePanel { + private final StudyProjectGenerator myGenerator; + private EduCustomCourseModuleBuilder myBuilder; + private JPanel myContentPanel; + private JPanel myInfoPanel; + private TextFieldWithBrowseButton myCourseArchivePath; + + public EduLocalCoursePanel(final StudyProjectGenerator generator, EduCustomCourseModuleBuilder builder) { + myGenerator = generator; + myBuilder = builder; + myCourseArchivePath.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + String coursePath = myCourseArchivePath.getText(); + CourseInfo courseInfo = generator.addLocalCourse(coursePath); + if (courseInfo != null) { + //TODO: REMOVE THIS after API CHANGE + myBuilder.setSelectedCourse(courseInfo); + myGenerator.setSelectedCourse(courseInfo); + //TODO: change API to do this!!! +// final String authorsString = Course.getAuthorsString(courseInfo.getAuthors()); +// ((JLabel)myInfoPanel.getComponent(0)).setText(!StringUtil.isEmptyOrSpaces(authorsString) ? "Author: " + authorsString : ""); +// ((JTextPane)myInfoPanel.getComponent(1)).setText(courseInfo.getDescription()); + } + else { + //TODO: validate!!! + } + } + }); + myCourseArchivePath.addBrowseFolderListener("Select Course Archive", null, null, + FileChooserDescriptorFactory.createSingleFileDescriptor()); + } + + public JPanel getContentPanel() { + return myContentPanel; + } + + private void createUIComponents() { + StudyNewProjectPanel panel = new StudyNewProjectPanel(myGenerator); + myInfoPanel = panel.getInfoPanel(); + } +} diff --git a/python/educational-core/student/student.iml b/python/educational-core/student/student.iml index 823dce83ff49..29d9b096e528 100644 --- a/python/educational-core/student/student.iml +++ b/python/educational-core/student/student.iml @@ -36,7 +36,8 @@ - + + \ No newline at end of file