new subtask action
authorLiana Bakradze <liana.bakradze@jetbrains.com>
Wed, 21 Sep 2016 13:09:37 +0000 (16:09 +0300)
committerliana.bakradze <liana.bakradze@jetbrains.com>
Thu, 17 Nov 2016 14:05:03 +0000 (17:05 +0300)
python/educational-core/course-creator/resources/META-INF/plugin.xml
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCLanguageManager.java
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAnswerPlaceholder.java
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCNewSubtaskAction.java [new file with mode: 0644]
python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java
python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/AnswerPlaceholder.java
python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/Task.java
python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCLanguageManager.java

index 253ecc51e3760260e2816a9411f3d83510759dab..134f7f4d4b28b530a103bdab9dfa50f67487c594 100644 (file)
@@ -87,6 +87,9 @@
 
     <action id="UnpackCourse" class="com.jetbrains.edu.coursecreator.actions.CCFromCourseArchive"/>
     <action id="GetCourse" class="com.jetbrains.edu.coursecreator.actions.CCGetCourseFromStepic"/>
+    <action class="com.jetbrains.edu.coursecreator.actions.CCNewSubtaskAction" id="CC.NewStep">
+      <add-to-group group-id="AnswerPlaceholderGroup" relative-to-action="DeleteAllPlaceholders" anchor="after"/>
+    </action>
   </actions>
 
 
index e797ad9a6160d0bfd9b6715a68e3590aa0ce87c1..32b41c7e8037a1b98f0c7f5f76d79c53c0439f90 100644 (file)
@@ -4,6 +4,7 @@ import com.intellij.ide.fileTemplates.FileTemplate;
 import com.intellij.lang.LanguageExtension;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.edu.learning.courseFormat.Task;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -26,4 +27,6 @@ public interface CCLanguageManager {
   default boolean isTestFile(VirtualFile file) {
     return false;
   }
+
+  default void createTestsForNewSubtask(@NotNull Project project, @NotNull Task task) {}
 }
index 8bc54aca86c38f12a3947de492994a9952d33153..9abfe83f87f7bcadbd2752bab78287efec77ecd2 100644 (file)
@@ -58,7 +58,7 @@ public class CCAddAnswerPlaceholder extends CCAnswerPlaceholderAction {
     FileDocumentManager.getInstance().saveDocument(document);
     final SelectionModel model = editor.getSelectionModel();
     final int offset = model.hasSelection() ? model.getSelectionStart() : editor.getCaretModel().getOffset();
-    int stepIndex = state.getTaskFile().getTask().getActiveStepIndex();
+    int stepIndex = state.getTaskFile().getTask().getActiveSubtaskIndex();
     final AnswerPlaceholder answerPlaceholder = new AnswerPlaceholder();
     answerPlaceholder.getSubtaskInfos().put(stepIndex, new AnswerPlaceholderSubtaskInfo());
     TaskFile taskFile = state.getTaskFile();
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCNewSubtaskAction.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCNewSubtaskAction.java
new file mode 100644 (file)
index 0000000..5f84c1b
--- /dev/null
@@ -0,0 +1,114 @@
+package com.jetbrains.edu.coursecreator.actions;
+
+import com.intellij.ide.fileTemplates.FileTemplate;
+import com.intellij.ide.fileTemplates.FileTemplateManager;
+import com.intellij.ide.fileTemplates.FileTemplateUtil;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.DumbAwareAction;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.io.FileUtilRt;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiManager;
+import com.jetbrains.edu.coursecreator.CCLanguageManager;
+import com.jetbrains.edu.coursecreator.CCUtils;
+import com.jetbrains.edu.coursecreator.settings.CCSettings;
+import com.jetbrains.edu.learning.StudyTaskManager;
+import com.jetbrains.edu.learning.StudyUtils;
+import com.jetbrains.edu.learning.core.EduNames;
+import com.jetbrains.edu.learning.courseFormat.Course;
+import com.jetbrains.edu.learning.courseFormat.Task;
+import com.jetbrains.edu.learning.courseFormat.TaskFile;
+import org.jetbrains.annotations.NotNull;
+
+
+public class CCNewSubtaskAction extends DumbAwareAction {
+  private static final Logger LOG = Logger.getInstance(CCNewSubtaskAction.class);
+  public static final String NEW_SUBTASK = "New Subtask";
+
+  public CCNewSubtaskAction() {
+    super(NEW_SUBTASK);
+  }
+
+  @Override
+  public void actionPerformed(AnActionEvent e) {
+    DataContext dataContext = e.getDataContext();
+    VirtualFile virtualFile = CommonDataKeys.VIRTUAL_FILE.getData(dataContext);
+    Editor editor = CommonDataKeys.EDITOR.getData(dataContext);
+    Project project = CommonDataKeys.PROJECT.getData(dataContext);
+    if (virtualFile == null || project == null || editor == null) {
+      return;
+    }
+    addSubtask(virtualFile, project);
+  }
+
+  public static void addSubtask(@NotNull VirtualFile virtualFile, @NotNull Project project) {
+    TaskFile taskFile = StudyUtils.getTaskFile(project, virtualFile);
+    if (taskFile == null) {
+      return;
+    }
+    VirtualFile taskDir = StudyUtils.getTaskDir(virtualFile);
+    if (taskDir == null) {
+      return;
+    }
+    Task task = taskFile.getTask();
+    createTestsForNewSubtask(project, task);
+    int num = task.getSubtaskNum();
+    createTaskDescriptionFile(project, taskDir, num);
+    task.setSubtaskNum(num + 1);
+    task.setActiveSubtaskIndex(num);
+    //TODO: switch subtask
+  }
+
+  private static void createTestsForNewSubtask(Project project, Task task) {
+    Course course = StudyTaskManager.getInstance(project).getCourse();
+    if (course == null) {
+      return;
+    }
+    CCLanguageManager manager = CCUtils.getStudyLanguageManager(course);
+    if (manager == null) {
+      return;
+    }
+    manager.createTestsForNewSubtask(project, task);
+  }
+
+  private static void createTaskDescriptionFile(Project project, VirtualFile taskDir, int index) {
+    String taskDescriptionFileName = StudyUtils.getTaskDescriptionFileName(CCSettings.getInstance().useHtmlAsDefaultTaskFormat());
+    FileTemplate taskTextTemplate = FileTemplateManager.getInstance(project).getInternalTemplate(taskDescriptionFileName);
+    PsiDirectory taskPsiDir = PsiManager.getInstance(project).findDirectory(taskDir);
+    if (taskTextTemplate != null && taskPsiDir != null) {
+      String nextTaskTextName = FileUtil.getNameWithoutExtension(taskDescriptionFileName) +
+                                EduNames.SUBTASK_MARKER +
+                                index + "." +
+                                FileUtilRt.getExtension(taskDescriptionFileName);
+      try {
+        FileTemplateUtil.createFromTemplate(taskTextTemplate, nextTaskTextName, null, taskPsiDir);
+      }
+      catch (Exception e) {
+        LOG.error(e);
+      }
+    }
+  }
+
+  @Override
+  public void update(AnActionEvent e) {
+    DataContext dataContext = e.getDataContext();
+    Presentation presentation = e.getPresentation();
+    presentation.setEnabledAndVisible(false);
+    VirtualFile virtualFile = CommonDataKeys.VIRTUAL_FILE.getData(dataContext);
+    Editor editor = CommonDataKeys.EDITOR.getData(dataContext);
+    Project project = CommonDataKeys.PROJECT.getData(dataContext);
+    if (virtualFile == null || project == null || editor == null) {
+      return;
+    }
+    if (CCUtils.isCourseCreator(project) && StudyUtils.getTaskForFile(project, virtualFile) != null) {
+      presentation.setEnabledAndVisible(true);
+    }
+  }
+}
\ No newline at end of file
index 9361f75c093bd64f65957730d1ef7a7f2b008324..0d73f5c58e7398894486eb03ca1dd3ba659f5571 100644 (file)
@@ -49,6 +49,8 @@ public class EduNames {
   public static final String ANSWER_PLACEHOLDER = "Answer Placeholder";
   public static final String SRC = "src";
 
+  public static final String SUBTASK_MARKER = "_subtask";
+
   private EduNames() {
   }
 
index a1532e804b2d7ac7dce0acee5fd0734a916ed582..0dc01b6f1f648f41748584f5d858257fb417f5bd 100644 (file)
@@ -212,7 +212,7 @@ public class AnswerPlaceholder {
     if (myTaskFile == null || myTaskFile.getTask() == null) {
       return mySubtaskInfos.get(0);
     }
-    int activeStepIndex = myTaskFile.getTask().getActiveStepIndex();
+    int activeStepIndex = myTaskFile.getTask().getActiveSubtaskIndex();
     return mySubtaskInfos.get(activeStepIndex);
   }
 }
index 7f4318dcfa82c014c8ecf52ed15f47b68ed2bb41..82c42c934f3488626f5b8283464d43f7dc3ecef4 100644 (file)
@@ -42,7 +42,8 @@ public class Task implements StudyItem {
   @Transient private Lesson myLesson;
   @Expose @SerializedName("update_date") private Date myUpdateDate;
 
-  private int myActiveStepIndex = 0;
+  private int myActiveSubtaskIndex = 0;
+  @Expose private int mySubtaskNum = 1;
 
   public Task() {}
 
@@ -253,11 +254,19 @@ public class Task implements StudyItem {
     return !date.after(myUpdateDate);
   }
 
-  public int getActiveStepIndex() {
-    return myActiveStepIndex;
+  public int getActiveSubtaskIndex() {
+    return myActiveSubtaskIndex;
   }
 
-  public void setActiveStepIndex(int activeStepIndex) {
-    myActiveStepIndex = activeStepIndex;
+  public void setActiveSubtaskIndex(int activeSubtaskIndex) {
+    myActiveSubtaskIndex = activeSubtaskIndex;
+  }
+
+  public int getSubtaskNum() {
+    return mySubtaskNum;
+  }
+
+  public void setSubtaskNum(int subtaskNum) {
+    mySubtaskNum = subtaskNum;
   }
 }
index 93e6abfcc5fb9291fc7ffe4630de25efeffcd0c7..f9586c66bca1c651f8536cf61ed22efd83343318 100644 (file)
@@ -2,15 +2,26 @@ package com.jetbrains.edu.coursecreator;
 
 import com.intellij.ide.fileTemplates.FileTemplate;
 import com.intellij.ide.fileTemplates.FileTemplateManager;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
 import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.io.FileUtilRt;
 import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.util.DocumentUtil;
+import com.jetbrains.edu.learning.StudyTaskManager;
 import com.jetbrains.edu.learning.core.EduNames;
+import com.jetbrains.edu.learning.courseFormat.Task;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.io.File;
+import java.io.IOException;
 
 public class PyCCLanguageManager implements CCLanguageManager {
+  private static final Logger LOG = Logger.getInstance(PyCCLanguageManager.class);
 
   @Nullable
   @Override
@@ -45,6 +56,59 @@ public class PyCCLanguageManager implements CCLanguageManager {
 
   @Override
   public boolean isTestFile(VirtualFile file) {
-    return EduNames.TESTS_FILE.equals(file.getName());
+    String name = file.getName();
+    if (EduNames.TESTS_FILE.equals(name)) {
+      return true;
+    }
+    return name.contains(FileUtil.getNameWithoutExtension(EduNames.TESTS_FILE)) && name.contains(EduNames.SUBTASK_MARKER);
+  }
+
+  @Override
+  public void createTestsForNewSubtask(@NotNull Project project, @NotNull Task task) {
+    VirtualFile taskDir = task.getTaskDir(project);
+    if (taskDir == null) {
+      return;
+    }
+
+    int prevSubtaskIndex = task.getActiveSubtaskIndex();
+    String name = prevSubtaskIndex == 0 ? EduNames.TESTS_FILE : getSubtaskTestsFileName(prevSubtaskIndex);
+    VirtualFile testsFile = taskDir.findChild(name);
+    if (testsFile == null) {
+      return;
+    }
+    Document document = FileDocumentManager.getInstance().getDocument(testsFile);
+    if (document == null) {
+      return;
+    }
+    CharSequence prevTestText = document.getCharsSequence();
+    int nextSubtaskIndex = prevSubtaskIndex + 1;
+    String nextSubtaskTestsFileName = getSubtaskTestsFileName(nextSubtaskIndex);
+    ApplicationManager.getApplication().runWriteAction(() -> {
+      try {
+        VirtualFile nextSubtaskTestsFile = taskDir.createChildData(this, nextSubtaskTestsFileName);
+        StudyTaskManager.getInstance(project).addInvisibleFiles(nextSubtaskTestsFile.getPath());
+        Document nextSubtaskDocument = FileDocumentManager.getInstance().getDocument(nextSubtaskTestsFile);
+        if (nextSubtaskDocument == null) {
+          return;
+        }
+        String header = "# This is test for subtask " + nextSubtaskIndex + ". We've already copied tests from previous subtask here.\n\n";
+        DocumentUtil.writeInRunUndoTransparentAction(() -> {
+          nextSubtaskDocument.insertString(0, header);
+          nextSubtaskDocument.insertString(header.length(), prevTestText);
+          FileDocumentManager.getInstance().saveDocument(nextSubtaskDocument);
+        });
+      }
+      catch (IOException e) {
+        LOG.error(e);
+      }
+    });
+  }
+
+  @NotNull
+  public static String getSubtaskTestsFileName(int index) {
+    return index == 0 ? EduNames.TESTS_FILE : FileUtil.getNameWithoutExtension(EduNames.TESTS_FILE) +
+                                              EduNames.SUBTASK_MARKER +
+                                              index + "." +
+                                              FileUtilRt.getExtension(EduNames.TESTS_FILE);
   }
-}
+}
\ No newline at end of file