Merge remote-tracking branch 'origin/liana/edu-tests'
authorliana.bakradze <liana.bakradze@jetbrains.com>
Mon, 19 Sep 2016 13:04:48 +0000 (16:04 +0300)
committerliana.bakradze <liana.bakradze@jetbrains.com>
Mon, 19 Sep 2016 13:04:48 +0000 (16:04 +0300)
# Conflicts:
# python/educational-core/student/src/com/jetbrains/edu/learning/ui/CCCreateAnswerPlaceholderPanel.java

30 files changed:
python/educational-core/course-creator/course-creator.iml
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.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/CCAddAsTaskFile.java
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCEditAnswerPlaceholder.java
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCHideFromStudent.java
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCShowPreview.java
python/educational-core/course-creator/testData/actions/addPlaceholder/deletePlaceholder_after.txt [new file with mode: 0644]
python/educational-core/course-creator/testData/actions/addPlaceholder/deletePlaceholder_before.txt [new file with mode: 0644]
python/educational-core/course-creator/testData/actions/addPlaceholder/onePlaceholder_after.txt [new file with mode: 0644]
python/educational-core/course-creator/testData/actions/addPlaceholder/onePlaceholder_before.txt [new file with mode: 0644]
python/educational-core/course-creator/testData/actions/addPlaceholder/placeholderIntersection.txt [new file with mode: 0644]
python/educational-core/course-creator/testData/actions/addPlaceholder/withoutSelection_after.txt [new file with mode: 0644]
python/educational-core/course-creator/testData/actions/addPlaceholder/withoutSelection_before.txt [new file with mode: 0644]
python/educational-core/course-creator/testData/actions/preview/noplaceholders.txt [new file with mode: 0644]
python/educational-core/course-creator/testData/actions/preview/several_after.txt [new file with mode: 0644]
python/educational-core/course-creator/testData/actions/preview/several_before.txt [new file with mode: 0644]
python/educational-core/course-creator/testData/actions/preview/test_after.txt [new file with mode: 0644]
python/educational-core/course-creator/testData/actions/preview/test_before.txt [new file with mode: 0644]
python/educational-core/course-creator/testData/actions/taskFileActions/nonTaskFile.txt [new file with mode: 0644]
python/educational-core/course-creator/testData/actions/taskFileActions/taskFile.txt [new file with mode: 0644]
python/educational-core/course-creator/testSrc/com/jetbrains/edu/coursecreator/CCTestCase.java [new file with mode: 0644]
python/educational-core/course-creator/testSrc/com/jetbrains/edu/coursecreator/CCTestsUtil.java [new file with mode: 0644]
python/educational-core/course-creator/testSrc/com/jetbrains/edu/coursecreator/actions/CCAnswerPlaceholderActionTest.java [new file with mode: 0644]
python/educational-core/course-creator/testSrc/com/jetbrains/edu/coursecreator/actions/CCShowPreviewTest.java [new file with mode: 0644]
python/educational-core/course-creator/testSrc/com/jetbrains/edu/coursecreator/actions/CCTaskFileActionTest.java [new file with mode: 0644]
python/educational-core/student/src/com/jetbrains/edu/learning/ui/CCCreateAnswerPlaceholderDialog.java
python/educational-core/student/src/com/jetbrains/edu/learning/ui/CCCreateAnswerPlaceholderPanel.java
python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyHint.kt

index 6c6bf51f6d20555ab40cbd8278de5a0594e660f5..7f8af6dd20f2873d7a7c0da40877fd3a2ad0fb66 100644 (file)
@@ -5,6 +5,7 @@
     <content url="file://$MODULE_DIR$">
       <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
       <sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/testSrc" isTestSource="true" />
       <excludeFolder url="file://$MODULE_DIR$/../../educational/course-creator/src/com/jetbrains/edu/coursecreator/format" />
     </content>
     <orderEntry type="inheritedJdk" />
@@ -13,5 +14,6 @@
     <orderEntry type="module" module-name="lang-impl" />
     <orderEntry type="module" module-name="student" />
     <orderEntry type="library" name="Guava" level="project" />
+    <orderEntry type="module" module-name="testFramework" scope="TEST" />
   </component>
 </module>
\ No newline at end of file
index 5a4e3d5b25f015c2fa370496b7ffb52a523cae08..27e5c6534f4b9b8e60e99cd139fd5e5743215038 100644 (file)
@@ -2,7 +2,6 @@ package com.jetbrains.edu.coursecreator;
 
 import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
-import com.intellij.ide.projectView.actions.MarkRootActionBase;
 import com.intellij.lang.Language;
 import com.intellij.openapi.actionSystem.AnActionEvent;
 import com.intellij.openapi.actionSystem.Presentation;
@@ -12,9 +11,8 @@ import com.intellij.openapi.module.Module;
 import com.intellij.openapi.project.DumbModePermission;
 import com.intellij.openapi.project.DumbService;
 import com.intellij.openapi.project.Project;
-import com.intellij.openapi.roots.ContentEntry;
-import com.intellij.openapi.roots.ModifiableRootModel;
-import com.intellij.openapi.roots.ModuleRootManager;
+import com.intellij.openapi.roots.ModuleRootModificationUtil;
+import com.intellij.openapi.roots.ProjectRootManager;
 import com.intellij.openapi.util.Ref;
 import com.intellij.openapi.util.io.FileUtil;
 import com.intellij.openapi.vfs.LocalFileSystem;
@@ -128,15 +126,12 @@ public class CCUtils {
           public void run() {
             try {
               generatedRoot.set(baseDir.createChildDirectory(this, GENERATED_FILES_FOLDER));
-              final ModifiableRootModel model = ModuleRootManager.getInstance(module).getModifiableModel();
-              ContentEntry entry = MarkRootActionBase.findContentEntry(model, generatedRoot.get());
-              if (entry == null) {
-                LOG.info("Failed to find contentEntry for archive folder");
+              VirtualFile contentRootForFile =
+                ProjectRootManager.getInstance(module.getProject()).getFileIndex().getContentRootForFile(generatedRoot.get());
+              if (contentRootForFile == null) {
                 return;
               }
-              entry.addExcludeFolder(generatedRoot.get());
-              model.commit();
-              module.getProject().save();
+              ModuleRootModificationUtil.updateExcludedFolders(module, contentRootForFile, Collections.emptyList(), Collections.singletonList(generatedRoot.get().getUrl()));
             }
             catch (IOException e) {
               LOG.info("Failed to create folder for generated files", e);
index 791bfaabce5fcc52dec63deb0b08e06c187c2f50..572db02ec8d1fd60f1ae3dccacf2c1aa5bac0ec9 100644 (file)
@@ -22,10 +22,19 @@ public class CCVirtualFileListener extends VirtualFileAdapter {
   @Override
   public void fileCreated(@NotNull VirtualFileEvent event) {
     VirtualFile createdFile = event.getFile();
+    if (createdFile.isDirectory()) {
+      return;
+    }
+    if (createdFile.getPath().contains(CCUtils.GENERATED_FILES_FOLDER)) {
+      return;
+    }
     Project project = ProjectUtil.guessProjectForFile(createdFile);
     if (project == null) {
       return;
     }
+    if (project.getBasePath() !=null && !FileUtil.isAncestor(project.getBasePath(), createdFile.getPath(), true)) {
+      return;
+    }
     Course course = StudyTaskManager.getInstance(project).getCourse();
     if (course == null || !CCUtils.isCourseCreator(project)) {
       return;
@@ -76,6 +85,9 @@ public class CCVirtualFileListener extends VirtualFileAdapter {
     if (project == null) {
       return;
     }
+    if (project.getBasePath() !=null && !FileUtil.isAncestor(project.getBasePath(), removedFile.getPath(), true)) {
+      return;
+    }
     Course course = StudyTaskManager.getInstance(project).getCourse();
     if (course == null || path.contains(FileUtil.toSystemIndependentName(course.getCourseDirectory()))) {
       return;
@@ -125,7 +137,6 @@ public class CCVirtualFileListener extends VirtualFileAdapter {
     if (task == null) {
       return;
     }
-    //TODO: remove from steps as well
     task.getTaskFiles().remove(removedTaskFile.getName());
   }
 }
index c6cfa9df1b21e185f7c39e8f9394b026231059d4..b2f26711ac5ad7dce3f629f8833387877b418fe3 100644 (file)
@@ -9,7 +9,7 @@ import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.editor.SelectionModel;
 import com.intellij.openapi.fileEditor.FileDocumentManager;
 import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.psi.PsiDocumentManager;
 import com.intellij.psi.PsiFile;
 import com.intellij.ui.JBColor;
@@ -45,7 +45,7 @@ public class CCAddAnswerPlaceholder extends CCAnswerPlaceholderAction {
     return false;
   }
 
-  private static void addPlaceholder(@NotNull CCState state) {
+  private void addPlaceholder(@NotNull CCState state) {
     Editor editor = state.getEditor();
     Project project = state.getProject();
     PsiFile file = state.getFile();
@@ -65,11 +65,14 @@ public class CCAddAnswerPlaceholder extends CCAnswerPlaceholderAction {
     String defaultPlaceholderText = "type here";
     answerPlaceholder.setPossibleAnswer(model.hasSelection() ? model.getSelectedText() : defaultPlaceholderText);
 
-    CCCreateAnswerPlaceholderDialog dlg = new CCCreateAnswerPlaceholderDialog(project, answerPlaceholder);
-    dlg.show();
-    if (dlg.getExitCode() != DialogWrapper.OK_EXIT_CODE) {
+    CCCreateAnswerPlaceholderDialog dlg = createDialog(project, answerPlaceholder);
+    if (!dlg.showAndGet()) {
       return;
     }
+    String answerPlaceholderText = dlg.getTaskText();
+    answerPlaceholder.setTaskText(StringUtil.notNullize(answerPlaceholderText));
+    answerPlaceholder.setLength(StringUtil.notNullize(answerPlaceholderText).length());
+    answerPlaceholder.setHints(dlg.getHints());
 
     if (!model.hasSelection()) {
       DocumentUtil.writeInRunUndoTransparentAction(() -> document.insertString(offset, defaultPlaceholderText));
@@ -180,4 +183,8 @@ public class CCAddAnswerPlaceholder extends CCAnswerPlaceholderAction {
     }
     return state.getAnswerPlaceholder() != null;
   }
+
+  protected CCCreateAnswerPlaceholderDialog createDialog(Project project, AnswerPlaceholder answerPlaceholder) {
+    return new CCCreateAnswerPlaceholderDialog(project, StringUtil.notNullize(answerPlaceholder.getTaskText()), answerPlaceholder.getHints());
+  }
 }
\ No newline at end of file
index f98a0223f4511e11d9f8533e9e5ff9cc39207d71..925bc592fea3363ce28676ad9613f50b0ee42720 100644 (file)
@@ -1,8 +1,7 @@
 package com.jetbrains.edu.coursecreator.actions;
 
 import com.intellij.ide.projectView.ProjectView;
-import com.intellij.openapi.command.undo.DocumentReference;
-import com.intellij.openapi.command.undo.UndoableAction;
+import com.intellij.openapi.command.undo.BasicUndoableAction;
 import com.intellij.openapi.command.undo.UnexpectedUndoException;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.vfs.VirtualFile;
@@ -12,7 +11,6 @@ import com.jetbrains.edu.learning.core.EduUtils;
 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.Nullable;
 
 public class CCAddAsTaskFile extends CCTaskFileActionBase {
   public static final String ACTION_NAME = "Make Visible to Student";
@@ -30,7 +28,7 @@ public class CCAddAsTaskFile extends CCTaskFileActionBase {
     return StudyUtils.getTaskFile(project, file) == null && !CCUtils.isTestsFile(project, file);
   }
 
-  private static class AddTaskFile implements UndoableAction {
+  private static class AddTaskFile extends BasicUndoableAction {
     private final VirtualFile myFile;
     private TaskFile myTaskFile;
     private final Course myCourse;
@@ -38,6 +36,7 @@ public class CCAddAsTaskFile extends CCTaskFileActionBase {
     private final Task myTask;
 
     public AddTaskFile(VirtualFile file, TaskFile taskFile, Course course, Project project, Task task) {
+      super(file);
       myFile = file;
       myTaskFile = taskFile;
       myCourse = course;
@@ -63,12 +62,6 @@ public class CCAddAsTaskFile extends CCTaskFileActionBase {
       ProjectView.getInstance(myProject).refresh();
     }
 
-    @Nullable
-    @Override
-    public DocumentReference[] getAffectedDocuments() {
-      return new DocumentReference[0];
-    }
-
     @Override
     public boolean isGlobal() {
       return true;
index f524329ad4feba6e9cb91af0a3dbd7685af68397..5dfb491d060a7bf8bacd51242959f4fa72a0bad2 100644 (file)
@@ -26,8 +26,7 @@ public class CCEditAnswerPlaceholder extends CCAnswerPlaceholderAction {
     if (answerPlaceholder == null) {
       return;
     }
-    CCCreateAnswerPlaceholderDialog dlg = new CCCreateAnswerPlaceholderDialog(project, answerPlaceholder
-    );
+    CCCreateAnswerPlaceholderDialog dlg = new CCCreateAnswerPlaceholderDialog(project, answerPlaceholder.getTaskText(), answerPlaceholder.getHints());
     dlg.setTitle("Edit Answer Placeholder");
     dlg.show();
   }
index 3ce85b39d7f8d81cbc04dc66080df4d5f4f89765..8d3100240063c2266e93f76cdd8511b7f69a6848 100644 (file)
@@ -2,14 +2,13 @@ package com.jetbrains.edu.coursecreator.actions;
 
 import com.intellij.ide.projectView.ProjectView;
 import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.command.undo.DocumentReference;
-import com.intellij.openapi.command.undo.UndoableAction;
+import com.intellij.openapi.command.undo.BasicUndoableAction;
 import com.intellij.openapi.command.undo.UnexpectedUndoException;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.fileEditor.FileEditor;
 import com.intellij.openapi.fileEditor.FileEditorManager;
-import com.intellij.openapi.fileEditor.impl.text.PsiAwareTextEditorImpl;
+import com.intellij.openapi.fileEditor.TextEditor;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.jetbrains.edu.coursecreator.CCUtils;
@@ -18,7 +17,6 @@ import com.jetbrains.edu.learning.core.EduUtils;
 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.Nullable;
 
 import java.io.IOException;
 import java.util.Map;
@@ -41,7 +39,7 @@ public class CCHideFromStudent extends CCTaskFileActionBase {
     EduUtils.runUndoableAction(project, ACTION_NAME, new HideTaskFile(project, course, file, task, taskFile));
   }
 
-  private static class HideTaskFile implements UndoableAction {
+  private static class HideTaskFile extends BasicUndoableAction {
 
     private final Project myProject;
     private final Course myCourse;
@@ -50,6 +48,7 @@ public class CCHideFromStudent extends CCTaskFileActionBase {
     private final TaskFile myTaskFile;
 
     public HideTaskFile(Project project, Course course, VirtualFile file, Task task, TaskFile taskFile) {
+      super(file);
       myProject = project;
       myCourse = course;
       myFile = file;
@@ -63,8 +62,8 @@ public class CCHideFromStudent extends CCTaskFileActionBase {
       CCUtils.createResourceFile(myFile, myCourse, StudyUtils.getTaskDir(myFile));
       if (!myTaskFile.getAnswerPlaceholders().isEmpty() && FileEditorManager.getInstance(myProject).isFileOpen(myFile)) {
         for (FileEditor fileEditor : FileEditorManager.getInstance(myProject).getEditors(myFile)) {
-          if (fileEditor instanceof PsiAwareTextEditorImpl) {
-            Editor editor = ((PsiAwareTextEditorImpl)fileEditor).getEditor();
+          if (fileEditor instanceof TextEditor) {
+            Editor editor = ((TextEditor)fileEditor).getEditor();
             StudyUtils.drawAllWindows(editor, myTaskFile);
           }
         }
@@ -78,12 +77,6 @@ public class CCHideFromStudent extends CCTaskFileActionBase {
       ProjectView.getInstance(myProject).refresh();
     }
 
-    @Nullable
-    @Override
-    public DocumentReference[] getAffectedDocuments() {
-      return new DocumentReference[0];
-    }
-
     @Override
     public boolean isGlobal() {
       return true;
@@ -93,8 +86,8 @@ public class CCHideFromStudent extends CCTaskFileActionBase {
   public static void hideFromStudent(VirtualFile file, Project project, Map<String, TaskFile> taskFiles, TaskFile taskFile) {
     if (!taskFile.getAnswerPlaceholders().isEmpty() && FileEditorManager.getInstance(project).isFileOpen(file)) {
       for (FileEditor fileEditor : FileEditorManager.getInstance(project).getEditors(file)) {
-        if (fileEditor instanceof PsiAwareTextEditorImpl) {
-          Editor editor = ((PsiAwareTextEditorImpl)fileEditor).getEditor();
+        if (fileEditor instanceof TextEditor) {
+          Editor editor = ((TextEditor)fileEditor).getEditor();
           editor.getMarkupModel().removeAllHighlighters();
         }
       }
index 52b497f61fd7ea50e54f76369c3658fc6be88bf6..f312436106c2750175986be1260453c256a4f71c 100644 (file)
@@ -55,6 +55,7 @@ import java.util.Calendar;
 
 public class CCShowPreview extends DumbAwareAction {
   public static final String SHOW_PREVIEW = "Show Preview";
+  public static final String NO_PREVIEW_MESSAGE = "Preview is available for task files with answer placeholders only";
 
   public CCShowPreview() {
     super(SHOW_PREVIEW, SHOW_PREVIEW, null);
@@ -161,6 +162,8 @@ public class CCShowPreview extends DumbAwareAction {
     createdEditor.setCaretEnabled(false);
     showPreviewFrame.setComponent(labeledEditor);
     showPreviewFrame.setSize(new Dimension(500, 500));
-    showPreviewFrame.show();
+    if (!ApplicationManager.getApplication().isUnitTestMode()) {
+      showPreviewFrame.show();
+    }
   }
 }
\ No newline at end of file
diff --git a/python/educational-core/course-creator/testData/actions/addPlaceholder/deletePlaceholder_after.txt b/python/educational-core/course-creator/testData/actions/addPlaceholder/deletePlaceholder_after.txt
new file mode 100644 (file)
index 0000000..56b857f
--- /dev/null
@@ -0,0 +1 @@
+we're going to delete this placeholder
\ No newline at end of file
diff --git a/python/educational-core/course-creator/testData/actions/addPlaceholder/deletePlaceholder_before.txt b/python/educational-core/course-creator/testData/actions/addPlaceholder/deletePlaceholder_before.txt
new file mode 100644 (file)
index 0000000..4c54702
--- /dev/null
@@ -0,0 +1 @@
+we're going to delete <placeholder>thi<caret>s</placeholder> placeholder
\ No newline at end of file
diff --git a/python/educational-core/course-creator/testData/actions/addPlaceholder/onePlaceholder_after.txt b/python/educational-core/course-creator/testData/actions/addPlaceholder/onePlaceholder_after.txt
new file mode 100644 (file)
index 0000000..ae22d67
--- /dev/null
@@ -0,0 +1 @@
+<placeholder taskText="type here" hint="Test hint">here</placeholder> will be added one placeholder
\ No newline at end of file
diff --git a/python/educational-core/course-creator/testData/actions/addPlaceholder/onePlaceholder_before.txt b/python/educational-core/course-creator/testData/actions/addPlaceholder/onePlaceholder_before.txt
new file mode 100644 (file)
index 0000000..ba43c83
--- /dev/null
@@ -0,0 +1 @@
+<selection>here</selection> will be added one placeholder
\ No newline at end of file
diff --git a/python/educational-core/course-creator/testData/actions/addPlaceholder/placeholderIntersection.txt b/python/educational-core/course-creator/testData/actions/addPlaceholder/placeholderIntersection.txt
new file mode 100644 (file)
index 0000000..c5c6689
--- /dev/null
@@ -0,0 +1 @@
+type <placeholder>h<selection>ere</selection></placeholder>
\ No newline at end of file
diff --git a/python/educational-core/course-creator/testData/actions/addPlaceholder/withoutSelection_after.txt b/python/educational-core/course-creator/testData/actions/addPlaceholder/withoutSelection_after.txt
new file mode 100644 (file)
index 0000000..fd68bcc
--- /dev/null
@@ -0,0 +1,3 @@
+def f():
+  pass
+  <placeholder taskText="type here" hint="Test hint">type here</placeholder>
\ No newline at end of file
diff --git a/python/educational-core/course-creator/testData/actions/addPlaceholder/withoutSelection_before.txt b/python/educational-core/course-creator/testData/actions/addPlaceholder/withoutSelection_before.txt
new file mode 100644 (file)
index 0000000..186cd19
--- /dev/null
@@ -0,0 +1,3 @@
+def f():
+  pass
+  <caret>
\ No newline at end of file
diff --git a/python/educational-core/course-creator/testData/actions/preview/noplaceholders.txt b/python/educational-core/course-creator/testData/actions/preview/noplaceholders.txt
new file mode 100644 (file)
index 0000000..ad22405
--- /dev/null
@@ -0,0 +1 @@
+no placeholders
\ No newline at end of file
diff --git a/python/educational-core/course-creator/testData/actions/preview/several_after.txt b/python/educational-core/course-creator/testData/actions/preview/several_after.txt
new file mode 100644 (file)
index 0000000..9422757
--- /dev/null
@@ -0,0 +1 @@
+print("<placeholder>veryverylongtextveryverylongtextveryverylongtextveryverylongtext</placeholder> + <placeholder>test</placeholder> = 2")
\ No newline at end of file
diff --git a/python/educational-core/course-creator/testData/actions/preview/several_before.txt b/python/educational-core/course-creator/testData/actions/preview/several_before.txt
new file mode 100644 (file)
index 0000000..652621a
--- /dev/null
@@ -0,0 +1 @@
+print("<placeholder taskText="veryverylongtextveryverylongtextveryverylongtextveryverylongtext">1</placeholder> + <placeholder taskText="test">1</placeholder> = 2")
\ No newline at end of file
diff --git a/python/educational-core/course-creator/testData/actions/preview/test_after.txt b/python/educational-core/course-creator/testData/actions/preview/test_after.txt
new file mode 100644 (file)
index 0000000..9a1e373
--- /dev/null
@@ -0,0 +1 @@
+<placeholder>type here</placeholder>
\ No newline at end of file
diff --git a/python/educational-core/course-creator/testData/actions/preview/test_before.txt b/python/educational-core/course-creator/testData/actions/preview/test_before.txt
new file mode 100644 (file)
index 0000000..3012cb8
--- /dev/null
@@ -0,0 +1 @@
+<placeholder taskText="type here">two</placeholder>
\ No newline at end of file
diff --git a/python/educational-core/course-creator/testData/actions/taskFileActions/nonTaskFile.txt b/python/educational-core/course-creator/testData/actions/taskFileActions/nonTaskFile.txt
new file mode 100644 (file)
index 0000000..57f41b7
--- /dev/null
@@ -0,0 +1 @@
+non task file
\ No newline at end of file
diff --git a/python/educational-core/course-creator/testData/actions/taskFileActions/taskFile.txt b/python/educational-core/course-creator/testData/actions/taskFileActions/taskFile.txt
new file mode 100644 (file)
index 0000000..03f277c
--- /dev/null
@@ -0,0 +1 @@
+test task file with <placeholder>placeholder</placeholder>
\ No newline at end of file
diff --git a/python/educational-core/course-creator/testSrc/com/jetbrains/edu/coursecreator/CCTestCase.java b/python/educational-core/course-creator/testSrc/com/jetbrains/edu/coursecreator/CCTestCase.java
new file mode 100644 (file)
index 0000000..8a16347
--- /dev/null
@@ -0,0 +1,194 @@
+package com.jetbrains.edu.coursecreator;
+
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.Result;
+import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.EditorFactory;
+import com.intellij.openapi.editor.markup.MarkupModel;
+import com.intellij.openapi.editor.markup.RangeHighlighter;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.testFramework.EditorTestUtil;
+import com.intellij.testFramework.fixtures.CodeInsightFixtureTestCase;
+import com.jetbrains.edu.learning.StudyTaskManager;
+import com.jetbrains.edu.learning.StudyUtils;
+import com.jetbrains.edu.learning.courseFormat.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.junit.ComparisonFailure;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public abstract class CCTestCase extends CodeInsightFixtureTestCase {
+  private static final Logger LOG = Logger.getInstance(CCTestCase.class);
+
+  @Nullable
+  public static RangeHighlighter getHighlighter(MarkupModel model, AnswerPlaceholder placeholder) {
+    for (RangeHighlighter highlighter : model.getAllHighlighters()) {
+      int endOffset = placeholder.getOffset() + placeholder.getRealLength();
+      if (highlighter.getStartOffset() == placeholder.getOffset() && highlighter.getEndOffset() == endOffset) {
+        return highlighter;
+      }
+    }
+    return null;
+  }
+
+  protected static void checkHighlighters(TaskFile taskFile, MarkupModel markupModel) {
+    for (AnswerPlaceholder answerPlaceholder : taskFile.getAnswerPlaceholders()) {
+      if (getHighlighter(markupModel, answerPlaceholder) == null) {
+        throw new AssertionError("No highlighter for placeholder: " + CCTestsUtil.getPlaceholderPresentation(answerPlaceholder));
+      }
+    }
+  }
+
+  public void checkByFile(TaskFile taskFile, String fileName, boolean useLength) {
+    Pair<Document, List<AnswerPlaceholder>> placeholders = getPlaceholders(fileName, useLength, true);
+    String message = "Placeholders don't match";
+    if (taskFile.getAnswerPlaceholders().size() != placeholders.second.size()) {
+      throw new ComparisonFailure(message,
+                                  CCTestsUtil.getPlaceholdersPresentation(taskFile.getAnswerPlaceholders()),
+                                  CCTestsUtil.getPlaceholdersPresentation(placeholders.second));
+    }
+    for (AnswerPlaceholder answerPlaceholder : placeholders.getSecond()) {
+      AnswerPlaceholder placeholder = taskFile.getAnswerPlaceholder(answerPlaceholder.getOffset());
+      if (!CCTestsUtil.comparePlaceholders(placeholder, answerPlaceholder)) {
+        throw new ComparisonFailure(message,
+                                    CCTestsUtil.getPlaceholdersPresentation(taskFile.getAnswerPlaceholders()),
+                                    CCTestsUtil.getPlaceholdersPresentation(placeholders.second));
+      }
+    }
+  }
+
+  @Override
+  protected String getBasePath() {
+    return "/community/python/educational-core/course-creator/testData";
+  }
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+    Course course = new Course();
+    course.setName("test course");
+    course.setCourseDirectory(getProject().getBasePath());
+    StudyTaskManager.getInstance(getProject()).setCourse(course);
+
+    Lesson lesson = new Lesson();
+    lesson.setName("lesson1");
+    Task task = new Task();
+    task.setName("task1");
+    task.setIndex(1);
+    lesson.addTask(task);
+    lesson.setIndex(1);
+    course.getLessons().add(lesson);
+    course.setCourseMode(CCUtils.COURSE_MODE);
+    course.initCourse(false);
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      @Override
+      public void run() {
+        try {
+          VirtualFile lesson1 = myFixture.getProject().getBaseDir().createChildDirectory(this, "lesson1");
+          lesson1.createChildDirectory(this, "task1");
+        }
+        catch (IOException e) {
+          //ignore
+        }
+      }
+    });
+  }
+
+  protected VirtualFile copyFileToTask(String name) {
+    return myFixture.copyFileToProject(name, FileUtil.join(getProject().getBasePath(), "lesson1", "task1", name));
+  }
+
+  protected VirtualFile configureByTaskFile(String name) {
+    Task task = StudyTaskManager.getInstance(getProject()).getCourse().getLessons().get(0).getTaskList().get(0);
+    TaskFile taskFile = new TaskFile();
+    taskFile.setTask(task);
+    task.getTaskFiles().put(name, taskFile);
+    VirtualFile file = copyFileToTask(name);
+    myFixture.configureFromExistingVirtualFile(file);
+    Document document = FileDocumentManager.getInstance().getDocument(file);
+    for (AnswerPlaceholder placeholder : getPlaceholders(document, false)) {
+      taskFile.addAnswerPlaceholder(placeholder);
+    }
+    taskFile.sortAnswerPlaceholders();
+    StudyUtils.drawAllWindows(myFixture.getEditor(), taskFile);
+    CCUtils.createResourceFile(file, StudyTaskManager.getInstance(getProject()).getCourse(), file.getParent());
+    return file;
+  }
+
+  private static List<AnswerPlaceholder> getPlaceholders(Document document, boolean useLength) {
+    final List<AnswerPlaceholder> placeholders = new ArrayList<>();
+    new WriteCommandAction(null) {
+      @Override
+      protected void run(@NotNull Result result) {
+        final String openingTagRx = "<placeholder( taskText=\"(.+?)\")?( possibleAnswer=\"(.+?)\")?( hint=\"(.+?)\")?>";
+        final String closingTagRx = "</placeholder>";
+        CharSequence text = document.getCharsSequence();
+        final Matcher openingMatcher = Pattern.compile(openingTagRx).matcher(text);
+        final Matcher closingMatcher = Pattern.compile(closingTagRx).matcher(text);
+        int pos = 0;
+        while (openingMatcher.find(pos)) {
+          AnswerPlaceholder answerPlaceholder = new AnswerPlaceholder();
+          answerPlaceholder.setUseLength(useLength);
+          String taskText = openingMatcher.group(2);
+          if (taskText != null) {
+            answerPlaceholder.setTaskText(taskText);
+            answerPlaceholder.setLength(taskText.length());
+          }
+          String possibleAnswer = openingMatcher.group(4);
+          if (possibleAnswer != null) {
+            answerPlaceholder.setPossibleAnswer(possibleAnswer);
+          }
+          String hint = openingMatcher.group(6);
+          if (hint != null) {
+            answerPlaceholder.setHint(hint);
+          }
+          answerPlaceholder.setOffset(openingMatcher.start());
+          if (!closingMatcher.find(openingMatcher.end())) {
+            LOG.error("No matching closing tag found");
+          }
+          if (useLength) {
+            answerPlaceholder.setLength(closingMatcher.start() - openingMatcher.end());
+          } else {
+            if (possibleAnswer == null) {
+              answerPlaceholder.setPossibleAnswer(document.getText(TextRange.create(openingMatcher.end(), closingMatcher.start())));
+            }
+          }
+          document.deleteString(closingMatcher.start(), closingMatcher.end());
+          document.deleteString(openingMatcher.start(), openingMatcher.end());
+          placeholders.add(answerPlaceholder);
+          pos = answerPlaceholder.getOffset() + answerPlaceholder.getRealLength();
+        }
+      }
+    }.execute();
+    return placeholders;
+  }
+
+  public Pair<Document, List<AnswerPlaceholder>> getPlaceholders(String name) {
+    return getPlaceholders(name, true, false);
+  }
+
+  public Pair<Document, List<AnswerPlaceholder>> getPlaceholders(String name, boolean useLength, boolean removeMarkers) {
+    VirtualFile resultFile = LocalFileSystem.getInstance().findFileByPath(getTestDataPath() + "/" + name);
+    Document document = FileDocumentManager.getInstance().getDocument(resultFile);
+    Document tempDocument = EditorFactory.getInstance().createDocument(document.getCharsSequence());
+    if (removeMarkers) {
+      EditorTestUtil.extractCaretAndSelectionMarkers(tempDocument);
+    }
+    List<AnswerPlaceholder> placeholders = getPlaceholders(tempDocument, useLength);
+    return Pair.create(tempDocument, placeholders);
+  }
+}
+
+
diff --git a/python/educational-core/course-creator/testSrc/com/jetbrains/edu/coursecreator/CCTestsUtil.java b/python/educational-core/course-creator/testSrc/com/jetbrains/edu/coursecreator/CCTestsUtil.java
new file mode 100644 (file)
index 0000000..8f4fb8a
--- /dev/null
@@ -0,0 +1,43 @@
+package com.jetbrains.edu.coursecreator;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
+import com.intellij.openapi.util.text.StringUtil;
+import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
+
+import java.util.Collection;
+import java.util.List;
+
+public class CCTestsUtil {
+  public static final String BEFORE_POSTFIX = "_before.txt";
+  public static final String AFTER_POSTFIX = "_after.txt";
+
+  private CCTestsUtil() {
+  }
+
+  public static boolean comparePlaceholders(AnswerPlaceholder p1, AnswerPlaceholder p2) {
+    if (p1.getOffset() != p2.getOffset()) return false;
+    if (p1.getRealLength() != p2.getRealLength()) return false;
+    if (p1.getPossibleAnswer() != null ? !p1.getPossibleAnswer().equals(p2.getPossibleAnswer()) : p2.getPossibleAnswer() != null) return false;
+    if (p1.getTaskText() != null ? !p1.getTaskText().equals(p2.getTaskText()) : p2.getTaskText() != null) return false;
+    if (!p1.getHints().equals(p1.getHints())) return false;
+    return true;
+  }
+
+  public static String getPlaceholderPresentation(AnswerPlaceholder placeholder) {
+    return "offset=" + placeholder.getOffset() +
+           " length=" + placeholder.getLength() +
+           " possibleAnswer=" + placeholder.getPossibleAnswer() +
+           " taskText=" + placeholder.getTaskText();
+  }
+
+  public static String getPlaceholdersPresentation(List<AnswerPlaceholder> placeholders) {
+    Collection<String> transformed = Collections2.transform(placeholders, new Function<AnswerPlaceholder, String>() {
+      @Override
+      public String apply(AnswerPlaceholder placeholder) {
+        return getPlaceholderPresentation(placeholder);
+      }
+    });
+    return "[" + StringUtil.join(transformed, ",") + "]";
+  }
+}
diff --git a/python/educational-core/course-creator/testSrc/com/jetbrains/edu/coursecreator/actions/CCAnswerPlaceholderActionTest.java b/python/educational-core/course-creator/testSrc/com/jetbrains/edu/coursecreator/actions/CCAnswerPlaceholderActionTest.java
new file mode 100644 (file)
index 0000000..9ca2aa1
--- /dev/null
@@ -0,0 +1,73 @@
+package com.jetbrains.edu.coursecreator.actions;
+
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.command.undo.UndoManager;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.edu.coursecreator.CCTestCase;
+import com.jetbrains.edu.coursecreator.CCTestsUtil;
+import com.jetbrains.edu.learning.StudyUtils;
+import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
+import com.jetbrains.edu.learning.courseFormat.TaskFile;
+import com.jetbrains.edu.learning.ui.CCCreateAnswerPlaceholderDialog;
+
+import java.util.Collections;
+import java.util.List;
+
+public class CCAnswerPlaceholderActionTest extends CCTestCase {
+  static class CCTestAction extends CCAddAnswerPlaceholder {
+    @Override
+    protected CCCreateAnswerPlaceholderDialog createDialog(Project project, AnswerPlaceholder answerPlaceholder) {
+      return new CCCreateAnswerPlaceholderDialog(project, answerPlaceholder.getTaskText(), answerPlaceholder.getHints()) {
+        @Override
+        public boolean showAndGet() {
+          return true;
+        }
+
+        @Override
+        public String getTaskText() {
+          return "type here";
+        }
+
+        @Override
+        public List<String> getHints() {
+          return Collections.singletonList("Test hint");
+        }
+      };
+    }
+  }
+
+  public void testPlaceholderWithSelection() {
+    doTest("onePlaceholder");
+  }
+
+  public void testPlaceholderWithoutSelection() {
+    doTest("withoutSelection");
+  }
+
+  public void testPlaceholderIntersection() {
+    configureByTaskFile("placeholderIntersection.txt");
+    Presentation presentation = myFixture.testAction(new CCTestAction());
+    assertTrue(presentation.isVisible() && !presentation.isEnabled());
+  }
+
+  public void testPlaceholderDeleted() {
+    doTest("deletePlaceholder");
+  }
+
+  private void doTest(String name) {
+    VirtualFile virtualFile = configureByTaskFile(name + CCTestsUtil.BEFORE_POSTFIX);
+    myFixture.testAction(new CCTestAction());
+    TaskFile taskFile = StudyUtils.getTaskFile(getProject(), virtualFile);
+    checkByFile(taskFile, name + CCTestsUtil.AFTER_POSTFIX, false);
+    checkHighlighters(taskFile, myFixture.getEditor().getMarkupModel());
+    UndoManager.getInstance(getProject()).undo(FileEditorManager.getInstance(getProject()).getSelectedEditor(virtualFile));
+    checkByFile(taskFile, name + CCTestsUtil.BEFORE_POSTFIX, false);
+  }
+
+  @Override
+  protected String getBasePath() {
+    return super.getBasePath()  + "/actions/addPlaceholder";
+  }
+}
diff --git a/python/educational-core/course-creator/testSrc/com/jetbrains/edu/coursecreator/actions/CCShowPreviewTest.java b/python/educational-core/course-creator/testSrc/com/jetbrains/edu/coursecreator/actions/CCShowPreviewTest.java
new file mode 100644 (file)
index 0000000..79f8b57
--- /dev/null
@@ -0,0 +1,72 @@
+package com.jetbrains.edu.coursecreator.actions;
+
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.LangDataKeys;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.EditorFactory;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiManager;
+import com.intellij.testFramework.MapDataContext;
+import com.intellij.testFramework.TestActionEvent;
+import com.jetbrains.edu.coursecreator.CCTestCase;
+import com.jetbrains.edu.coursecreator.CCTestsUtil;
+import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
+
+import java.util.List;
+
+public class CCShowPreviewTest extends CCTestCase {
+
+  public void testPreviewUnavailable() {
+    VirtualFile file = configureByTaskFile("noplaceholders.txt");
+    CCShowPreview action = new CCShowPreview();
+    TestActionEvent e = getActionEvent(action, PsiManager.getInstance(getProject()).findFile(file));
+    action.beforeActionPerformedUpdate(e);
+    assertTrue(e.getPresentation().isEnabled() && e.getPresentation().isVisible());
+    try {
+      action.actionPerformed(e);
+      assertTrue("No message shown", false);
+    } catch (RuntimeException ex) {
+      assertEquals(CCShowPreview.NO_PREVIEW_MESSAGE, ex.getMessage());
+    }
+  }
+
+  public void testOnePlaceholder() {
+    doTest("test");
+  }
+
+  public void testSeveralPlaceholders() {
+    doTest("several");
+  }
+
+  private void doTest(String name) {
+    VirtualFile file = configureByTaskFile(name + CCTestsUtil.BEFORE_POSTFIX);
+    CCShowPreview action = new CCShowPreview();
+    TestActionEvent e = getActionEvent(action,PsiManager.getInstance(getProject()).findFile(file));
+    action.beforeActionPerformedUpdate(e);
+    assertTrue(e.getPresentation().isEnabled() && e.getPresentation().isVisible());
+    action.actionPerformed(e);
+    Editor editor = EditorFactory.getInstance().getAllEditors()[1];
+    Pair<Document, List<AnswerPlaceholder>> pair = getPlaceholders(name + CCTestsUtil.AFTER_POSTFIX);
+    assertEquals("Files don't match", editor.getDocument().getText(), pair.getFirst().getText());
+    for (AnswerPlaceholder placeholder : pair.getSecond()) {
+      assertNotNull("No highlighter for placeholder:" + CCTestsUtil.getPlaceholderPresentation(placeholder), getHighlighter(editor.getMarkupModel(), placeholder));
+    }
+  }
+
+  @Override
+  protected String getBasePath() {
+    return super.getBasePath() + "/actions/preview";
+  }
+
+  TestActionEvent getActionEvent(AnAction action, PsiFile psiFile) {
+    MapDataContext context = new MapDataContext();
+    context.put(CommonDataKeys.PSI_FILE, psiFile);
+    context.put(CommonDataKeys.PROJECT, getProject());
+    context.put(LangDataKeys.MODULE, myFixture.getModule());
+    return new TestActionEvent(context, action);
+  }
+}
diff --git a/python/educational-core/course-creator/testSrc/com/jetbrains/edu/coursecreator/actions/CCTaskFileActionTest.java b/python/educational-core/course-creator/testSrc/com/jetbrains/edu/coursecreator/actions/CCTaskFileActionTest.java
new file mode 100644 (file)
index 0000000..c8c12a9
--- /dev/null
@@ -0,0 +1,57 @@
+package com.jetbrains.edu.coursecreator.actions;
+
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.command.undo.UndoManager;
+import com.intellij.openapi.fileEditor.FileEditor;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.testFramework.MapDataContext;
+import com.intellij.testFramework.TestActionEvent;
+import com.jetbrains.edu.coursecreator.CCTestCase;
+import com.jetbrains.edu.learning.StudyUtils;
+import com.jetbrains.edu.learning.courseFormat.TaskFile;
+import org.jetbrains.annotations.NotNull;
+
+public class CCTaskFileActionTest extends CCTestCase {
+  public void testHideTaskFile() {
+    VirtualFile virtualFile = configureByTaskFile("taskFile.txt");
+    launchAction(virtualFile, new CCHideFromStudent());
+    assertNull(StudyUtils.getTaskFile(getProject(), virtualFile));
+    UndoManager.getInstance(getProject()).undo(FileEditorManager.getInstance(getProject()).getSelectedEditor(virtualFile));
+    TaskFile taskFile = StudyUtils.getTaskFile(getProject(), virtualFile);
+    assertNotNull(taskFile);
+    checkHighlighters(taskFile, myFixture.getEditor().getMarkupModel());
+  }
+
+  public void testAddTaskFile() {
+    VirtualFile virtualFile = copyFileToTask("nonTaskFile.txt");
+    myFixture.configureFromExistingVirtualFile(virtualFile);
+    launchAction(virtualFile, new CCAddAsTaskFile());
+    TaskFile taskFile = StudyUtils.getTaskFile(getProject(), virtualFile);
+    assertNotNull(taskFile);
+    FileEditor fileEditor = FileEditorManager.getInstance(getProject()).getSelectedEditor(virtualFile);
+    UndoManager.getInstance(getProject()).undo(fileEditor);
+    assertNull(StudyUtils.getTaskFile(getProject(), virtualFile));
+  }
+
+  private void launchAction(VirtualFile virtualFile, AnAction action) {
+    TestActionEvent e = getActionEvent(virtualFile, action);
+    action.beforeActionPerformedUpdate(e);
+    assertTrue(e.getPresentation().isEnabled() && e.getPresentation().isVisible());
+    action.actionPerformed(e);
+  }
+
+  @NotNull
+  private TestActionEvent getActionEvent(VirtualFile virtualFile, AnAction action) {
+    MapDataContext context = new MapDataContext();
+    context.put(CommonDataKeys.VIRTUAL_FILE, virtualFile);
+    context.put(CommonDataKeys.PROJECT, getProject());
+    return new TestActionEvent(context, action);
+  }
+
+  @Override
+  protected String getBasePath() {
+    return super.getBasePath() + "/actions/taskFileActions";
+  }
+}
index 854ff553784c0cdad11da0b15767c6083e4cce83..1f3571065a341200b102cde5c1f009a64f757acb 100644 (file)
@@ -4,7 +4,6 @@ import com.intellij.openapi.project.Project;
 import com.intellij.openapi.ui.DialogWrapper;
 import com.intellij.openapi.ui.ValidationInfo;
 import com.intellij.openapi.util.text.StringUtil;
-import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -14,8 +13,7 @@ import java.util.List;
 
 public class CCCreateAnswerPlaceholderDialog extends DialogWrapper {
 
-  private static final String ourTitle = "Add Answer Placeholder";
-  private final AnswerPlaceholder myAnswerPlaceholder;
+  private static final String TITLE = "Add Answer Placeholder";
   private final CCCreateAnswerPlaceholderPanel myPanel;
   private final Project myProject;
 
@@ -24,32 +22,24 @@ public class CCCreateAnswerPlaceholderDialog extends DialogWrapper {
   }
 
   public CCCreateAnswerPlaceholderDialog(@NotNull final Project project,
-                                         @NotNull final AnswerPlaceholder answerPlaceholder) {
+                                         String placeholderText,
+                                         List<String> hints) {
     super(project, true);
     
-    myAnswerPlaceholder = answerPlaceholder;
     myProject = project;
-    myPanel = new CCCreateAnswerPlaceholderPanel(answerPlaceholder);
-    myPanel.showAnswerPlaceholderText(StringUtil.notNullize(answerPlaceholder.getTaskText()));
-    
-    setTitle(ourTitle);
+    myPanel = new CCCreateAnswerPlaceholderPanel(placeholderText, hints);
+    setTitle(TITLE);
     init();
     initValidation();
   }
 
-  @Override
-  protected void doOKAction() {
-    String answerPlaceholderText = myPanel.getAnswerPlaceholderText();
-    myAnswerPlaceholder.setTaskText(StringUtil.notNullize(answerPlaceholderText));
-    myAnswerPlaceholder.setLength(StringUtil.notNullize(answerPlaceholderText).length());
+  public String getTaskText() {
+    return StringUtil.notNullize(myPanel.getAnswerPlaceholderText());
+  }
+
+  public List<String> getHints() {
     final List<String> hints = myPanel.getHints();
-    if (hints.size() == 1 && hints.get(0).isEmpty()) {
-      myAnswerPlaceholder.setHints(Collections.emptyList());
-    }
-    else {
-      myAnswerPlaceholder.setHints(hints);
-    }
-    super.doOKAction();
+    return hints.size() == 1 && hints.get(0).isEmpty() ? Collections.emptyList() : hints;
   }
 
   @Nullable
index 9013b7a4d7090814a60dbff4724279f82b735ea4..f5ccc64ddd57bf9426486bfe5cc1b4dbe922c234 100644 (file)
@@ -10,7 +10,6 @@ import com.intellij.ui.JBColor;
 import com.intellij.ui.components.JBLabel;
 import com.intellij.uiDesigner.core.GridLayoutManager;
 import com.intellij.util.ui.UIUtil;
-import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
 import org.jetbrains.annotations.NotNull;
 
 import javax.swing.*;
@@ -21,7 +20,11 @@ import java.util.ArrayList;
 import java.util.List;
 
 public class CCCreateAnswerPlaceholderPanel {
-  private static final String ourFirstHintText = "Type here to add hint";
+  private static final String NEXT_HINT = "Next Hint";
+  private static final String PREVIOUS_HINT = "Previous Hint";
+  private static final String ADD_HINT = "Add Hint";
+  private static final String REMOVE_HINT = "Remove Hint";
+  private static final String HINT_PLACEHOLDER = "Type here to add hint";
 
   private JPanel myPanel;
   private JTextArea myHintTextArea;
@@ -29,16 +32,15 @@ public class CCCreateAnswerPlaceholderPanel {
   private JBLabel myHintLabel;
   private JPanel actionsPanel;
   private JTextArea myPlaceholderTextArea;
-  private List<String> myHints = new ArrayList<String>() {
-  };
+  private List<String> myHints = new ArrayList<>();
   private int myShownHintNumber = 0;
 
-  public CCCreateAnswerPlaceholderPanel(@NotNull final AnswerPlaceholder answerPlaceholder) {
-    if (answerPlaceholder.getHints().isEmpty()) {
-      myHints.add(ourFirstHintText);
+  public CCCreateAnswerPlaceholderPanel(String placeholderText, List<String> hints) {
+    if (hints.isEmpty()) {
+      myHints.add(HINT_PLACEHOLDER);
     }
     else {
-      myHints.addAll(answerPlaceholder.getHints());
+      myHints.addAll(hints);
     }
 
     myPlaceholderTextArea.setBorder(BorderFactory.createLineBorder(JBColor.border()));
@@ -50,6 +52,7 @@ public class CCCreateAnswerPlaceholderPanel {
 
     actionsPanel.add(createHintToolbarComponent(), BorderLayout.WEST);
     showHint(myHints.get(myShownHintNumber));
+    myPlaceholderTextArea.setText(placeholderText);
   }
 
   @NotNull
@@ -57,7 +60,7 @@ public class CCCreateAnswerPlaceholderPanel {
     return new FocusAdapter() {
       @Override
       public void focusGained(FocusEvent e) {
-        if (myHintTextArea.getText().equals(ourFirstHintText)) {
+        if (myHintTextArea.getText().equals(HINT_PLACEHOLDER)) {
           myHintTextArea.setForeground(UIUtil.getActiveTextColor());
           myHintTextArea.setText("");
         }
@@ -67,7 +70,7 @@ public class CCCreateAnswerPlaceholderPanel {
       public void focusLost(FocusEvent e) {
         if (myShownHintNumber == 0 && myHintTextArea.getText().isEmpty()) {
           myHintTextArea.setForeground(UIUtil.getInactiveTextColor());
-          myHintTextArea.setText(ourFirstHintText);
+          myHintTextArea.setText(HINT_PLACEHOLDER);
         }
       }
     };
@@ -89,12 +92,8 @@ public class CCCreateAnswerPlaceholderPanel {
     }
   }
 
-  public void showAnswerPlaceholderText(String answerPlaceholderText) {
-    myPlaceholderTextArea.setText(answerPlaceholderText);
-  }
-
   public void showHint(String hintText) {
-    if (myHints.get(myShownHintNumber).equals(ourFirstHintText)) {
+    if (myHints.get(myShownHintNumber).equals(HINT_PLACEHOLDER)) {
       myHintTextArea.setForeground(UIUtil.getInactiveTextColor());
     }
     else {
@@ -111,7 +110,7 @@ public class CCCreateAnswerPlaceholderPanel {
 
   public List<String> getHints() {
     final String hintText = myHintTextArea.getText();
-    if (myShownHintNumber == 0 && hintText.equals(ourFirstHintText)) {
+    if (myShownHintNumber == 0 && hintText.equals(HINT_PLACEHOLDER)) {
       myHints.set(myShownHintNumber, "");
     }
     else {
@@ -132,7 +131,7 @@ public class CCCreateAnswerPlaceholderPanel {
   private class ShowNext extends AnAction {
 
     public ShowNext() {
-      super("Next Hint", "Next Hint", AllIcons.Actions.Forward);
+      super(NEXT_HINT, NEXT_HINT, AllIcons.Actions.Forward);
     }
 
     @Override
@@ -150,7 +149,7 @@ public class CCCreateAnswerPlaceholderPanel {
   private class ShowPrevious extends AnAction {
 
     public ShowPrevious() {
-      super("Previous Hint", "Previous Hint", AllIcons.Actions.Back);
+      super(PREVIOUS_HINT, PREVIOUS_HINT, AllIcons.Actions.Back);
     }
 
     @Override
@@ -168,7 +167,7 @@ public class CCCreateAnswerPlaceholderPanel {
   private class AddHint extends AnAction {
 
     public AddHint() {
-      super("Add Hint", "Add Hint", AllIcons.General.Add);
+      super(ADD_HINT, ADD_HINT, AllIcons.General.Add);
     }
 
     @Override
@@ -182,7 +181,7 @@ public class CCCreateAnswerPlaceholderPanel {
   private class RemoveHint extends AnAction {
 
     public RemoveHint() {
-      super("Remove Hint", "Remove Hint", AllIcons.General.Remove);
+      super(REMOVE_HINT, REMOVE_HINT, AllIcons.General.Remove);
     }
 
     @Override
index 9ccc793a5b461fea34488a5417515a4ee795f435..530155108d1ee3e8299782ccf3a40dddd98b4294 100644 (file)
@@ -95,7 +95,7 @@ class StudyHint(private val myPlaceholder: AnswerPlaceholder?,
   private inner class EditHint : AnAction("Edit Hint", "Edit Hint", AllIcons.Modules.Edit) {
     
     override fun actionPerformed(e: AnActionEvent?) {
-      val dialog = CCCreateAnswerPlaceholderDialog(e!!.project!!, myPlaceholder!!)
+      val dialog = CCCreateAnswerPlaceholderDialog(e!!.project!!, myPlaceholder!!.taskText, myPlaceholder.hints)
       dialog.show()
     }