add subtasks to placeholder inner representation
authorLiana Bakradze <liana.bakradze@jetbrains.com>
Wed, 21 Sep 2016 11:33:20 +0000 (14:33 +0300)
committerliana.bakradze <liana.bakradze@jetbrains.com>
Thu, 17 Nov 2016 14:05:02 +0000 (17:05 +0300)
23 files changed:
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAnswerPlaceholder.java
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCShowPreview.java
python/educational-core/course-creator/testSrc/com/jetbrains/edu/coursecreator/CCTestCase.java
python/educational-core/student/src/com/jetbrains/edu/learning/StudyTaskManager.java
python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java
python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyFillPlaceholdersAction.java
python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyNextWindowAction.java
python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyPrevWindowAction.java
python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshTaskFileAction.java
python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java
python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudySmartChecker.java
python/educational-core/student/src/com/jetbrains/edu/learning/core/EduAnswerPlaceholderPainter.java
python/educational-core/student/src/com/jetbrains/edu/learning/core/EduUtils.java
python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/AnswerPlaceholder.java
python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/AnswerPlaceholderSubtaskInfo.java [new file with mode: 0644]
python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/Task.java
python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/TaskFile.java
python/educational-core/student/src/com/jetbrains/edu/learning/courseGeneration/StudyProjectGenerator.java
python/educational-core/student/src/com/jetbrains/edu/learning/navigation/StudyNavigator.java
python/educational-core/student/src/com/jetbrains/edu/learning/projectView/StudyDirectoryNode.java
python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCCommandLineState.java
python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyCheckAction.java

index b2f26711ac5ad7dce3f629f8833387877b418fe3..8bc54aca86c38f12a3947de492994a9952d33153 100644 (file)
@@ -19,6 +19,7 @@ import com.jetbrains.edu.learning.core.EduAnswerPlaceholderPainter;
 import com.jetbrains.edu.learning.core.EduNames;
 import com.jetbrains.edu.learning.core.EduUtils;
 import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
+import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholderSubtaskInfo;
 import com.jetbrains.edu.learning.courseFormat.TaskFile;
 import com.jetbrains.edu.learning.ui.CCCreateAnswerPlaceholderDialog;
 import org.jetbrains.annotations.NotNull;
@@ -57,19 +58,24 @@ 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();
     final AnswerPlaceholder answerPlaceholder = new AnswerPlaceholder();
-
+    answerPlaceholder.getSubtaskInfos().put(stepIndex, new AnswerPlaceholderSubtaskInfo());
+    TaskFile taskFile = state.getTaskFile();
+    int index = taskFile.getAnswerPlaceholders().size();
+    answerPlaceholder.setIndex(index);
+    answerPlaceholder.setTaskFile(taskFile);
+    taskFile.sortAnswerPlaceholders();
     answerPlaceholder.setOffset(offset);
     answerPlaceholder.setUseLength(false);
 
     String defaultPlaceholderText = "type here";
-    answerPlaceholder.setPossibleAnswer(model.hasSelection() ? model.getSelectedText() : defaultPlaceholderText);
-
     CCCreateAnswerPlaceholderDialog dlg = createDialog(project, answerPlaceholder);
     if (!dlg.showAndGet()) {
       return;
     }
     String answerPlaceholderText = dlg.getTaskText();
+    answerPlaceholder.setPossibleAnswer(model.hasSelection() ? model.getSelectedText() : defaultPlaceholderText);
     answerPlaceholder.setTaskText(StringUtil.notNullize(answerPlaceholderText));
     answerPlaceholder.setLength(StringUtil.notNullize(answerPlaceholderText).length());
     answerPlaceholder.setHints(dlg.getHints());
@@ -78,11 +84,7 @@ public class CCAddAnswerPlaceholder extends CCAnswerPlaceholderAction {
       DocumentUtil.writeInRunUndoTransparentAction(() -> document.insertString(offset, defaultPlaceholderText));
     }
 
-    TaskFile taskFile = state.getTaskFile();
-    int index = taskFile.getAnswerPlaceholders().size();
-    answerPlaceholder.setIndex(index);
-    answerPlaceholder.setTaskFile(taskFile);
-    taskFile.sortAnswerPlaceholders();
+
     answerPlaceholder.setPossibleAnswer(model.hasSelection() ? model.getSelectedText() : defaultPlaceholderText);
     AddAction action = new AddAction(answerPlaceholder, taskFile, editor);
     EduUtils.runUndoableAction(project, "Add Answer Placeholder", action);
index 69c628f360ce99693a31fbdf3695bba07ffc87be..91e13d9314d076f1d68477ac75400f8c242f76d7 100644 (file)
@@ -143,7 +143,7 @@ public class CCFromCourseArchive extends DumbAwareAction {
     EduDocumentListener listener = new EduDocumentListener(taskFile, false);
     document.addDocumentListener(listener);
     taskFile.sortAnswerPlaceholders();
-    for (int i = taskFile.getAnswerPlaceholders().size() - 1; i >= 0; i--) {
+    for (int i = taskFile.getActivePlaceholders().size() - 1; i >= 0; i--) {
       final AnswerPlaceholder answerPlaceholder = taskFile.getAnswerPlaceholders().get(i);
       replaceAnswerPlaceholder(project, document, answerPlaceholder);
     }
index f312436106c2750175986be1260453c256a4f71c..ef6b7a6c960c81b12b04e613eb3a28cbeb056dd5 100644 (file)
@@ -108,7 +108,7 @@ public class CCShowPreview extends DumbAwareAction {
     }
 
 
-    if (taskFile.getAnswerPlaceholders().isEmpty()) {
+    if (taskFile.getActivePlaceholders().isEmpty()) {
       Messages.showInfoMessage("Preview is available for task files with answer placeholders only", "No Preview for This File");
       return;
     }
@@ -146,7 +146,7 @@ public class CCShowPreview extends DumbAwareAction {
         factory.releaseEditor(createdEditor);
       }
     });
-    for (AnswerPlaceholder answerPlaceholder : taskFile.getAnswerPlaceholders()) {
+    for (AnswerPlaceholder answerPlaceholder : taskFile.getActivePlaceholders()) {
       answerPlaceholder.setUseLength(true);
       EduAnswerPlaceholderPainter.drawAnswerPlaceholder(createdEditor, answerPlaceholder, JBColor.BLUE);
     }
index 8a16347581ff13483f7cc3d0ad1c77b8f77849d6..0ee7e1d272427e84e5cab6bfd74773d47e4f0a3e 100644 (file)
@@ -25,6 +25,7 @@ import org.junit.ComparisonFailure;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -44,7 +45,7 @@ public abstract class CCTestCase extends CodeInsightFixtureTestCase {
   }
 
   protected static void checkHighlighters(TaskFile taskFile, MarkupModel markupModel) {
-    for (AnswerPlaceholder answerPlaceholder : taskFile.getAnswerPlaceholders()) {
+    for (AnswerPlaceholder answerPlaceholder : taskFile.getActivePlaceholders()) {
       if (getHighlighter(markupModel, answerPlaceholder) == null) {
         throw new AssertionError("No highlighter for placeholder: " + CCTestsUtil.getPlaceholderPresentation(answerPlaceholder));
       }
@@ -54,16 +55,16 @@ public abstract class CCTestCase extends CodeInsightFixtureTestCase {
   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()) {
+    if (taskFile.getActivePlaceholders().size() != placeholders.second.size()) {
       throw new ComparisonFailure(message,
-                                  CCTestsUtil.getPlaceholdersPresentation(taskFile.getAnswerPlaceholders()),
+                                  CCTestsUtil.getPlaceholdersPresentation(taskFile.getActivePlaceholders()),
                                   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(taskFile.getActivePlaceholders()),
                                     CCTestsUtil.getPlaceholdersPresentation(placeholders.second));
       }
     }
@@ -140,6 +141,8 @@ public abstract class CCTestCase extends CodeInsightFixtureTestCase {
         int pos = 0;
         while (openingMatcher.find(pos)) {
           AnswerPlaceholder answerPlaceholder = new AnswerPlaceholder();
+          AnswerPlaceholderSubtaskInfo subtaskInfo = new AnswerPlaceholderSubtaskInfo();
+          answerPlaceholder.getSubtaskInfos().put(0, subtaskInfo);
           answerPlaceholder.setUseLength(useLength);
           String taskText = openingMatcher.group(2);
           if (taskText != null) {
@@ -152,7 +155,7 @@ public abstract class CCTestCase extends CodeInsightFixtureTestCase {
           }
           String hint = openingMatcher.group(6);
           if (hint != null) {
-            answerPlaceholder.setHint(hint);
+            answerPlaceholder.setHints(Collections.singletonList(hint));
           }
           answerPlaceholder.setOffset(openingMatcher.start());
           if (!closingMatcher.find(openingMatcher.end())) {
index e2fd2c33246bde0664bc5578bf2f1f58ad0b97ce..b6d9a71b52415de6ad32fbeda0b6ea71366273d8 100644 (file)
@@ -108,7 +108,7 @@ public class StudyTaskManager implements PersistentStateComponent<Element>, Dumb
   }
 
   public boolean hasFailedAnswerPlaceholders(@NotNull final TaskFile taskFile) {
-    return taskFile.getAnswerPlaceholders().size() > 0 && taskFile.hasFailedPlaceholders();
+    return taskFile.getActivePlaceholders().size() > 0 && taskFile.hasFailedPlaceholders();
   }
 
   @Nullable
index 580f8465d05c018ee0ae542ee89619bf4de44aa4..366bfe76d1ab0b32f20029e4597a56a36db122e9 100644 (file)
@@ -352,7 +352,7 @@ public class StudyUtils {
     final Project project = editor.getProject();
     if (project == null) return;
     final StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
-    for (AnswerPlaceholder answerPlaceholder : taskFile.getAnswerPlaceholders()) {
+    for (AnswerPlaceholder answerPlaceholder : taskFile.getActivePlaceholders()) {
       final JBColor color = taskManager.getColor(answerPlaceholder);
       EduAnswerPlaceholderPainter.drawAnswerPlaceholder(editor, answerPlaceholder, color);
     }
@@ -726,7 +726,7 @@ public class StudyUtils {
     if (studyEditor == null) return;
     final Editor editor = studyEditor.getEditor();
     IdeFocusManager.getInstance(project).requestFocus(editor.getContentComponent(), true);
-    final List<AnswerPlaceholder> placeholders = studyEditor.getTaskFile().getAnswerPlaceholders();
+    final List<AnswerPlaceholder> placeholders = studyEditor.getTaskFile().getActivePlaceholders();
     if (placeholders.isEmpty()) return;
     final AnswerPlaceholder placeholder = placeholders.get(0);
     int startOffset = placeholder.getOffset();
index 831167d66ff4f45dd91823f473b86302b8cc4349..8d104531c0afcaffb130c67318b4b3d7de47314c 100644 (file)
@@ -30,7 +30,7 @@ public class StudyFillPlaceholdersAction extends AnAction {
       final Document document = studyState.getEditor().getDocument();
       final TaskFile realTaskFile = taskFile;
       CommandProcessor.getInstance().runUndoTransparentAction(() -> ApplicationManager.getApplication().runWriteAction(() -> {
-        for (AnswerPlaceholder placeholder : realTaskFile.getAnswerPlaceholders()) {
+        for (AnswerPlaceholder placeholder : realTaskFile.getActivePlaceholders()) {
           String answer = placeholder.getPossibleAnswer();
           if (answer == null) {
             continue;
@@ -63,7 +63,7 @@ public class StudyFillPlaceholdersAction extends AnAction {
         return;
       }
       TaskFile taskFile = studyState.getTaskFile();
-      if (taskFile.getAnswerPlaceholders().isEmpty()) {
+      if (taskFile.getActivePlaceholders().isEmpty()) {
         presentation.setEnabledAndVisible(false);
       }
     }
index 040cae0b206d6dc774f75a7e47f05dbad240b87d..b6f53e9be1565c430a4c279dac48324865ba5185 100644 (file)
@@ -24,7 +24,7 @@ public class StudyNextWindowAction extends StudyWindowNavigationAction {
   @Override
   protected AnswerPlaceholder getTargetPlaceholder(@NotNull final TaskFile taskFile, int offset) {
     final AnswerPlaceholder selectedAnswerPlaceholder = taskFile.getAnswerPlaceholder(offset);
-    final List<AnswerPlaceholder> placeholders = taskFile.getAnswerPlaceholders();
+    final List<AnswerPlaceholder> placeholders = taskFile.getActivePlaceholders();
     if (selectedAnswerPlaceholder == null) {
       for (AnswerPlaceholder placeholder : placeholders) {
         if (placeholder.getOffset() > offset) {
index 28444d14b67d7de11e5b5ecbaaeb18741413d9bc..68f18d7da4111596fd20b07d2d9009e13a3ff490 100644 (file)
@@ -27,7 +27,7 @@ public class StudyPrevWindowAction extends StudyWindowNavigationAction {
   @Override
   protected AnswerPlaceholder getTargetPlaceholder(@NotNull final TaskFile taskFile, int offset) {
     final AnswerPlaceholder selectedAnswerPlaceholder = taskFile.getAnswerPlaceholder(offset);
-    final List<AnswerPlaceholder> placeholders = taskFile.getAnswerPlaceholders();
+    final List<AnswerPlaceholder> placeholders = taskFile.getActivePlaceholders();
     if (selectedAnswerPlaceholder == null) {
       for (int i = placeholders.size() - 1; i >= 0; i--) {
         final AnswerPlaceholder placeholder = placeholders.get(i);
index c4046496b736954c61d3189eb67ebd817d7de3b4..59b89211bdbe1ca0ed3f0130ff2feb41f943fb7c 100644 (file)
@@ -104,7 +104,7 @@ public class StudyRefreshTaskFileAction extends StudyActionWithShortcut {
 
   private static void resetAnswerPlaceholders(TaskFile selectedTaskFile, Project project) {
     final StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
-    for (AnswerPlaceholder answerPlaceholder : selectedTaskFile.getAnswerPlaceholders()) {
+    for (AnswerPlaceholder answerPlaceholder : selectedTaskFile.getActivePlaceholders()) {
       answerPlaceholder.reset();
       taskManager.setStatus(answerPlaceholder, StudyStatus.Unchecked);
     }
index 73812b9be5bc0a5497e3483e99e4e7ce192f67eb..5569e2fd2e898f258c2842c3b948bbb7256b554a 100644 (file)
@@ -124,7 +124,7 @@ public class StudyCheckUtils {
       return;
     }
     final VirtualFile answerFile = getCopyWithAnswers(taskDir, virtualFile, taskFile, answerTaskFile);
-    for (final AnswerPlaceholder answerPlaceholder : answerTaskFile.getAnswerPlaceholders()) {
+    for (final AnswerPlaceholder answerPlaceholder : answerTaskFile.getActivePlaceholders()) {
       final Document document = FileDocumentManager.getInstance().getDocument(virtualFile);
       if (document == null) {
         continue;
@@ -150,7 +150,7 @@ public class StudyCheckUtils {
         TaskFile.copy(source, target);
         EduDocumentListener listener = new EduDocumentListener(target);
         document.addDocumentListener(listener);
-        for (AnswerPlaceholder answerPlaceholder : target.getAnswerPlaceholders()) {
+        for (AnswerPlaceholder answerPlaceholder : target.getActivePlaceholders()) {
           final int start = answerPlaceholder.getOffset();
           final int end = start + answerPlaceholder.getRealLength();
           final String text = answerPlaceholder.getPossibleAnswer();
index e67c2b62b2275433c7bf6127e4a2392a63941f2a..48ff8e48b24de9f80571bfbe3cc5b20381cb32df 100644 (file)
@@ -56,7 +56,7 @@ public class StudySmartChecker {
         windowDocument.addDocumentListener(listener);
         int start = placeholder.getOffset();
         int end = start + placeholder.getRealLength();
-        final AnswerPlaceholder userAnswerPlaceholder = usersTaskFile.getAnswerPlaceholders().get(placeholder.getIndex());
+        final AnswerPlaceholder userAnswerPlaceholder = usersTaskFile.getActivePlaceholders().get(placeholder.getIndex());
         int userStart = userAnswerPlaceholder.getOffset();
         int userEnd = userStart + userAnswerPlaceholder.getRealLength();
         String text = usersDocument.getText(new TextRange(userStart, userEnd));
index 5c83a89af9899b2bf10065942669d7092bf05ddc..b8a841b190816e63dec825acbca4622df1db450b 100644 (file)
@@ -76,7 +76,7 @@ public class EduAnswerPlaceholderPainter {
 
 
   public static void createGuardedBlocks(@NotNull final Editor editor, TaskFile taskFile) {
-    for (AnswerPlaceholder answerPlaceholder : taskFile.getAnswerPlaceholders()) {
+    for (AnswerPlaceholder answerPlaceholder : taskFile.getActivePlaceholders()) {
       createGuardedBlocks(editor, answerPlaceholder);
     }
   }
index fc6effb6ea939573ed62dabe9f5b75f1fc03827d..3ba5b458f85561b20e48d72e840a21ff42bdbe2e 100644 (file)
@@ -87,7 +87,7 @@ public class EduUtils {
       try {
         fileWindows = taskDir.createChildData(taskFile, name);
         printWriter = new PrintWriter(new FileOutputStream(fileWindows.getPath()));
-        for (AnswerPlaceholder answerPlaceholder : taskFile.getAnswerPlaceholders()) {
+        for (AnswerPlaceholder answerPlaceholder : taskFile.getActivePlaceholders()) {
           int length = answerPlaceholder.getRealLength();
           int start = answerPlaceholder.getOffset();
           final String windowDescription = document.getText(new TextRange(start, start + length));
@@ -163,7 +163,7 @@ public class EduUtils {
     EduDocumentListener listener = new EduDocumentListener(taskFile, false);
     studentDocument.addDocumentListener(listener);
 
-    for (AnswerPlaceholder placeholder : taskFile.getAnswerPlaceholders()) {
+    for (AnswerPlaceholder placeholder : taskFile.getActivePlaceholders()) {
       replaceAnswerPlaceholder(project, studentDocument, placeholder);
     }
     studentDocument.removeDocumentListener(listener);
index c3975ba5524a276ec8cd024de9df4ab5e911c6f5..a1532e804b2d7ac7dce0acee5fd0734a916ed582 100644 (file)
@@ -2,30 +2,18 @@ package com.jetbrains.edu.learning.courseFormat;
 
 import com.google.gson.annotations.Expose;
 import com.google.gson.annotations.SerializedName;
-import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.util.containers.HashMap;
 import com.intellij.util.xmlb.annotations.Transient;
 import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
 
-import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Implementation of windows which user should type in
  */
 
 public class AnswerPlaceholder {
-  private static final Logger LOG = Logger.getInstance(AnswerPlaceholder.class);
-  
-  @SerializedName("hint")
-  @Expose private String myHint = "";
-
-  @SerializedName("additional_hints")
-  @Expose private List<String> myAdditionalHints = new ArrayList<>();
-
-  @SerializedName("possible_answer")
-  @Expose private String possibleAnswer = "";
 
   @SerializedName("offset")
   @Expose private int myOffset = -1;
@@ -33,15 +21,14 @@ public class AnswerPlaceholder {
   @Expose private int length = -1;
 
   private int myIndex = -1;
-  private String myTaskText;
   private MyInitialState myInitialState;
   private StudyStatus myStatus = StudyStatus.Unchecked;
   private boolean mySelected = false;
   private boolean myUseLength = true;
 
-
   @Transient private TaskFile myTaskFile;
 
+  @Expose private Map<Integer, AnswerPlaceholderSubtaskInfo> mySubtaskInfos = new HashMap<>();
   public AnswerPlaceholder() {
   }
 
@@ -73,21 +60,14 @@ public class AnswerPlaceholder {
     this.length = length;
   }
 
-  @NotNull
-  public List<String> getAdditionalHints() {
-    return myAdditionalHints;
-  }
-
-  public void setAdditionalHints(@Nullable final List<String> additionalHints) {
-    myAdditionalHints = additionalHints;
-  }
-
+  @Transient
   public String getPossibleAnswer() {
-    return possibleAnswer;
+    return getActiveSubtaskInfo().getPossibleAnswer();
   }
 
+  @Transient
   public void setPossibleAnswer(String possibleAnswer) {
-    this.possibleAnswer = possibleAnswer;
+    getActiveSubtaskInfo().setPossibleAnswer(possibleAnswer);
   }
 
   public MyInitialState getInitialState() {
@@ -98,12 +78,14 @@ public class AnswerPlaceholder {
     myInitialState = initialState;
   }
 
+  @Transient
   public String getTaskText() {
-    return myTaskText;
+    return getActiveSubtaskInfo().getPlaceholderText();
   }
 
+  @Transient
   public void setTaskText(String taskText) {
-    myTaskText = taskText;
+    getActiveSubtaskInfo().setPlaceholderText(taskText);
   }
 
   @Transient
@@ -117,7 +99,7 @@ public class AnswerPlaceholder {
   }
 
   public int getPossibleAnswerLength() {
-    return possibleAnswer.length();
+    return getPossibleAnswer().length();
   }
 
   /**
@@ -126,9 +108,6 @@ public class AnswerPlaceholder {
   public void reset() {
     myOffset = myInitialState.getOffset();
     length = myInitialState.getLength();
-    if (!myUseLength) {
-      possibleAnswer = myTaskText;
-    }
   }
 
   public StudyStatus getStatus() {
@@ -148,7 +127,7 @@ public class AnswerPlaceholder {
   }
 
   public void init() {
-    setInitialState(new MyInitialState(myOffset, myTaskText.length()));
+    setInitialState(new MyInitialState(myOffset, getTaskText().length()));
   }
 
   public boolean getUseLength() {
@@ -174,65 +153,30 @@ public class AnswerPlaceholder {
     myOffset = offset;
   }
 
-  public String getHint() {
-    return myHint;
-  }
-
-  public void setHint(String hint) {
-    myHint = hint;
-  }
-
   @Transient
   public List<String> getHints() {
-    if (myHint.isEmpty() && myAdditionalHints.isEmpty()) return Collections.emptyList();
-    final ArrayList<String> result = new ArrayList<>();
-    result.add(myHint);
-    result.addAll(myAdditionalHints);
-    return result;
+    return getActiveSubtaskInfo().getHints();
   }
 
   @Transient
   public void setHints(@NotNull final List<String> hints) {
-    if (hints.isEmpty()) {
-      myHint = "";
-      myAdditionalHints.clear();
-    }
-    else {
-      myHint = hints.get(0);
-      myAdditionalHints = hints.subList(1, hints.size());
-    }
-  }
-
-  public void setHintByIndex(int i, @NotNull final String text) {
-    if (i == 0) {
-      myHint = text;
-    }
-    else {
-      myAdditionalHints.set(i - 1, text);
-    }
+   getActiveSubtaskInfo().setHints(hints);
   }
 
   public void addHint(@NotNull final String text) {
-    if (myHint.isEmpty() && myAdditionalHints.isEmpty()) {
-      myHint = text;
-    }
-    else {
-      myAdditionalHints.add(text);
-    }
+    getActiveSubtaskInfo().addHint(text);
   }
 
   public void removeHint(int i) {
-    if (i == 0) {
-      myHint = "";
-    }
-    else {
-      if (i - 1 <myAdditionalHints.size()) {
-        myAdditionalHints.remove(i - 1);
-      }
-      else {
-        LOG.warn("Trying to remove nonexistent hint. Hint to remove number: " + (i - 1) + "number of hints: " + getHints().size());
-      }
-    }
+    getActiveSubtaskInfo().removeHint(i);
+  }
+
+  public Map<Integer, AnswerPlaceholderSubtaskInfo> getSubtaskInfos() {
+    return mySubtaskInfos;
+  }
+
+  public void setSubtaskInfos(Map<Integer, AnswerPlaceholderSubtaskInfo> subtaskInfos) {
+    mySubtaskInfos = subtaskInfos;
   }
 
   public static class MyInitialState {
@@ -263,4 +207,12 @@ public class AnswerPlaceholder {
       this.offset = offset;
     }
   }
+
+  public AnswerPlaceholderSubtaskInfo getActiveSubtaskInfo() {
+    if (myTaskFile == null || myTaskFile.getTask() == null) {
+      return mySubtaskInfos.get(0);
+    }
+    int activeStepIndex = myTaskFile.getTask().getActiveStepIndex();
+    return mySubtaskInfos.get(activeStepIndex);
+  }
 }
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/AnswerPlaceholderSubtaskInfo.java b/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/AnswerPlaceholderSubtaskInfo.java
new file mode 100644 (file)
index 0000000..b648592
--- /dev/null
@@ -0,0 +1,130 @@
+package com.jetbrains.edu.learning.courseFormat;
+
+import com.google.gson.annotations.Expose;
+import com.google.gson.annotations.SerializedName;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.util.xmlb.annotations.Transient;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class AnswerPlaceholderSubtaskInfo {
+  private static final Logger LOG = Logger.getInstance(AnswerPlaceholderSubtaskInfo.class);
+  @SerializedName("hint")
+  @Expose private String myHint = "";
+
+  @SerializedName("additional_hints")
+  @Expose private List<String> myAdditionalHints = new ArrayList<>();
+
+  @SerializedName("possible_answer")
+  @Expose private String possibleAnswer = "";
+
+  @Expose private String myPlaceholderText;
+  private boolean mySelected = false;
+  private StudyStatus myStatus = StudyStatus.Unchecked;
+  @Expose private boolean myHasFrame = true;
+
+  public StudyStatus getStatus() {
+    return myStatus;
+  }
+
+  public void setStatus(StudyStatus status) {
+    myStatus = status;
+  }
+
+  @Transient
+  public List<String> getHints() {
+    if (myHint.isEmpty() && myAdditionalHints.isEmpty()) return Collections.emptyList();
+    final ArrayList<String> result = new ArrayList<>();
+    result.add(myHint);
+    result.addAll(myAdditionalHints);
+    return result;
+  }
+
+  @Transient
+  public void setHints(@NotNull final List<String> hints) {
+    if (hints.isEmpty()) {
+      myHint = "";
+      myAdditionalHints.clear();
+    }
+    else {
+      myHint = hints.get(0);
+      myAdditionalHints = hints.subList(1, hints.size());
+    }
+  }
+
+  public void addHint(@NotNull final String text) {
+    if (myHint.isEmpty() && myAdditionalHints.isEmpty()) {
+      myHint = text;
+    }
+    else {
+      myAdditionalHints.add(text);
+    }
+  }
+
+  public void removeHint(int i) {
+    if (i == 0) {
+      myHint = "";
+    }
+    else {
+      if (i - 1 <myAdditionalHints.size()) {
+        myAdditionalHints.remove(i - 1);
+      }
+      else {
+        LOG.warn("Trying to remove nonexistent hint. Hint to remove number: " + (i - 1) + "number of hints: " + getHints().size());
+      }
+    }
+  }
+
+  @NotNull
+  public List<String> getAdditionalHints() {
+    return myAdditionalHints;
+  }
+
+  public void setAdditionalHints(@Nullable final List<String> additionalHints) {
+    myAdditionalHints = additionalHints;
+  }
+
+  public String getPossibleAnswer() {
+    return possibleAnswer;
+  }
+
+  public void setPossibleAnswer(String possibleAnswer) {
+    this.possibleAnswer = possibleAnswer;
+  }
+
+  public String getPlaceholderText() {
+    return myPlaceholderText;
+  }
+
+  public void setPlaceholderText(String placeholderText) {
+    myPlaceholderText = placeholderText;
+  }
+
+  public String getHint() {
+    return myHint;
+  }
+
+  public void setHint(String hint) {
+    myHint = hint;
+  }
+
+  public boolean getSelected() {
+    return mySelected;
+  }
+
+  public void setSelected(boolean selected) {
+    mySelected = selected;
+  }
+
+  public boolean isHasFrame() {
+    return myHasFrame;
+  }
+
+  public void setHasFrame(boolean hasFrame) {
+    myHasFrame = hasFrame;
+  }
+}
index 378b68e24afc50c8ab49c23ed0b149377edd1997..7f4318dcfa82c014c8ecf52ed15f47b68ed2bb41 100644 (file)
@@ -42,6 +42,8 @@ public class Task implements StudyItem {
   @Transient private Lesson myLesson;
   @Expose @SerializedName("update_date") private Date myUpdateDate;
 
+  private int myActiveStepIndex = 0;
+
   public Task() {}
 
   public Task(@NotNull final String name) {
@@ -219,7 +221,7 @@ public class Task implements StudyItem {
   public void setStatus(StudyStatus status) {
     myStatus = status;
     for (TaskFile taskFile : taskFiles.values()) {
-      for (AnswerPlaceholder placeholder : taskFile.getAnswerPlaceholders()) {
+      for (AnswerPlaceholder placeholder : taskFile.getActivePlaceholders()) {
         placeholder.setStatus(status);
       }
     }
@@ -250,4 +252,12 @@ public class Task implements StudyItem {
     if (myUpdateDate == null) return false;
     return !date.after(myUpdateDate);
   }
+
+  public int getActiveStepIndex() {
+    return myActiveStepIndex;
+  }
+
+  public void setActiveStepIndex(int activeStepIndex) {
+    myActiveStepIndex = activeStepIndex;
+  }
 }
index 26dd6cdafc0843936bca7bfbe0a0717a84110e50..9682cebd5a70a164353fd1cc2b50cf9097740606 100644 (file)
@@ -44,6 +44,16 @@ public class TaskFile {
     return myAnswerPlaceholders;
   }
 
+  public List<AnswerPlaceholder> getActivePlaceholders() {
+    List<AnswerPlaceholder> result = new ArrayList<>();
+    for (AnswerPlaceholder placeholder : myAnswerPlaceholders) {
+      if (placeholder.getActiveSubtaskInfo() != null) {
+        result.add(placeholder);
+      }
+    }
+    return result;
+  }
+
   public void setAnswerPlaceholders(List<AnswerPlaceholder> answerPlaceholders) {
     this.myAnswerPlaceholders = answerPlaceholders;
   }
@@ -88,7 +98,7 @@ public class TaskFile {
 
 
   public static void copy(@NotNull final TaskFile source, @NotNull final TaskFile target) {
-    List<AnswerPlaceholder> sourceAnswerPlaceholders = source.getAnswerPlaceholders();
+    List<AnswerPlaceholder> sourceAnswerPlaceholders = source.getActivePlaceholders();
     List<AnswerPlaceholder> answerPlaceholdersCopy = new ArrayList<>(sourceAnswerPlaceholders.size());
     for (AnswerPlaceholder answerPlaceholder : sourceAnswerPlaceholders) {
       AnswerPlaceholder answerPlaceholderCopy = new AnswerPlaceholder();
index 5df925d276f8e16e92ff723e022fb042cd9cae97..6c714792132e8e2c193b600c1e673f6a329687b5 100644 (file)
@@ -184,7 +184,7 @@ public class StudyProjectGenerator {
       final VirtualFile virtualFile = ((VirtualDirectoryImpl)taskDir).refreshAndFindChild(name);
       if (virtualFile != null) {
         FileEditorManager.getInstance(project).openFile(virtualFile, true);
-        if (!taskFile.getAnswerPlaceholders().isEmpty()) {
+        if (!taskFile.getActivePlaceholders().isEmpty()) {
           activeVirtualFile = virtualFile;
         }
       }
index 3749d196cc2d46a44ae48bb56f86d73ef11d1efe..9a420b3dd20e4c1b88754afab53b14af3e542c53 100644 (file)
@@ -74,7 +74,7 @@ public class StudyNavigator {
   public static void navigateToFirstFailedAnswerPlaceholder(@NotNull final Editor editor, @NotNull final TaskFile taskFile) {
     final Project project = editor.getProject();
     if (project == null) return;
-    for (AnswerPlaceholder answerPlaceholder : taskFile.getAnswerPlaceholders()) {
+    for (AnswerPlaceholder answerPlaceholder : taskFile.getActivePlaceholders()) {
       if (answerPlaceholder.getStatus() != StudyStatus.Failed) {
         continue;
       }
@@ -94,8 +94,8 @@ public class StudyNavigator {
 
 
   public static void navigateToFirstAnswerPlaceholder(@NotNull final Editor editor, @NotNull final TaskFile taskFile) {
-    if (!taskFile.getAnswerPlaceholders().isEmpty()) {
-      AnswerPlaceholder firstAnswerPlaceholder = StudyUtils.getFirst(taskFile.getAnswerPlaceholders());
+    if (!taskFile.getActivePlaceholders().isEmpty()) {
+      AnswerPlaceholder firstAnswerPlaceholder = StudyUtils.getFirst(taskFile.getActivePlaceholders());
       if (firstAnswerPlaceholder == null) return;
       navigateToAnswerPlaceholder(editor, firstAnswerPlaceholder);
     }
@@ -113,7 +113,7 @@ public class StudyNavigator {
         if (shouldBeActive != null) {
           FileEditorManager.getInstance(project).openFile(vf, true);
         }
-        if (shouldBeActive == null && !taskFile.getAnswerPlaceholders().isEmpty()) {
+        if (shouldBeActive == null && !taskFile.getActivePlaceholders().isEmpty()) {
           shouldBeActive = vf;
         }
       }
index 5461d80515774cecc66dc2665b9b5529d06e9744..623d648e27ec26fc91344b36aa7cbc3daa168fcd 100644 (file)
@@ -165,7 +165,7 @@ public class StudyDirectoryNode extends PsiDirectoryNode {
           if (file != null) {
             FileEditorManager.getInstance(myProject).openFile(file, true);
           }
-          if (!entry.getValue().getAnswerPlaceholders().isEmpty()) {
+          if (!entry.getValue().getActivePlaceholders().isEmpty()) {
             child = file;
           }
         }
index 3b1104243c6f216b43c466a86ba7ca56fdf1441f..8185e689834c49c835752ec94b45a88f3c5f3727 100644 (file)
@@ -72,7 +72,7 @@ public class PyCCCommandLineState extends PythonCommandLineState {
   private String getFirstTaskFilePath() {
     for (Map.Entry<String, TaskFile> entry : myTask.getTaskFiles().entrySet()) {
       String path = getTaskFilePath(entry.getKey());
-      if (!entry.getValue().getAnswerPlaceholders().isEmpty()) {
+      if (!entry.getValue().getActivePlaceholders().isEmpty()) {
         return path;
       }
       VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByPath(path);
index 9bea1b5a731a45233b29281bdb92e1d5c804b9c5..9adf69d8837680b578d5dabc806bd64a10c9697a 100644 (file)
@@ -101,7 +101,7 @@ public class PyStudyCheckAction extends StudyCheckAction {
           for (Map.Entry<String, TaskFile> entry : myTask.getTaskFiles().entrySet()) {
             final String name = entry.getKey();
             final TaskFile taskFile = entry.getValue();
-            if (taskFile.getAnswerPlaceholders().size() < 2) {
+            if (taskFile.getActivePlaceholders().size() < 2) {
               continue;
             }
             final Course course = myTaskManger.getCourse();
@@ -141,7 +141,7 @@ public class PyStudyCheckAction extends StudyCheckAction {
       TaskFile taskFile = entry.getValue();
       VirtualFile virtualFile = taskDir.findChild(name);
       if (virtualFile != null) {
-        if (!taskFile.getAnswerPlaceholders().isEmpty()) {
+        if (!taskFile.getActivePlaceholders().isEmpty()) {
           taskVirtualFile = virtualFile;
         }
       }