full support for stepik in kotlin-java courses

This commit is contained in:
Ekaterina Tuzova
2017-04-07 19:52:36 +03:00
parent 1bc47c4d3e
commit 669a3e5a67
9 changed files with 198 additions and 19 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 B

@@ -9,6 +9,7 @@ import com.intellij.openapi.progress.Task.Backgroundable;
import com.jetbrains.edu.learning.core.EduNames;
import com.jetbrains.edu.learning.courseFormat.tasks.Task;
import com.jetbrains.edu.learning.stepic.EduStepicConnector;
import com.jetbrains.edu.learning.stepic.EduStepicNames;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
@@ -17,7 +18,8 @@ import java.util.List;
public class RemoteCourse extends Course {
//course type in format "pycharm<version> <language>"
@SerializedName("course_format") private String myType = "pycharm" + EduStepicConnector.CURRENT_VERSION + " " + getLanguageID();
@SerializedName("course_format") private String myType =
String.format("%s%d %s", EduStepicNames.PYCHARM_PREFIX, EduStepicConnector.CURRENT_VERSION, getLanguageID());
@SerializedName("is_idea_compatible") private boolean isCompatible = true;
List<Integer> sections;
List<Integer> instructors = new ArrayList<>();
@@ -31,6 +33,11 @@ public class RemoteCourse extends Course {
return myType;
}
public void setLanguage(@NotNull final String language) {
super.setLanguage(language);
updateType(language);
}
public List<Integer> getSections() {
return sections;
}
@@ -107,8 +114,10 @@ public class RemoteCourse extends Course {
public void copyCourseParameters(RemoteCourse course) {
setName(course.getName());
setUpdateDate(course.getUpdateDate());
}
private void updateType(String language) {
myType = String.format("%s%d %s", EduStepicNames.PYCHARM_PREFIX, EduStepicConnector.CURRENT_VERSION, language);
}
}
@@ -144,7 +144,7 @@ public class StudyProjectGenerator {
}
@NotNull
public List<Course> getCoursesUnderProgress(boolean force, @NotNull final String progressTitle, @NotNull final Project project) {
public List<Course> getCoursesUnderProgress(boolean force, @NotNull final String progressTitle, @Nullable final Project project) {
try {
return ProgressManager.getInstance()
.runProcessWithProgressSynchronously(() -> {
@@ -3,16 +3,35 @@ package com.jetbrains.edu.learning.intellij;
import com.intellij.icons.AllIcons;
import com.intellij.ide.util.projectWizard.WizardContext;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.platform.ProjectTemplate;
import com.intellij.platform.ProjectTemplatesFactory;
import com.jetbrains.edu.learning.courseFormat.Course;
import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator;
import com.jetbrains.edu.learning.intellij.stepik.EduRemoteCourseTemplate;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@SuppressWarnings("unused") //used in other educational plugins that are stored in separate repository
public class EduIntelliJTemplateFactory extends ProjectTemplatesFactory {
private static final String GROUP_NAME = "Education";
private static List<Course> ourRemoteCourses;
static {
ProgressManager.getInstance().run(new Task.Backgroundable(null, "Updating Course") {
@Override
public void run(@NotNull ProgressIndicator indicator) {
ourRemoteCourses = new StudyProjectGenerator().getCourses(true);
}
});
}
@NotNull
@Override
@@ -23,7 +42,14 @@ public class EduIntelliJTemplateFactory extends ProjectTemplatesFactory {
@NotNull
@Override
public ProjectTemplate[] createTemplates(@Nullable String group, WizardContext context) {
return ApplicationManager.getApplication().getExtensions(EduIntelliJProjectTemplate.EP_NAME);
final ArrayList<EduIntelliJProjectTemplate> templates = new ArrayList<>();
if (ourRemoteCourses != null) {
for (Course course : ourRemoteCourses) {
templates.add(new EduRemoteCourseTemplate(course));
}
}
Collections.addAll(templates, ApplicationManager.getApplication().getExtensions(EduIntelliJProjectTemplate.EP_NAME));
return templates.toArray(new ProjectTemplate[templates.size()]);
}
@Override
@@ -0,0 +1,90 @@
package com.jetbrains.edu.learning.intellij.stepik;
import com.intellij.ide.util.projectWizard.JavaModuleBuilder;
import com.intellij.ide.util.projectWizard.ModuleWizardStep;
import com.intellij.ide.util.projectWizard.ProjectWizardStepFactory;
import com.intellij.ide.util.projectWizard.SettingsStep;
import com.intellij.lang.Language;
import com.intellij.openapi.diagnostic.Logger;
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.util.Conditions;
import com.intellij.openapi.util.InvalidDataException;
import com.jetbrains.edu.learning.EduPluginConfigurator;
import com.jetbrains.edu.learning.StudyTaskManager;
import com.jetbrains.edu.learning.courseFormat.Course;
import com.jetbrains.edu.learning.intellij.generation.EduProjectGenerator;
import org.jdom.JDOMException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
class EduRemoteCourseModuleBuilder extends JavaModuleBuilder {
private static final Logger LOG = Logger.getInstance(EduRemoteCourseModuleBuilder.class);
private final Course myCourse;
private EduProjectGenerator myGenerator = new EduProjectGenerator();
public EduRemoteCourseModuleBuilder(Course course) {
myCourse = course;
}
@Nullable
@Override
public Module commitModule(@NotNull Project project, @Nullable ModifiableModuleModel model) {
Module module = super.commitModule(project, model);
if (module == null) {
return null;
}
String languageName = myCourse.getLanguageID();
Language language = Language.findLanguageByID(languageName);
if (language == null) {
return module;
}
EduPluginConfigurator configurator = EduPluginConfigurator.INSTANCE.forLanguage(language);
if (configurator == null) {
return module;
}
configurator.configureModule(module);
return module;
}
@Nullable
@Override
public String getBuilderId() {
return "remote.course.builder." + myCourse.getName();
}
@Nullable
@Override
public ModuleWizardStep modifySettingsStep(@NotNull SettingsStep settingsStep) {
return ProjectWizardStepFactory.getInstance().createJavaSettingsStep(settingsStep, this, Conditions.alwaysTrue());
}
@NotNull
@Override
public Module createModule(@NotNull ModifiableModuleModel moduleModel)
throws InvalidDataException, IOException, ModuleWithNameAlreadyExists, JDOMException, ConfigurationException {
Module baseModule = super.createModule(moduleModel);
String languageName = myCourse.getLanguageID();
Language language = Language.findLanguageByID(languageName);
if (language != null) {
EduPluginConfigurator configurator = EduPluginConfigurator.INSTANCE.forLanguage(language);
if (configurator != null) {
Project project = baseModule.getProject();
myGenerator.setSelectedCourse(myCourse);
myGenerator.generateProject(project, project.getBaseDir());
Course course = StudyTaskManager.getInstance(project).getCourse();
if (course == null) {
LOG.info("failed to generate course");
return baseModule;
}
configurator.createCourseModuleContent(moduleModel, project, course, getModuleFileDirectory());
}
}
return baseModule;
}
}
@@ -0,0 +1,48 @@
package com.jetbrains.edu.learning.intellij.stepik;
import com.intellij.ide.util.projectWizard.AbstractModuleBuilder;
import com.intellij.openapi.ui.ValidationInfo;
import com.jetbrains.edu.learning.courseFormat.Course;
import com.jetbrains.edu.learning.intellij.EduIntelliJProjectTemplate;
import icons.EducationalCoreIcons;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
public class EduRemoteCourseTemplate implements EduIntelliJProjectTemplate {
private final Course myCourse;
public EduRemoteCourseTemplate(Course course) {
myCourse = course;
}
@NotNull
@Override
public String getName() {
return myCourse.getName();
}
@Nullable
@Override
public String getDescription() {
return myCourse.getDescription();
}
@Override
public Icon getIcon() {
return EducationalCoreIcons.Stepik;
}
@NotNull
@Override
public AbstractModuleBuilder createModuleBuilder() {
return new EduRemoteCourseModuleBuilder(myCourse);
}
@Nullable
@Override
public ValidationInfo validateSettings() {
return null;
}
}
@@ -152,6 +152,8 @@ public class EduStepicConnector {
final List<RemoteCourse> courses = coursesContainer.courses;
for (RemoteCourse info : courses) {
if (!info.isAdaptive() && StringUtil.isEmptyOrSpaces(info.getType())) continue;
setCourseLanguage(info);
if (canBeOpened(info)) {
final ArrayList<StepicUser> authors = new ArrayList<>();
for (Integer instructor : info.getInstructors()) {
@@ -169,12 +171,19 @@ public class EduStepicConnector {
}
}
static boolean canBeOpened(RemoteCourse courseInfo) {
if (courseInfo.isAdaptive()) {
return true;
private static void setCourseLanguage(RemoteCourse info) {
if (info.isAdaptive()) {
info.setLanguage("Python"); // adaptive courses available only in PyCharm now
return;
}
String courseType = courseInfo.getType();
String courseType = info.getType();
final int separator = courseType.indexOf(" ");
assert separator != -1;
final String language = courseType.substring(separator + 1);
info.setLanguage(language);
}
static boolean canBeOpened(RemoteCourse courseInfo) {
final ArrayList<String> supportedLanguages = new ArrayList<>();
final LanguageExtensionPoint[] extensions = Extensions.getExtensions(EduPluginConfigurator.EP_NAME, null);
for (LanguageExtensionPoint extension : extensions) {
@@ -182,12 +191,14 @@ public class EduStepicConnector {
supportedLanguages.add(languageId);
}
if (courseInfo.isAdaptive()) {
return supportedLanguages.contains(courseInfo.getLanguageID());
}
String courseType = courseInfo.getType();
final List<String> typeLanguage = StringUtil.split(courseType, " ");
String prefix = typeLanguage.get(0);
if (typeLanguage.size() > 1) {
final String courseLanguage = typeLanguage.get(typeLanguage.size() - 1);
if (!supportedLanguages.contains(courseLanguage)) return false;
}
if (!supportedLanguages.contains(courseInfo.getLanguageID())) return false;
if (typeLanguage.size() < 2 || !prefix.startsWith(PYCHARM_PREFIX)) {
return false;
}
@@ -205,14 +216,8 @@ public class EduStepicConnector {
}
}
public static RemoteCourse getCourse(@NotNull final Project project, @NotNull final RemoteCourse course) {
final RemoteCourse remoteCourse = (RemoteCourse)course.copy();
public static RemoteCourse getCourse(@NotNull final Project project, @NotNull final RemoteCourse remoteCourse) {
if (!remoteCourse.isAdaptive()) {
String courseType = remoteCourse.getType();
final int separator = courseType.indexOf(" ");
assert separator != -1;
final String language = courseType.substring(separator + 1);
remoteCourse.setLanguage(language);
try {
for (Integer section : remoteCourse.getSections()) {
remoteCourse.addLessons(getLessons(section));
@@ -22,6 +22,7 @@ public class EducationalCoreIcons {
public static final Icon ResetTaskFile = load("/icons/com/jetbrains/edu/learning/ResetTaskFile.png"); // 16x16
public static final Icon Sandbox = load("/icons/com/jetbrains/edu/learning/Sandbox.png"); // 16x16
public static final Icon ShowHint = load("/icons/com/jetbrains/edu/learning/showHint.png"); // 16x16
public static final Icon Stepik = load("/icons/com/jetbrains/edu/learning/Stepik.png"); // 16x16
public static final Icon Task = load("/icons/com/jetbrains/edu/learning/Task.png"); // 16x16
public static final Icon TaskCompl = load("/icons/com/jetbrains/edu/learning/TaskCompl.png"); // 16x16
public static final Icon TaskDescription = load("/icons/com/jetbrains/edu/learning/TaskDescription.png"); // 13x13