EDU-339 Unable to create new task after deletion
authorliana.bakradze <liana.bakradze@jetbrains.com>
Tue, 4 Aug 2015 19:23:31 +0000 (22:23 +0300)
committerliana.bakradze <liana.bakradze@jetbrains.com>
Tue, 4 Aug 2015 19:25:22 +0000 (22:25 +0300)
python/educational/course-creator/src/com/jetbrains/edu/coursecreator/CCFileDeletedListener.java [new file with mode: 0644]
python/educational/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectComponent.java
python/educational/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java
python/educational/src/com/jetbrains/edu/EduUtils.java
python/educational/src/com/jetbrains/edu/courseFormat/AnswerPlaceholder.java
python/educational/src/com/jetbrains/edu/courseFormat/Course.java
python/educational/src/com/jetbrains/edu/courseFormat/Lesson.java
python/educational/src/com/jetbrains/edu/courseFormat/StudyOrderable.java [new file with mode: 0644]
python/educational/src/com/jetbrains/edu/courseFormat/Task.java
python/educational/src/com/jetbrains/edu/courseFormat/TaskFile.java

diff --git a/python/educational/course-creator/src/com/jetbrains/edu/coursecreator/CCFileDeletedListener.java b/python/educational/course-creator/src/com/jetbrains/edu/coursecreator/CCFileDeletedListener.java
new file mode 100644 (file)
index 0000000..095cc44
--- /dev/null
@@ -0,0 +1,106 @@
+package com.jetbrains.edu.coursecreator;
+
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ModifiableRootModel;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.VirtualFileAdapter;
+import com.intellij.openapi.vfs.VirtualFileEvent;
+import com.intellij.util.Function;
+import com.jetbrains.edu.EduNames;
+import com.jetbrains.edu.EduUtils;
+import com.jetbrains.edu.courseFormat.*;
+import com.jetbrains.edu.coursecreator.actions.CCRunTestsAction;
+import org.jetbrains.annotations.NotNull;
+
+class CCFileDeletedListener extends VirtualFileAdapter {
+
+  private final Project myProject;
+
+  CCFileDeletedListener(@NotNull final Project project) {
+    myProject = project;
+  }
+
+  @Override
+  public void fileDeleted(@NotNull VirtualFileEvent event) {
+    if (myProject.isDisposed() || !myProject.isOpen()) {
+      return;
+    }
+    VirtualFile removedFile = event.getFile();
+    final TaskFile taskFile = CCProjectService.getInstance(myProject).getTaskFile(removedFile);
+    if (taskFile != null) {
+      deleteAnswerFile(removedFile, taskFile);
+      return;
+    }
+    Course course = CCProjectService.getInstance(myProject).getCourse();
+    if (course == null) {
+      return;
+    }
+    if (removedFile.getName().contains(EduNames.TASK)) {
+      deleteTask(course, removedFile, myProject);
+    }
+    if (removedFile.getName().contains(EduNames.LESSON)) {
+      deleteLesson(course, removedFile);
+    }
+  }
+
+  private void deleteLesson(@NotNull final Course course, @NotNull final VirtualFile removedLessonFile) {
+    Lesson removedLesson = course.getLesson(removedLessonFile.getName());
+    if (removedLesson == null) {
+      return;
+    }
+    VirtualFile courseDir = myProject.getBaseDir();
+    CCUtils.updateHigherElements(courseDir.getChildren(), new Function<VirtualFile, StudyOrderable>() {
+      @Override
+      public StudyOrderable fun(VirtualFile file) {
+        return course.getLesson(file.getName());
+      }
+    }, removedLesson, EduNames.LESSON);
+    course.getLessons().remove(removedLesson);
+  }
+
+  private static void deleteTask(@NotNull final Course course, @NotNull final VirtualFile removedTask, @NotNull final Project project) {
+    VirtualFile lessonDir = removedTask.getParent();
+    if (lessonDir == null || !lessonDir.getName().contains(EduNames.LESSON)) {
+      return;
+    }
+    final Lesson lesson = course.getLesson(lessonDir.getName());
+    if (lesson == null) {
+      return;
+    }
+    Task task = lesson.getTask(removedTask.getName());
+    if (task == null) {
+      return;
+    }
+    CCUtils.updateHigherElements(lessonDir.getChildren(), new Function<VirtualFile, StudyOrderable>() {
+      @Override
+      public StudyOrderable fun(VirtualFile file) {
+        return lesson.getTask(file.getName());
+      }
+    }, task, EduNames.TASK);
+    ModifiableRootModel model = EduUtils.getModel(lessonDir, project);
+    if (model == null) {
+      return;
+    }
+    EduUtils.commitAndSaveModel(model);
+    lesson.getTaskList().remove(task);
+  }
+
+  private void deleteAnswerFile(@NotNull final VirtualFile removedAnswerFile, TaskFile taskFile) {
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      @Override
+      public void run() {
+        VirtualFile taskDir = removedAnswerFile.getParent();
+        if (taskDir != null) {
+          CCRunTestsAction.clearTestEnvironment(taskDir, myProject);
+        }
+      }
+    });
+    String name = CCProjectService.getRealTaskFileName(removedAnswerFile.getName());
+    Task task = taskFile.getTask();
+    if (task == null) {
+      return;
+    }
+    task.getTaskFiles().remove(name);
+  }
+}
index 22a5c01969e37e9320004de01923524fce88bc76..b983a497875f075f17b8c1c82a4a0529f7728270 100644 (file)
@@ -13,15 +13,8 @@ import com.intellij.openapi.project.Project;
 import com.intellij.openapi.project.ProjectManager;
 import com.intellij.openapi.startup.StartupManager;
 import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.openapi.vfs.VirtualFileAdapter;
-import com.intellij.openapi.vfs.VirtualFileEvent;
 import com.intellij.openapi.vfs.VirtualFileManager;
-import com.jetbrains.edu.EduNames;
 import com.jetbrains.edu.courseFormat.Course;
-import com.jetbrains.edu.courseFormat.Lesson;
-import com.jetbrains.edu.courseFormat.Task;
-import com.jetbrains.edu.courseFormat.TaskFile;
-import com.jetbrains.edu.coursecreator.actions.CCRunTestsAction;
 import org.jetbrains.annotations.NotNull;
 
 import java.io.IOException;
@@ -29,7 +22,7 @@ import java.io.IOException;
 public class CCProjectComponent implements ProjectComponent {
   private static final Logger LOG = Logger.getInstance(CCProjectComponent.class.getName());
   private final Project myProject;
-  private FileDeletedListener myListener;
+  private CCFileDeletedListener myListener;
 
   public CCProjectComponent(Project project) {
     myProject = project;
@@ -76,7 +69,7 @@ public class CCProjectComponent implements ProjectComponent {
                 }
               }
             });
-          myListener = new FileDeletedListener();
+          myListener = new CCFileDeletedListener(myProject);
           VirtualFileManager.getInstance().addVirtualFileListener(myListener);
           final CCEditorFactoryListener editorFactoryListener = new CCEditorFactoryListener();
           EditorFactory.getInstance().addEditorFactoryListener(editorFactoryListener, myProject);
@@ -102,98 +95,4 @@ public class CCProjectComponent implements ProjectComponent {
       VirtualFileManager.getInstance().removeVirtualFileListener(myListener);
     }
   }
-
-  private class FileDeletedListener extends VirtualFileAdapter {
-
-    @Override
-    public void fileDeleted(@NotNull VirtualFileEvent event) {
-      if (myProject.isDisposed() || !myProject.isOpen()) {
-        return;
-      }
-      Course course = CCProjectService.getInstance(myProject).getCourse();
-      if (course == null) {
-        return;
-      }
-      VirtualFile removedFile = event.getFile();
-      if (removedFile.getName().contains(".answer")) {
-        deleteTaskFile(removedFile);
-      }
-      if (removedFile.getName().contains(EduNames.TASK)) {
-        deleteTask(removedFile);
-      }
-      if (removedFile.getName().contains(EduNames.LESSON)) {
-        deleteLesson(course, removedFile);
-      }
-    }
-
-    private void deleteLesson(@NotNull final Course course, @NotNull final VirtualFile file) {
-      VirtualFile courseDir = file.getParent();
-      if (!courseDir.getName().equals(myProject.getName())) {
-        return;
-      }
-      Lesson lesson = course.getLesson(file.getName());
-      if (lesson != null) {
-        course.getLessons().remove(lesson);
-      }
-    }
-
-    private void deleteTask(@NotNull final VirtualFile removedFile) {
-      VirtualFile lessonDir = removedFile.getParent();
-      final CCProjectService projectService = CCProjectService.getInstance(myProject);
-      if (lessonDir == null || !lessonDir.getName().contains(EduNames.LESSON)) {
-        return;
-      }
-      VirtualFile courseDir = lessonDir.getParent();
-      if (!courseDir.getName().equals(myProject.getName())) {
-        return;
-      }
-      final Course course = projectService.getCourse();
-      Lesson lesson = course.getLesson(lessonDir.getName());
-      if (lesson == null) {
-        return;
-      }
-      Task task = lesson.getTask(removedFile.getName());
-      if (task == null) {
-        return;
-      }
-      lesson.getTaskList().remove(task);
-    }
-
-    private void deleteTaskFile(@NotNull final VirtualFile removedFile) {
-      final CCProjectService projectService = CCProjectService.getInstance(myProject);
-      final VirtualFile taskDir = removedFile.getParent();
-      if (taskDir == null || !taskDir.getName().contains(EduNames.TASK)) {
-        return;
-      }
-      VirtualFile lessonDir = taskDir.getParent();
-      if (lessonDir == null || !lessonDir.getName().contains(EduNames.LESSON)) {
-        return;
-      }
-      VirtualFile courseDir = lessonDir.getParent();
-      if (!courseDir.getName().equals(myProject.getName())) {
-        return;
-      }
-      final Course course = projectService.getCourse();
-      Lesson lesson = course.getLesson(lessonDir.getName());
-      if (lesson == null) {
-        return;
-      }
-      Task task = lesson.getTask(taskDir.getName());
-      if (task == null) {
-        return;
-      }
-      TaskFile taskFile = projectService.getTaskFile(removedFile);
-      if (taskFile == null) {
-        return;
-      }
-      ApplicationManager.getApplication().runWriteAction(new Runnable() {
-        @Override
-        public void run() {
-          CCRunTestsAction.clearTestEnvironment(taskDir, myProject);
-        }
-      });
-      String name = CCProjectService.getRealTaskFileName(removedFile.getName());
-      task.getTaskFiles().remove(name);
-    }
-  }
 }
index 2e46c635d8a89381805dac09ca14b137fc0efad7..aaaccb4939c8b73be1ae7b84b75aa19b522ee127 100644 (file)
@@ -1,14 +1,22 @@
 package com.jetbrains.edu.coursecreator;
 
 import com.intellij.lang.Language;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.psi.PsiElement;
 import com.intellij.psi.PsiFile;
+import com.intellij.util.Function;
 import com.jetbrains.edu.courseFormat.Course;
+import com.jetbrains.edu.courseFormat.StudyOrderable;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
+import java.io.IOException;
+
 public class CCUtils {
+  private static final Logger LOG = Logger.getInstance(CCUtils.class);
+
   @Nullable
   public static CCLanguageManager getStudyLanguageManager(@NotNull final Course course) {
     Language language = Language.findLanguageByID(course.getLanguage());
@@ -22,4 +30,41 @@ public class CCUtils {
     VirtualFile file = ((PsiFile)element).getVirtualFile();
     return CCProjectService.getInstance(element.getProject()).isAnswerFile(file);
   }
+
+  /**
+   * This method decreases index and updates directory names of
+   * all tasks/lessons that have higher index than specified object
+   * @param dirs directories that are used to get tasks/lessons
+   * @param getStudyOrderable function that is used to get task/lesson from VirtualFile. This function can return null
+   * @param thresholdObject task/lesson which index is used as threshold
+   * @param prefix task or lesson directory name prefix
+   */
+  public static void updateHigherElements(VirtualFile[] dirs,
+                                          @NotNull Function<VirtualFile, StudyOrderable> getStudyOrderable,
+                                          @NotNull final StudyOrderable thresholdObject,
+                                          final String prefix) {
+    int threshold = thresholdObject.getIndex();
+    for (final VirtualFile dir : dirs) {
+      final StudyOrderable orderable = getStudyOrderable.fun(dir);
+      if (orderable == null) {
+        continue;
+      }
+      int index = orderable.getIndex();
+      if (index > threshold) {
+        final int newIndex = index - 1;
+        orderable.setIndex(newIndex);
+        ApplicationManager.getApplication().runWriteAction(new Runnable() {
+          @Override
+          public void run() {
+            try {
+              dir.rename(this, prefix + newIndex);
+            }
+            catch (IOException e) {
+              LOG.error(e);
+            }
+          }
+        });
+      }
+    }
+  }
 }
index 3fc34c3e52e7d71cc367e2a97b4cfde86e24088e..f80c843b27229191d1a0ad6d23e22094f97fe6c2 100644 (file)
@@ -34,27 +34,38 @@ public class EduUtils {
   }
   private static final Logger LOG = Logger.getInstance(EduUtils.class.getName());
 
+  public static void commitAndSaveModel(final ModifiableRootModel model) {
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      @Override
+      public void run() {
+        model.commit();
+        model.getProject().save();
+      }
+    });
+  }
 
-  public static void markDirAsSourceRoot(@NotNull final VirtualFile dir, @NotNull final Project project) {
+  @Nullable
+  public static ModifiableRootModel getModel(@NotNull VirtualFile dir, @NotNull Project project) {
     final Module module = ModuleUtilCore.findModuleForFile(dir, project);
     if (module == null) {
       LOG.info("Module for " + dir.getPath() + " was not found");
+      return null;
+    }
+    return ModuleRootManager.getInstance(module).getModifiableModel();
+  }
+
+  public static void markDirAsSourceRoot(@NotNull final VirtualFile dir, @NotNull final Project project) {
+    final ModifiableRootModel model = getModel(dir, project);
+    if (model == null) {
       return;
     }
-    final ModifiableRootModel model = ModuleRootManager.getInstance(module).getModifiableModel();
     final ContentEntry entry = MarkRootActionBase.findContentEntry(model, dir);
     if (entry == null) {
       LOG.info("Content entry for " + dir.getPath() + " was not found");
       return;
     }
     entry.addSourceFolder(dir, false);
-    ApplicationManager.getApplication().runWriteAction(new Runnable() {
-      @Override
-      public void run() {
-        model.commit();
-        module.getProject().save();
-      }
-    });
+    commitAndSaveModel(model);
   }
 
   public static void enableAction(@NotNull final AnActionEvent event, boolean isEnable) {
index a2ffd42ef345fd1a0b0de73e0107b43d9ddb50e1..b71df1b5fb5f28db8009ed163d80e895ae36d1f5 100644 (file)
@@ -11,7 +11,7 @@ import org.jetbrains.annotations.Nullable;
  * Implementation of windows which user should type in
  */
 
-public class AnswerPlaceholder {
+public class AnswerPlaceholder implements StudyOrderable {
 
   @Expose private int line = 0;
   @Expose private int start = 0;
index 413b251b10354ac258666051eba6fb90c15f06c1..98fdc0ea0e68ec0d8d09bf2ca13d4ce93c57bc3d 100644 (file)
@@ -13,7 +13,7 @@ import org.jetbrains.annotations.NotNull;
 import java.util.ArrayList;
 import java.util.List;
 
-public class Course {
+public class Course implements Named {
   @Expose
   private List<Lesson> lessons = new ArrayList<Lesson>();
 
index 382255acfbdfb1a6743eaf0b50f4b8315fa4f2d7..5c7d9ceb2745a0aa06bee19e7d0ac85c273fa14c 100644 (file)
@@ -10,7 +10,7 @@ import org.jetbrains.annotations.NotNull;
 import java.util.ArrayList;
 import java.util.List;
 
-public class Lesson implements Named{
+public class Lesson implements Named, StudyOrderable {
   @Transient
   public int id;
   @Transient
diff --git a/python/educational/src/com/jetbrains/edu/courseFormat/StudyOrderable.java b/python/educational/src/com/jetbrains/edu/courseFormat/StudyOrderable.java
new file mode 100644 (file)
index 0000000..1d773e3
--- /dev/null
@@ -0,0 +1,6 @@
+package com.jetbrains.edu.courseFormat;
+
+public interface StudyOrderable {
+  int getIndex();
+  void setIndex(int index);
+}
index 1503d0242e1ae08e316d3975164d44538327c10d..8fd57c94351fb2425a09f1c1cb2e44472d45f790 100644 (file)
@@ -17,7 +17,7 @@ import java.util.Map;
 /**
  * Implementation of task which contains task files, tests, input file for tests
  */
-public class Task implements Named {
+public class Task implements Named, StudyOrderable {
   @Expose
   private String name;
 
index af372c809b7f775d41145b8d4d1069bf22aa069c..7b51b7d174b3f3cc0ca06d2642971d62c1a4fa04 100644 (file)
@@ -17,7 +17,7 @@ import java.util.List;
  * which is visible to student in project view
  */
 
-public class TaskFile {
+public class TaskFile implements StudyOrderable {
   @SerializedName("placeholders")
   @Expose
   private List<AnswerPlaceholder> myAnswerPlaceholders = new ArrayList<AnswerPlaceholder>();