mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
extracted course format from interactive learning
This commit is contained in:
+2
-1
@@ -27,9 +27,10 @@ public class AnswerPlaceholder implements Comparable<AnswerPlaceholder> {
|
||||
@Expose private String hint;
|
||||
@Expose private String possible_answer;
|
||||
@Expose private int length;
|
||||
private int myIndex;
|
||||
|
||||
private String myTaskText;
|
||||
private int myReplacementLength;
|
||||
private int myIndex;
|
||||
|
||||
public String getHint() {
|
||||
return hint;
|
||||
|
||||
@@ -7,5 +7,7 @@
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="platform-api" />
|
||||
<orderEntry type="library" name="gson" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -5,10 +5,12 @@
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/src/com/jetbrains/edu/learning/course" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="lang-impl" />
|
||||
<orderEntry type="library" name="gson" level="project" />
|
||||
<orderEntry type="module" module-name="educational" />
|
||||
</component>
|
||||
</module>
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package com.jetbrains.edu.learning;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Implementation of class which contains information to be shawn in course description in tool window
|
||||
* and when project is being created
|
||||
*/
|
||||
public class CourseInfo {
|
||||
boolean is_public;
|
||||
public List<Integer> sections;
|
||||
@SerializedName("title")
|
||||
private String myName;
|
||||
@SerializedName("summary")
|
||||
private String myDescription;
|
||||
|
||||
private String myAuthor;
|
||||
public static CourseInfo INVALID_COURSE = new CourseInfo("", "", "");
|
||||
|
||||
public CourseInfo(String name, String author, String description) {
|
||||
myName = name;
|
||||
myAuthor = author;
|
||||
myDescription = description;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return myAuthor;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return myDescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
CourseInfo that = (CourseInfo)o;
|
||||
return that.getName().equals(myName) && that.getAuthor().equals(myAuthor)
|
||||
&& that.getDescription().equals(myDescription);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = myName != null ? myName.hashCode() : 0;
|
||||
result = 31 * result + (myAuthor != null ? myAuthor.hashCode() : 0);
|
||||
result = 31 * result + (myDescription != null ? myDescription.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.jetbrains.edu.learning;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.jetbrains.edu.courseFormat.Task;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class StudyCourseResourceManager {
|
||||
|
||||
/**
|
||||
* Gets text of resource file such as test input file or task text in needed format
|
||||
*
|
||||
* @param fileName name of resource file which should exist in task directory
|
||||
* @param wrapHTML if it's necessary to wrap text with html tags
|
||||
* @return text of resource file wrapped with html tags if necessary
|
||||
*/
|
||||
@Nullable
|
||||
public String getResourceText(@NotNull final Project project, @NotNull final Task task, @NotNull final String fileName, boolean wrapHTML) {
|
||||
VirtualFile taskDir = task.getTaskDir(project);
|
||||
if (taskDir != null) {
|
||||
return StudyUtils.getFileText(taskDir.getCanonicalPath(), fileName, wrapHTML, "UTF-8");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -5,8 +5,8 @@ import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.event.DocumentAdapter;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.editor.impl.event.DocumentEventImpl;
|
||||
import com.jetbrains.edu.learning.course.TaskFile;
|
||||
import com.jetbrains.edu.learning.course.AnswerPlaceholder;
|
||||
import com.jetbrains.edu.courseFormat.AnswerPlaceholder;
|
||||
import com.jetbrains.edu.courseFormat.TaskFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
+7
-6
@@ -13,9 +13,10 @@ import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.problems.WolfTheProblemSolver;
|
||||
import com.jetbrains.edu.learning.course.AnswerPlaceholder;
|
||||
import com.jetbrains.edu.learning.course.TaskFile;
|
||||
import com.jetbrains.edu.courseFormat.AnswerPlaceholder;
|
||||
import com.jetbrains.edu.courseFormat.TaskFile;
|
||||
import com.jetbrains.edu.learning.editor.StudyEditor;
|
||||
import com.jetbrains.edu.learning.navigation.StudyNavigator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.awt.*;
|
||||
@@ -41,10 +42,10 @@ class StudyEditorFactoryListener implements EditorFactoryListener {
|
||||
final AnswerPlaceholder answerPlaceholder = myTaskFile.getAnswerPlaceholder(editor.getDocument(), pos);
|
||||
if (answerPlaceholder != null) {
|
||||
myTaskFile.setSelectedAnswerPlaceholder(answerPlaceholder);
|
||||
answerPlaceholder.draw(editor);
|
||||
StudyPainter.drawAnswerPlaceholder(editor, answerPlaceholder);
|
||||
}
|
||||
else {
|
||||
myTaskFile.drawAllWindows(editor);
|
||||
StudyPainter.drawAllWindows(editor, myTaskFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,11 +71,11 @@ class StudyEditorFactoryListener implements EditorFactoryListener {
|
||||
final StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
|
||||
final TaskFile taskFile = taskManager.getTaskFile(openedFile);
|
||||
if (taskFile != null) {
|
||||
taskFile.navigateToFirstTaskWindow(editor);
|
||||
StudyNavigator.navigateToFirstTaskWindow(editor, taskFile);
|
||||
editor.addEditorMouseListener(new WindowSelectionListener(taskFile));
|
||||
StudyEditor.addDocumentListener(document, new StudyDocumentListener(taskFile));
|
||||
WolfTheProblemSolver.getInstance(project).clearProblems(openedFile);
|
||||
taskFile.drawAllWindows(editor);
|
||||
StudyPainter.drawAllWindows(editor, taskFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ import com.intellij.lang.LanguageExtension;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.jetbrains.edu.learning.course.Task;
|
||||
import com.jetbrains.edu.courseFormat.Task;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
package com.jetbrains.edu.learning;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.jetbrains.edu.StudyNames;
|
||||
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 org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class StudyGenerator {
|
||||
private StudyGenerator() {
|
||||
|
||||
}
|
||||
private static final Logger LOG = Logger.getInstance(StudyGenerator.class.getName());
|
||||
|
||||
/**
|
||||
* Creates task files in its task folder in project user created
|
||||
*
|
||||
* @param taskDir project directory of task which task file belongs to
|
||||
* @param resourceRoot directory where original task file stored
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void createTaskFile(@NotNull final VirtualFile taskDir, @NotNull final File resourceRoot,
|
||||
@NotNull final String name) throws IOException {
|
||||
String systemIndependentName = FileUtil.toSystemIndependentName(name);
|
||||
final int index = systemIndependentName.lastIndexOf("/");
|
||||
if (index > 0) {
|
||||
systemIndependentName = systemIndependentName.substring(index + 1);
|
||||
}
|
||||
File resourceFile = new File(resourceRoot, name);
|
||||
File fileInProject = new File(taskDir.getPath(), systemIndependentName);
|
||||
FileUtil.copy(resourceFile, fileInProject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates task directory in its lesson folder in project user created
|
||||
*
|
||||
* @param lessonDir project directory of lesson which task belongs to
|
||||
* @param resourceRoot directory where original task file stored
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void createTask(@NotNull final Task task, @NotNull final VirtualFile lessonDir, @NotNull final File resourceRoot,
|
||||
@NotNull final Project project) throws IOException {
|
||||
VirtualFile taskDir = lessonDir.createChildDirectory(project, StudyNames.TASK_DIR + Integer.toString(task.getIndex() + 1));
|
||||
StudyUtils.markDirAsSourceRoot(taskDir, project);
|
||||
File newResourceRoot = new File(resourceRoot, taskDir.getName());
|
||||
int i = 0;
|
||||
for (Map.Entry<String, TaskFile> taskFile : task.getTaskFiles().entrySet()) {
|
||||
TaskFile taskFileContent = taskFile.getValue();
|
||||
taskFileContent.setIndex(i);
|
||||
i++;
|
||||
createTaskFile(taskDir, newResourceRoot, taskFile.getKey());
|
||||
}
|
||||
File[] filesInTask = newResourceRoot.listFiles();
|
||||
if (filesInTask != null) {
|
||||
for (File file : filesInTask) {
|
||||
String fileName = file.getName();
|
||||
if (!task.isTaskFile(fileName)) {
|
||||
File resourceFile = new File(newResourceRoot, fileName);
|
||||
File fileInProject = new File(taskDir.getCanonicalPath(), fileName);
|
||||
FileUtil.copy(resourceFile, fileInProject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates lesson directory in its course folder in project user created
|
||||
*
|
||||
* @param courseDir project directory of course
|
||||
* @param resourceRoot directory where original lesson stored
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void createLesson(@NotNull final Lesson lesson, @NotNull final VirtualFile courseDir, @NotNull final File resourceRoot,
|
||||
@NotNull final Project project) throws IOException {
|
||||
String lessonDirName = StudyNames.LESSON_DIR + Integer.toString(lesson.getIndex() + 1);
|
||||
VirtualFile lessonDir = courseDir.createChildDirectory(project, lessonDirName);
|
||||
final List<Task> taskList = lesson.getTaskList();
|
||||
for (int i = 0; i < taskList.size(); i++) {
|
||||
Task task = taskList.get(i);
|
||||
task.setIndex(i);
|
||||
createTask(task, lessonDir, new File(resourceRoot, lessonDir.getName()), project);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates course directory in project user created
|
||||
*
|
||||
* @param baseDir project directory
|
||||
* @param resourceRoot directory where original course is stored
|
||||
*/
|
||||
public static void createCourse(@NotNull final Course course, @NotNull final VirtualFile baseDir, @NotNull final File resourceRoot,
|
||||
@NotNull final Project project) {
|
||||
ApplicationManager.getApplication().invokeLater(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
final List<Lesson> lessons = course.getLessons();
|
||||
for (int i = 0; i < lessons.size(); i++) {
|
||||
Lesson lesson = lessons.get(i);
|
||||
lesson.setIndex(i);
|
||||
createLesson(lesson, baseDir, resourceRoot, project);
|
||||
}
|
||||
baseDir.createChildDirectory(this, StudyNames.SANDBOX_DIR);
|
||||
File[] files = resourceRoot.listFiles(new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(File dir, String name) {
|
||||
return !name.contains(StudyNames.LESSON_DIR) && !name.equals("course.json") && !name.equals("hints");
|
||||
}
|
||||
});
|
||||
for (File file : files) {
|
||||
FileUtil.copy(file, new File(baseDir.getPath(), file.getName()));
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -4,7 +4,7 @@ import com.intellij.codeInsight.highlighting.HighlightErrorFilter;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiErrorElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.jetbrains.edu.learning.course.TaskFile;
|
||||
import com.jetbrains.edu.courseFormat.TaskFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class StudyHighlightErrorFilter extends HighlightErrorFilter{
|
||||
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
package com.jetbrains.edu.learning;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.editor.actionSystem.EditorActionManager;
|
||||
import com.intellij.openapi.editor.colors.EditorColors;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsManager;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsScheme;
|
||||
import com.intellij.openapi.editor.impl.DocumentImpl;
|
||||
import com.intellij.openapi.editor.markup.*;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.jetbrains.edu.courseFormat.AnswerPlaceholder;
|
||||
import com.jetbrains.edu.courseFormat.TaskFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
|
||||
public class StudyPainter {
|
||||
private StudyPainter() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw task window with color according to its status
|
||||
*/
|
||||
public static void drawAnswerPlaceholder(@NotNull final Editor editor, AnswerPlaceholder answerPlaceholder) {
|
||||
Document document = editor.getDocument();
|
||||
if (!answerPlaceholder.isValid(document)) {
|
||||
return;
|
||||
}
|
||||
EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme();
|
||||
final TextAttributes defaultTestAttributes = new TextAttributes(scheme.getDefaultForeground(), scheme.getDefaultBackground(), null,
|
||||
EffectType.BOXED, Font.PLAIN);
|
||||
final JBColor color = answerPlaceholder.getColor();
|
||||
int startOffset = answerPlaceholder.getRealStartOffset(document);
|
||||
RangeHighlighter
|
||||
highlighter = editor.getMarkupModel().addRangeHighlighter(startOffset, startOffset + answerPlaceholder.getLength(), HighlighterLayer.LAST + 1,
|
||||
defaultTestAttributes, HighlighterTargetArea.EXACT_RANGE);
|
||||
highlighter.setCustomRenderer(new CustomHighlighterRenderer() {
|
||||
@Override
|
||||
public void paint(@NotNull Editor editor, @NotNull RangeHighlighter highlighter, @NotNull Graphics g) {
|
||||
g.setColor(color);
|
||||
Point point = editor.logicalPositionToXY(editor.offsetToLogicalPosition(highlighter.getStartOffset()));
|
||||
Point pointEnd = editor.logicalPositionToXY(editor.offsetToLogicalPosition(highlighter.getEndOffset()));
|
||||
g.drawRect(point.x, point.y - 2, (pointEnd.x - point.x), editor.getLineHeight() + 1);
|
||||
}
|
||||
});
|
||||
editor.getCaretModel().moveToOffset(startOffset);
|
||||
highlighter.setGreedyToLeft(true);
|
||||
highlighter.setGreedyToRight(true);
|
||||
}
|
||||
|
||||
|
||||
public static void drawAllWindows(Editor editor, TaskFile taskFile) {
|
||||
editor.getMarkupModel().removeAllHighlighters();
|
||||
for (AnswerPlaceholder answerPlaceholder : taskFile.getAnswerPlaceholders()) {
|
||||
drawAnswerPlaceholder(editor, answerPlaceholder);
|
||||
}
|
||||
final Document document = editor.getDocument();
|
||||
EditorActionManager.getInstance()
|
||||
.setReadonlyFragmentModificationHandler(document, new TaskWindowDeleteHandler(editor));
|
||||
createGuardedBlocks(editor, taskFile);
|
||||
editor.getColorsScheme().setColor(EditorColors.READONLY_FRAGMENT_BACKGROUND_COLOR, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Marks symbols adjacent to task windows as read-only fragments
|
||||
*/
|
||||
public static void createGuardedBlocks(@NotNull final Editor editor, TaskFile taskFile) {
|
||||
final Document document = editor.getDocument();
|
||||
if (document instanceof DocumentImpl) {
|
||||
DocumentImpl documentImpl = (DocumentImpl)document;
|
||||
List<RangeMarker> blocks = documentImpl.getGuardedBlocks();
|
||||
for (AnswerPlaceholder answerPlaceholder : taskFile.getAnswerPlaceholders()) {
|
||||
if (!answerPlaceholder.isValid(document)) {
|
||||
return;
|
||||
}
|
||||
int start = answerPlaceholder.getRealStartOffset(document);
|
||||
int end = start + answerPlaceholder.getLength();
|
||||
if (start != 0) {
|
||||
createGuardedBlock(editor, blocks, start - 1, start);
|
||||
}
|
||||
if (end != document.getTextLength()) {
|
||||
createGuardedBlock(editor, blocks, end, end + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void createGuardedBlock(Editor editor, List<RangeMarker> blocks, int start, int end) {
|
||||
RangeHighlighter rh = editor.getMarkupModel()
|
||||
.addRangeHighlighter(start, end, HighlighterLayer.LAST + 1, null, HighlighterTargetArea.EXACT_RANGE);
|
||||
blocks.add(rh);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+5
-2
@@ -24,7 +24,10 @@ import com.intellij.openapi.wm.ex.ToolWindowManagerEx;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.edu.learning.course.*;
|
||||
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.learning.stepic.StudyStepicConnector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -56,7 +59,7 @@ public class StudyProjectGenerator {
|
||||
flushCourse(course);
|
||||
course.init(false);
|
||||
final File courseDirectory = new File(myCoursesDir, course.getName());
|
||||
course.create(baseDir, courseDirectory, project);
|
||||
StudyGenerator.createCourse(course, baseDir, courseDirectory, project);
|
||||
course.setCourseDirectory(new File(myCoursesDir, mySelectedCourseInfo.getName()).getAbsolutePath());
|
||||
VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
|
||||
StudyTaskManager.getInstance(project).setCourse(course);
|
||||
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package com.jetbrains.edu.learning;
|
||||
|
||||
import com.intellij.execution.ExecutionException;
|
||||
import com.intellij.execution.process.CapturingProcessHandler;
|
||||
import com.intellij.execution.process.ProcessOutput;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.jetbrains.edu.StudyNames;
|
||||
import com.jetbrains.edu.courseFormat.AnswerPlaceholder;
|
||||
import com.jetbrains.edu.courseFormat.StudyStatus;
|
||||
import com.jetbrains.edu.courseFormat.TaskFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class StudySmartChecker {
|
||||
private StudySmartChecker() {
|
||||
|
||||
}
|
||||
private static final Logger LOG = Logger.getInstance(StudySmartChecker.class);
|
||||
|
||||
public static void smartCheck(@NotNull final AnswerPlaceholder placeholder,
|
||||
@NotNull final Project project,
|
||||
@NotNull final VirtualFile answerFile,
|
||||
@NotNull final TaskFile answerTaskFile,
|
||||
@NotNull final TaskFile usersTaskFile,
|
||||
@NotNull final StudyTestRunner testRunner,
|
||||
@NotNull final VirtualFile virtualFile,
|
||||
@NotNull final Document usersDocument) {
|
||||
|
||||
try {
|
||||
final int index = placeholder.getIndex();
|
||||
final VirtualFile windowCopy =
|
||||
answerFile.copy(project, answerFile.getParent(), answerFile.getNameWithoutExtension() + index + StudyNames.WINDOW_POSTFIX);
|
||||
final FileDocumentManager documentManager = FileDocumentManager.getInstance();
|
||||
final Document windowDocument = documentManager.getDocument(windowCopy);
|
||||
if (windowDocument != null) {
|
||||
final File resourceFile = StudyUtils.copyResourceFile(virtualFile.getName(), windowCopy.getName(), project, usersTaskFile.getTask());
|
||||
final TaskFile windowTaskFile = new TaskFile();
|
||||
TaskFile.copy(answerTaskFile, windowTaskFile);
|
||||
StudyDocumentListener listener = new StudyDocumentListener(windowTaskFile);
|
||||
windowDocument.addDocumentListener(listener);
|
||||
int start = placeholder.getRealStartOffset(windowDocument);
|
||||
int end = start + placeholder.getLength();
|
||||
final AnswerPlaceholder userAnswerPlaceholder = usersTaskFile.getAnswerPlaceholders().get(placeholder.getIndex());
|
||||
int userStart = userAnswerPlaceholder.getRealStartOffset(usersDocument);
|
||||
int userEnd = userStart + userAnswerPlaceholder.getLength();
|
||||
String text = usersDocument.getText(new TextRange(userStart, userEnd));
|
||||
windowDocument.replaceString(start, end, text);
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
documentManager.saveDocument(windowDocument);
|
||||
}
|
||||
});
|
||||
VirtualFile fileWindows = StudyUtils.flushWindows(windowTaskFile, windowCopy);
|
||||
Process smartTestProcess = testRunner.createCheckProcess(project, windowCopy.getPath());
|
||||
final CapturingProcessHandler handler = new CapturingProcessHandler(smartTestProcess);
|
||||
final ProcessOutput output = handler.runProcess();
|
||||
boolean res = testRunner.getTestsOutput(output).equals(StudyTestRunner.TEST_OK);
|
||||
userAnswerPlaceholder.setStatus(res ? StudyStatus.Solved : StudyStatus.Failed, StudyStatus.Unchecked);
|
||||
StudyUtils.deleteFile(windowCopy);
|
||||
if (fileWindows != null) {
|
||||
StudyUtils.deleteFile(fileWindows);
|
||||
}
|
||||
if (!resourceFile.delete()) {
|
||||
LOG.error("failed to delete", resourceFile.getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -3,8 +3,8 @@ package com.jetbrains.edu.learning;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.jetbrains.edu.learning.course.Task;
|
||||
import com.jetbrains.edu.learning.course.TaskFile;
|
||||
import com.jetbrains.edu.courseFormat.Task;
|
||||
import com.jetbrains.edu.courseFormat.TaskFile;
|
||||
import com.jetbrains.edu.learning.editor.StudyEditor;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
||||
+9
-8
@@ -27,11 +27,12 @@ import com.intellij.openapi.vfs.VirtualFileEvent;
|
||||
import com.intellij.openapi.vfs.VirtualFileManager;
|
||||
import com.intellij.openapi.wm.*;
|
||||
import com.intellij.util.xmlb.XmlSerializer;
|
||||
import com.jetbrains.edu.StudyNames;
|
||||
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.learning.actions.*;
|
||||
import com.jetbrains.edu.learning.course.Course;
|
||||
import com.jetbrains.edu.learning.course.Lesson;
|
||||
import com.jetbrains.edu.learning.course.Task;
|
||||
import com.jetbrains.edu.learning.course.TaskFile;
|
||||
import com.jetbrains.edu.learning.ui.StudyCondition;
|
||||
import com.jetbrains.edu.learning.ui.StudyToolWindowFactory;
|
||||
import org.jdom.Element;
|
||||
@@ -326,7 +327,7 @@ public class StudyTaskManager implements ProjectComponent, PersistentStateCompon
|
||||
return null;
|
||||
}
|
||||
final String taskDirName = taskDir.getName();
|
||||
if (taskDirName.contains(Task.TASK_DIR)) {
|
||||
if (taskDirName.contains(StudyNames.TASK_DIR)) {
|
||||
final VirtualFile lessonDir = taskDir.getParent();
|
||||
if (lessonDir != null) {
|
||||
int lessonIndex = StudyUtils.getIndex(lessonDir.getName(), StudyNames.LESSON_DIR);
|
||||
@@ -335,7 +336,7 @@ public class StudyTaskManager implements ProjectComponent, PersistentStateCompon
|
||||
return null;
|
||||
}
|
||||
final Lesson lesson = lessons.get(lessonIndex);
|
||||
int taskIndex = StudyUtils.getIndex(taskDirName, Task.TASK_DIR);
|
||||
int taskIndex = StudyUtils.getIndex(taskDirName, StudyNames.TASK_DIR);
|
||||
final List<Task> tasks = lesson.getTaskList();
|
||||
if (!StudyUtils.indexIsValid(taskIndex, tasks)) {
|
||||
return null;
|
||||
@@ -352,8 +353,8 @@ public class StudyTaskManager implements ProjectComponent, PersistentStateCompon
|
||||
public void fileCreated(@NotNull VirtualFileEvent event) {
|
||||
final VirtualFile createdFile = event.getFile();
|
||||
final VirtualFile taskDir = createdFile.getParent();
|
||||
if (taskDir != null && taskDir.getName().contains(Task.TASK_DIR)) {
|
||||
int taskIndex = StudyUtils.getIndex(taskDir.getName(), Task.TASK_DIR);
|
||||
if (taskDir != null && taskDir.getName().contains(StudyNames.TASK_DIR)) {
|
||||
int taskIndex = StudyUtils.getIndex(taskDir.getName(), StudyNames.TASK_DIR);
|
||||
final VirtualFile lessonDir = taskDir.getParent();
|
||||
if (lessonDir != null && lessonDir.getName().contains(StudyNames.LESSON_DIR)) {
|
||||
int lessonIndex = StudyUtils.getIndex(lessonDir.getName(), StudyNames.LESSON_DIR);
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import com.intellij.execution.ExecutionException;
|
||||
import com.intellij.execution.process.ProcessOutput;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.jetbrains.edu.learning.course.Task;
|
||||
import com.jetbrains.edu.courseFormat.Task;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public abstract class StudyTestRunner {
|
||||
|
||||
+6
-2
@@ -29,7 +29,11 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileManager;
|
||||
import com.intellij.openapi.wm.ToolWindowManager;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.jetbrains.edu.learning.course.*;
|
||||
import com.jetbrains.edu.StudyNames;
|
||||
import com.jetbrains.edu.courseFormat.AnswerPlaceholder;
|
||||
import com.jetbrains.edu.courseFormat.Course;
|
||||
import com.jetbrains.edu.courseFormat.Task;
|
||||
import com.jetbrains.edu.courseFormat.TaskFile;
|
||||
import com.jetbrains.edu.learning.editor.StudyEditor;
|
||||
import com.jetbrains.edu.learning.ui.StudyToolWindowFactory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -197,7 +201,7 @@ public class StudyUtils {
|
||||
int taskNum = task.getIndex() + 1;
|
||||
int lessonNum = task.getLesson().getIndex() + 1;
|
||||
assert course != null;
|
||||
final String pathToResource = FileUtil.join(course.getCourseDirectory(), StudyNames.LESSON_DIR + lessonNum, Task.TASK_DIR + taskNum);
|
||||
final String pathToResource = FileUtil.join(course.getCourseDirectory(), StudyNames.LESSON_DIR + lessonNum, StudyNames.TASK_DIR + taskNum);
|
||||
final File resourceFile = new File(pathToResource, copyName);
|
||||
FileUtil.copy(new File(pathToResource, sourceName), resourceFile);
|
||||
return resourceFile;
|
||||
|
||||
+11
-11
@@ -30,15 +30,13 @@ import com.intellij.openapi.wm.IdeFrame;
|
||||
import com.intellij.openapi.wm.WindowManager;
|
||||
import com.intellij.openapi.wm.ex.StatusBarEx;
|
||||
import com.intellij.openapi.wm.ex.WindowManagerEx;
|
||||
import com.jetbrains.edu.learning.StudyDocumentListener;
|
||||
import com.jetbrains.edu.learning.StudyState;
|
||||
import com.jetbrains.edu.learning.StudyTestRunner;
|
||||
import com.jetbrains.edu.learning.StudyUtils;
|
||||
import com.jetbrains.edu.learning.course.StudyStatus;
|
||||
import com.jetbrains.edu.learning.course.Task;
|
||||
import com.jetbrains.edu.learning.course.TaskFile;
|
||||
import com.jetbrains.edu.learning.course.AnswerPlaceholder;
|
||||
import com.jetbrains.edu.courseFormat.AnswerPlaceholder;
|
||||
import com.jetbrains.edu.courseFormat.StudyStatus;
|
||||
import com.jetbrains.edu.courseFormat.Task;
|
||||
import com.jetbrains.edu.courseFormat.TaskFile;
|
||||
import com.jetbrains.edu.learning.*;
|
||||
import com.jetbrains.edu.learning.editor.StudyEditor;
|
||||
import com.jetbrains.edu.learning.navigation.StudyNavigator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -98,7 +96,7 @@ public class StudyCheckAction extends DumbAwareAction {
|
||||
FileEditor fileEditor = FileEditorManager.getInstance(project).getSelectedEditor(virtualFile);
|
||||
if (fileEditor instanceof StudyEditor) {
|
||||
StudyEditor studyEditor = (StudyEditor)fileEditor;
|
||||
taskFile.drawAllWindows(studyEditor.getEditor());
|
||||
StudyPainter.drawAllWindows(studyEditor.getEditor(), taskFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -303,7 +301,8 @@ public class StudyCheckAction extends DumbAwareAction {
|
||||
IdeFocusManager.getInstance(project).requestFocus(editorToNavigate.getContentComponent(), true);
|
||||
}
|
||||
});
|
||||
taskFileToNavigate.navigateToFirstFailedTaskWindow(editor);
|
||||
|
||||
StudyNavigator.navigateToFirstFailedTaskWindow(editor, taskFileToNavigate);
|
||||
}
|
||||
|
||||
private void runSmartTestProcess(@NotNull final VirtualFile taskDir,
|
||||
@@ -325,7 +324,8 @@ public class StudyCheckAction extends DumbAwareAction {
|
||||
if (!answerPlaceholder.isValid(document)) {
|
||||
continue;
|
||||
}
|
||||
answerPlaceholder.smartCheck(project, answerFile, answerTaskFile, taskFile, testRunner, virtualFile, document);
|
||||
StudySmartChecker.smartCheck(answerPlaceholder, project, answerFile, answerTaskFile, taskFile, testRunner,
|
||||
virtualFile, document);
|
||||
}
|
||||
StudyUtils.deleteFile(answerFile);
|
||||
}
|
||||
|
||||
+5
-5
@@ -20,12 +20,12 @@ import com.intellij.ui.tabs.TabInfo;
|
||||
import com.intellij.ui.tabs.TabsListener;
|
||||
import com.intellij.ui.tabs.impl.JBEditorTabs;
|
||||
import com.intellij.util.PlatformIcons;
|
||||
import com.jetbrains.edu.learning.StudyNames;
|
||||
import com.jetbrains.edu.StudyNames;
|
||||
import com.jetbrains.edu.courseFormat.Task;
|
||||
import com.jetbrains.edu.courseFormat.TaskFile;
|
||||
import com.jetbrains.edu.courseFormat.UserTest;
|
||||
import com.jetbrains.edu.learning.StudyTaskManager;
|
||||
import com.jetbrains.edu.learning.StudyUtils;
|
||||
import com.jetbrains.edu.learning.course.Task;
|
||||
import com.jetbrains.edu.learning.course.TaskFile;
|
||||
import com.jetbrains.edu.learning.course.UserTest;
|
||||
import com.jetbrains.edu.learning.editor.StudyEditor;
|
||||
import com.jetbrains.edu.learning.ui.StudyTestContentPanel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -62,7 +62,7 @@ public class StudyEditInputAction extends DumbAwareAction {
|
||||
if (newSelection.getIcon() != null) {
|
||||
int tabCount = tabbedPane.getTabCount();
|
||||
VirtualFile taskDir = openedFile.getParent();
|
||||
VirtualFile testsDir = taskDir.findChild(Task.USER_TESTS);
|
||||
VirtualFile testsDir = taskDir.findChild(StudyNames.USER_TESTS);
|
||||
assert testsDir != null;
|
||||
UserTest userTest = createUserTest(testsDir, currentTask);
|
||||
userTest.setEditable(true);
|
||||
|
||||
+3
-2
@@ -1,7 +1,8 @@
|
||||
package com.jetbrains.edu.learning.actions;
|
||||
|
||||
import com.jetbrains.edu.learning.course.Task;
|
||||
import com.jetbrains.edu.courseFormat.Task;
|
||||
import com.jetbrains.edu.learning.editor.StudyEditor;
|
||||
import com.jetbrains.edu.learning.navigation.StudyNavigator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -23,6 +24,6 @@ public class StudyNextStudyTaskAction extends StudyTaskNavigationAction {
|
||||
|
||||
@Override
|
||||
protected Task getTargetTask(@NotNull final Task sourceTask) {
|
||||
return sourceTask.next();
|
||||
return StudyNavigator.nextTask(sourceTask);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
package com.jetbrains.edu.learning.actions;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.jetbrains.edu.courseFormat.AnswerPlaceholder;
|
||||
import com.jetbrains.edu.learning.StudyUtils;
|
||||
import com.jetbrains.edu.learning.course.AnswerPlaceholder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
package com.jetbrains.edu.learning.actions;
|
||||
|
||||
import com.jetbrains.edu.courseFormat.AnswerPlaceholder;
|
||||
import com.jetbrains.edu.learning.StudyUtils;
|
||||
import com.jetbrains.edu.learning.course.AnswerPlaceholder;
|
||||
import icons.InteractiveLearningIcons;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
+3
-2
@@ -1,8 +1,9 @@
|
||||
package com.jetbrains.edu.learning.actions;
|
||||
|
||||
|
||||
import com.jetbrains.edu.learning.course.Task;
|
||||
import com.jetbrains.edu.courseFormat.Task;
|
||||
import com.jetbrains.edu.learning.editor.StudyEditor;
|
||||
import com.jetbrains.edu.learning.navigation.StudyNavigator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -23,6 +24,6 @@ public class StudyPreviousStudyTaskAction extends StudyTaskNavigationAction {
|
||||
|
||||
@Override
|
||||
protected Task getTargetTask(@NotNull final Task sourceTask) {
|
||||
return sourceTask.prev();
|
||||
return StudyNavigator.previousTask(sourceTask);
|
||||
}
|
||||
}
|
||||
+10
-6
@@ -19,12 +19,15 @@ import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.wm.IdeFocusManager;
|
||||
import com.jetbrains.edu.learning.StudyNames;
|
||||
import com.intellij.problems.WolfTheProblemSolver;
|
||||
import com.jetbrains.edu.StudyNames;
|
||||
import com.jetbrains.edu.courseFormat.*;
|
||||
import com.jetbrains.edu.courseFormat.info.LessonInfo;
|
||||
import com.jetbrains.edu.learning.StudyPainter;
|
||||
import com.jetbrains.edu.learning.StudyState;
|
||||
import com.jetbrains.edu.learning.StudyUtils;
|
||||
import com.jetbrains.edu.learning.course.*;
|
||||
import com.jetbrains.edu.learning.editor.StudyEditor;
|
||||
import com.jetbrains.edu.learning.navigation.StudyNavigator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
@@ -63,15 +66,16 @@ public class StudyRefreshTaskFileAction extends DumbAwareAction {
|
||||
}
|
||||
WolfTheProblemSolver.getInstance(project).clearProblems(studyState.getVirtualFile());
|
||||
taskFile.setHighlightErrors(false);
|
||||
taskFile.drawAllWindows(editor);
|
||||
taskFile.createGuardedBlocks(editor);
|
||||
StudyPainter.drawAllWindows(editor, taskFile);
|
||||
StudyPainter.createGuardedBlocks(editor, taskFile);
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
IdeFocusManager.getInstance(project).requestFocus(editor.getContentComponent(), true);
|
||||
}
|
||||
});
|
||||
taskFile.navigateToFirstTaskWindow(editor);
|
||||
|
||||
StudyNavigator.navigateToFirstTaskWindow(editor, taskFile);
|
||||
showBalloon(project, "You can start again now", MessageType.INFO);
|
||||
}
|
||||
|
||||
@@ -121,7 +125,7 @@ public class StudyRefreshTaskFileAction extends DumbAwareAction {
|
||||
clearDocument(document);
|
||||
Task task = taskFile.getTask();
|
||||
String lessonDir = StudyNames.LESSON_DIR + String.valueOf(task.getLesson().getIndex() + 1);
|
||||
String taskDir = Task.TASK_DIR + String.valueOf(task.getIndex() + 1);
|
||||
String taskDir = StudyNames.TASK_DIR + String.valueOf(task.getIndex() + 1);
|
||||
Course course = task.getLesson().getCourse();
|
||||
File resourceFile = new File(course.getCourseDirectory());
|
||||
if (!resourceFile.exists()) {
|
||||
|
||||
+2
-2
@@ -14,10 +14,10 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.jetbrains.edu.courseFormat.Task;
|
||||
import com.jetbrains.edu.courseFormat.TaskFile;
|
||||
import com.jetbrains.edu.learning.StudyTaskManager;
|
||||
import com.jetbrains.edu.learning.StudyUtils;
|
||||
import com.jetbrains.edu.learning.course.Task;
|
||||
import com.jetbrains.edu.learning.course.TaskFile;
|
||||
import com.jetbrains.edu.learning.editor.StudyEditor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
||||
+2
-2
@@ -13,11 +13,11 @@ import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.jetbrains.edu.courseFormat.AnswerPlaceholder;
|
||||
import com.jetbrains.edu.courseFormat.Course;
|
||||
import com.jetbrains.edu.learning.StudyState;
|
||||
import com.jetbrains.edu.learning.StudyTaskManager;
|
||||
import com.jetbrains.edu.learning.StudyUtils;
|
||||
import com.jetbrains.edu.learning.course.AnswerPlaceholder;
|
||||
import com.jetbrains.edu.learning.course.Course;
|
||||
import com.jetbrains.edu.learning.editor.StudyEditor;
|
||||
import icons.InteractiveLearningIcons;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
+4
-4
@@ -14,10 +14,10 @@ import com.intellij.openapi.wm.ToolWindow;
|
||||
import com.intellij.openapi.wm.ToolWindowId;
|
||||
import com.intellij.openapi.wm.ToolWindowManager;
|
||||
import com.intellij.util.ui.tree.TreeUtil;
|
||||
import com.jetbrains.edu.learning.StudyNames;
|
||||
import com.jetbrains.edu.StudyNames;
|
||||
import com.jetbrains.edu.courseFormat.Task;
|
||||
import com.jetbrains.edu.courseFormat.TaskFile;
|
||||
import com.jetbrains.edu.learning.StudyState;
|
||||
import com.jetbrains.edu.learning.course.Task;
|
||||
import com.jetbrains.edu.learning.course.TaskFile;
|
||||
import com.jetbrains.edu.learning.editor.StudyEditor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -60,7 +60,7 @@ abstract public class StudyTaskNavigationAction extends DumbAwareAction {
|
||||
if (lessonDir == null) {
|
||||
return;
|
||||
}
|
||||
String taskDirName = Task.TASK_DIR + String.valueOf(nextTaskIndex + 1);
|
||||
String taskDirName = StudyNames.TASK_DIR + String.valueOf(nextTaskIndex + 1);
|
||||
VirtualFile taskDir = lessonDir.findChild(taskDirName);
|
||||
if (taskDir == null) {
|
||||
return;
|
||||
|
||||
+4
-3
@@ -6,11 +6,12 @@ import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.jetbrains.edu.courseFormat.AnswerPlaceholder;
|
||||
import com.jetbrains.edu.courseFormat.TaskFile;
|
||||
import com.jetbrains.edu.learning.StudyTaskManager;
|
||||
import com.jetbrains.edu.learning.StudyUtils;
|
||||
import com.jetbrains.edu.learning.course.AnswerPlaceholder;
|
||||
import com.jetbrains.edu.learning.course.TaskFile;
|
||||
import com.jetbrains.edu.learning.editor.StudyEditor;
|
||||
import com.jetbrains.edu.learning.navigation.StudyNavigator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -39,7 +40,7 @@ abstract public class StudyWindowNavigationAction extends DumbAwareAction {
|
||||
if (nextAnswerPlaceholder == null) {
|
||||
return;
|
||||
}
|
||||
selectedTaskFile.navigateToTaskWindow(selectedEditor, nextAnswerPlaceholder);
|
||||
StudyNavigator.navigateToTaskWindow(selectedEditor, nextAnswerPlaceholder, selectedTaskFile);
|
||||
selectedTaskFile.setSelectedAnswerPlaceholder(nextAnswerPlaceholder);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -33,11 +33,11 @@ import com.intellij.ui.HideableTitledPanel;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.util.ui.EmptyClipboardOwner;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.jetbrains.edu.courseFormat.Task;
|
||||
import com.jetbrains.edu.courseFormat.TaskFile;
|
||||
import com.jetbrains.edu.learning.StudyDocumentListener;
|
||||
import com.jetbrains.edu.learning.StudyTaskManager;
|
||||
import com.jetbrains.edu.learning.actions.*;
|
||||
import com.jetbrains.edu.learning.course.Task;
|
||||
import com.jetbrains.edu.learning.course.TaskFile;
|
||||
import icons.InteractiveLearningIcons;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
+1
-1
@@ -8,8 +8,8 @@ import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.jetbrains.edu.courseFormat.TaskFile;
|
||||
import com.jetbrains.edu.learning.StudyTaskManager;
|
||||
import com.jetbrains.edu.learning.course.TaskFile;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package com.jetbrains.edu.learning.navigation;
|
||||
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.LogicalPosition;
|
||||
import com.jetbrains.edu.courseFormat.*;
|
||||
import com.jetbrains.edu.learning.StudyUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class StudyNavigator {
|
||||
private StudyNavigator() {
|
||||
|
||||
}
|
||||
|
||||
public static Task nextTask(@NotNull final Task task) {
|
||||
Lesson currentLesson = task.getLesson();
|
||||
List<Task> taskList = currentLesson.getTaskList();
|
||||
if (task.getIndex() + 1 < taskList.size()) {
|
||||
return taskList.get(task.getIndex() + 1);
|
||||
}
|
||||
Lesson nextLesson = nextLesson(currentLesson);
|
||||
if (nextLesson == null) {
|
||||
return null;
|
||||
}
|
||||
return StudyUtils.getFirst(nextLesson.getTaskList());
|
||||
}
|
||||
|
||||
public static Task previousTask(@NotNull final Task task) {
|
||||
Lesson currentLesson = task.getLesson();
|
||||
if (task.getIndex() - 1 >= 0) {
|
||||
return currentLesson.getTaskList().get(task.getIndex() - 1);
|
||||
}
|
||||
Lesson prevLesson = previousLesson(currentLesson);
|
||||
if (prevLesson == null) {
|
||||
return null;
|
||||
}
|
||||
//getting last task in previous lesson
|
||||
return prevLesson.getTaskList().get(prevLesson.getTaskList().size() - 1);
|
||||
}
|
||||
|
||||
public static Lesson nextLesson(@NotNull final Lesson lesson) {
|
||||
List<Lesson> lessons = lesson.getCourse().getLessons();
|
||||
if (lesson.getIndex() + 1 >= lessons.size()) {
|
||||
return null;
|
||||
}
|
||||
return lessons.get(lesson.getIndex() + 1);
|
||||
}
|
||||
|
||||
public static Lesson previousLesson(@NotNull final Lesson lesson) {
|
||||
if (lesson.getIndex() - 1 < 0) {
|
||||
return null;
|
||||
}
|
||||
return lesson.getCourse().getLessons().get(lesson.getIndex() - 1);
|
||||
}
|
||||
|
||||
public static void navigateToFirstFailedTaskWindow(@NotNull final Editor editor, @NotNull final TaskFile taskFile) {
|
||||
for (AnswerPlaceholder answerPlaceholder : taskFile.getAnswerPlaceholders()) {
|
||||
if (answerPlaceholder.getStatus() != StudyStatus.Failed) {
|
||||
continue;
|
||||
}
|
||||
navigateToTaskWindow(editor, answerPlaceholder, taskFile);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void navigateToTaskWindow(@NotNull final Editor editor, @NotNull final AnswerPlaceholder answerPlaceholder,
|
||||
@NotNull final TaskFile taskFile) {
|
||||
if (!answerPlaceholder.isValid(editor.getDocument())) {
|
||||
return;
|
||||
}
|
||||
taskFile.setSelectedAnswerPlaceholder(answerPlaceholder);
|
||||
LogicalPosition taskWindowStart = new LogicalPosition(answerPlaceholder.getLine(), answerPlaceholder.getStart());
|
||||
editor.getCaretModel().moveToLogicalPosition(taskWindowStart);
|
||||
}
|
||||
|
||||
|
||||
public static void navigateToFirstTaskWindow(@NotNull final Editor editor, @NotNull final TaskFile taskFile) {
|
||||
if (!taskFile.getAnswerPlaceholders().isEmpty()) {
|
||||
AnswerPlaceholder firstAnswerPlaceholder = StudyUtils.getFirst(taskFile.getAnswerPlaceholders());
|
||||
navigateToTaskWindow(editor, firstAnswerPlaceholder, taskFile);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+12
-12
@@ -11,10 +11,10 @@ import com.intellij.psi.PsiDirectory;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.jetbrains.edu.learning.StudyNames;
|
||||
import com.jetbrains.edu.StudyNames;
|
||||
import com.jetbrains.edu.courseFormat.*;
|
||||
import com.jetbrains.edu.learning.StudyTaskManager;
|
||||
import com.jetbrains.edu.learning.StudyUtils;
|
||||
import com.jetbrains.edu.learning.course.*;
|
||||
import icons.InteractiveLearningIcons;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -49,7 +49,7 @@ public class StudyDirectoryNode extends PsiDirectoryNode {
|
||||
data.addText(" (" + valueName + ")", SimpleTextAttributes.GRAYED_ATTRIBUTES);
|
||||
return;
|
||||
}
|
||||
if (valueName.contains(Task.TASK_DIR)) {
|
||||
if (valueName.contains(StudyNames.TASK_DIR)) {
|
||||
TaskFile file = null;
|
||||
for (PsiElement child : myValue.getChildren()) {
|
||||
VirtualFile virtualFile = child.getContainingFile().getVirtualFile();
|
||||
@@ -69,10 +69,10 @@ public class StudyDirectoryNode extends PsiDirectoryNode {
|
||||
setStudyAttributes(lesson, data, lesson.getName());
|
||||
}
|
||||
|
||||
if (valueName.contains(Course.SANDBOX_DIR)) {
|
||||
if (valueName.contains(StudyNames.SANDBOX_DIR)) {
|
||||
if (myValue.getParent() != null) {
|
||||
if (!myValue.getParent().getName().contains(Course.SANDBOX_DIR)) {
|
||||
data.setPresentableText(Course.SANDBOX_DIR);
|
||||
if (!myValue.getParent().getName().contains(StudyNames.SANDBOX_DIR)) {
|
||||
data.setPresentableText(StudyNames.SANDBOX_DIR);
|
||||
data.setIcon(InteractiveLearningIcons.Sandbox);
|
||||
return;
|
||||
}
|
||||
@@ -84,14 +84,14 @@ public class StudyDirectoryNode extends PsiDirectoryNode {
|
||||
@Override
|
||||
public int getTypeSortWeight(boolean sortByType) {
|
||||
String name = myValue.getName();
|
||||
if (name.contains(StudyNames.LESSON_DIR) || name.contains(Task.TASK_DIR)) {
|
||||
String logicalName = name.contains(StudyNames.LESSON_DIR) ? StudyNames.LESSON_DIR : Task.TASK_DIR;
|
||||
if (name.contains(StudyNames.LESSON_DIR) || name.contains(StudyNames.TASK_DIR)) {
|
||||
String logicalName = name.contains(StudyNames.LESSON_DIR) ? StudyNames.LESSON_DIR : StudyNames.TASK_DIR;
|
||||
return StudyUtils.getIndex(name, logicalName) + 1;
|
||||
}
|
||||
return name.contains(Course.SANDBOX_DIR) ? 0 : 3;
|
||||
return name.contains(StudyNames.SANDBOX_DIR) ? 0 : 3;
|
||||
}
|
||||
|
||||
private static void setStudyAttributes(Stateful stateful, PresentationData data, String additionalName) {
|
||||
private static void setStudyAttributes(StudyStateful stateful, PresentationData data, String additionalName) {
|
||||
StudyStatus taskStatus = stateful.getStatus();
|
||||
switch (taskStatus) {
|
||||
case Unchecked: {
|
||||
@@ -127,7 +127,7 @@ public class StudyDirectoryNode extends PsiDirectoryNode {
|
||||
|
||||
@Override
|
||||
public void navigate(boolean requestFocus) {
|
||||
if (myValue.getName().contains(Task.TASK_DIR)) {
|
||||
if (myValue.getName().contains(StudyNames.TASK_DIR)) {
|
||||
TaskFile taskFile = null;
|
||||
VirtualFile virtualFile = null;
|
||||
for (PsiElement child : myValue.getChildren()) {
|
||||
@@ -170,7 +170,7 @@ public class StudyDirectoryNode extends PsiDirectoryNode {
|
||||
|
||||
@Override
|
||||
public boolean expandOnDoubleClick() {
|
||||
if (myValue.getName().contains(Task.TASK_DIR)) {
|
||||
if (myValue.getName().contains(StudyNames.TASK_DIR)) {
|
||||
return false;
|
||||
}
|
||||
return super.expandOnDoubleClick();
|
||||
|
||||
+4
-5
@@ -8,10 +8,9 @@ import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiDirectory;
|
||||
import com.jetbrains.edu.StudyNames;
|
||||
import com.jetbrains.edu.courseFormat.TaskFile;
|
||||
import com.jetbrains.edu.learning.StudyTaskManager;
|
||||
import com.jetbrains.edu.learning.course.Course;
|
||||
import com.jetbrains.edu.learning.course.Task;
|
||||
import com.jetbrains.edu.learning.course.TaskFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -33,7 +32,7 @@ public class StudyTreeStructureProvider implements TreeStructureProvider, DumbAw
|
||||
if (project != null) {
|
||||
if (node.getValue() instanceof PsiDirectory) {
|
||||
final PsiDirectory nodeValue = (PsiDirectory)node.getValue();
|
||||
if (!nodeValue.getName().contains(Task.USER_TESTS)) {
|
||||
if (!nodeValue.getName().contains(StudyNames.USER_TESTS)) {
|
||||
StudyDirectoryNode newNode = new StudyDirectoryNode(project, nodeValue, settings);
|
||||
nodes.add(newNode);
|
||||
}
|
||||
@@ -51,7 +50,7 @@ public class StudyTreeStructureProvider implements TreeStructureProvider, DumbAw
|
||||
}
|
||||
final String parentName = parent.getName();
|
||||
if (parentName != null) {
|
||||
if (parentName.equals(Course.SANDBOX_DIR)) {
|
||||
if (parentName.equals(StudyNames.SANDBOX_DIR)) {
|
||||
nodes.add(node);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-1
@@ -5,7 +5,11 @@ import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.util.io.HttpRequests;
|
||||
import com.jetbrains.edu.learning.course.*;
|
||||
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.learning.CourseInfo;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
|
||||
+1
-1
@@ -3,9 +3,9 @@ package com.jetbrains.edu.learning.ui;
|
||||
import com.intellij.facet.ui.FacetValidatorsManager;
|
||||
import com.intellij.facet.ui.ValidationResult;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.jetbrains.edu.learning.CourseInfo;
|
||||
import com.jetbrains.edu.learning.StudyProjectGenerator;
|
||||
import com.jetbrains.edu.learning.StudyUtils;
|
||||
import com.jetbrains.edu.learning.course.CourseInfo;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ package com.jetbrains.edu.learning.ui;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.ui.DocumentAdapter;
|
||||
import com.intellij.ui.components.JBScrollPane;
|
||||
import com.jetbrains.edu.learning.course.UserTest;
|
||||
import com.jetbrains.edu.courseFormat.UserTest;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
+4
-4
@@ -7,11 +7,11 @@ import com.intellij.openapi.wm.ToolWindowFactory;
|
||||
import com.intellij.ui.content.Content;
|
||||
import com.intellij.ui.content.ContentFactory;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.jetbrains.edu.courseFormat.Course;
|
||||
import com.jetbrains.edu.courseFormat.Lesson;
|
||||
import com.jetbrains.edu.courseFormat.StudyStatus;
|
||||
import com.jetbrains.edu.courseFormat.info.LessonInfo;
|
||||
import com.jetbrains.edu.learning.StudyTaskManager;
|
||||
import com.jetbrains.edu.learning.course.Course;
|
||||
import com.jetbrains.edu.learning.course.Lesson;
|
||||
import com.jetbrains.edu.learning.course.LessonInfo;
|
||||
import com.jetbrains.edu.learning.course.StudyStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
+8
-1
@@ -13,18 +13,25 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jetbrains.edu.learning;
|
||||
package com.jetbrains.edu;
|
||||
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
|
||||
@NonNls
|
||||
public class StudyNames {
|
||||
public static final String TASK_HTML = "task.html";
|
||||
public static final String TASK_TESTS = "tests.py";
|
||||
public static final String LESSON = "lesson";
|
||||
public static final String TEST_HELPER = "test_helper.py";
|
||||
public static final String USER_TESTER = "user_tester.py";
|
||||
public static final String LESSON_DIR = "lesson";
|
||||
public static final String TEST_TAB_NAME = "test";
|
||||
public static final String USER_TEST_INPUT = "input";
|
||||
public static final String USER_TEST_OUTPUT = "output";
|
||||
public static final String WINDOW_POSTFIX = "_window.py";
|
||||
public static final String TASK_DIR = "task";
|
||||
public static final String USER_TESTS = "userTests";
|
||||
public static final String SANDBOX_DIR = "Sandbox";
|
||||
|
||||
private StudyNames() {
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
package com.jetbrains.edu.courseFormat;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.ui.JBColor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Implementation of windows which user should type in
|
||||
*/
|
||||
|
||||
public class AnswerPlaceholder implements Comparable, StudyStateful {
|
||||
|
||||
@Expose private int line = 0;
|
||||
@Expose private int start = 0;
|
||||
@Expose private String hint = "";
|
||||
@SerializedName("possible_answer")
|
||||
@Expose private String possibleAnswer = "";
|
||||
@Expose private int length = 0;
|
||||
private int myIndex = -1;
|
||||
private StudyStatus myStatus = StudyStatus.Unchecked;
|
||||
private String myTaskText;
|
||||
private MyInitialState myInitialState;
|
||||
|
||||
|
||||
private TaskFile myTaskFile;
|
||||
|
||||
public void init(final TaskFile file, boolean isRestarted) {
|
||||
if (!isRestarted) {
|
||||
myInitialState = new MyInitialState(line, length, start);
|
||||
}
|
||||
myTaskFile = file;
|
||||
}
|
||||
|
||||
public StudyStatus getStatus() {
|
||||
return myStatus;
|
||||
}
|
||||
|
||||
public void setStatus(StudyStatus status, StudyStatus oldStatus) {
|
||||
myStatus = status;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return myIndex;
|
||||
}
|
||||
|
||||
public void setIndex(int index) {
|
||||
myIndex = index;
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
public void setLength(int length) {
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public int getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public void setStart(int start) {
|
||||
this.start = start;
|
||||
}
|
||||
|
||||
public int getLine() {
|
||||
return line;
|
||||
}
|
||||
|
||||
public void setLine(int line) {
|
||||
this.line = line;
|
||||
}
|
||||
|
||||
public String getHint() {
|
||||
return hint;
|
||||
}
|
||||
|
||||
public void setHint(@NotNull final String hint) {
|
||||
this.hint = hint;
|
||||
}
|
||||
|
||||
public String getPossibleAnswer() {
|
||||
return possibleAnswer;
|
||||
}
|
||||
|
||||
public void setPossibleAnswer(String possibleAnswer) {
|
||||
this.possibleAnswer = possibleAnswer;
|
||||
}
|
||||
|
||||
public MyInitialState getInitialState() {
|
||||
return myInitialState;
|
||||
}
|
||||
|
||||
public void setInitialState(@NotNull final MyInitialState initialState) {
|
||||
myInitialState = initialState;
|
||||
}
|
||||
|
||||
public TaskFile getTaskFile() {
|
||||
return myTaskFile;
|
||||
}
|
||||
|
||||
public JBColor getColor() {
|
||||
if (myStatus == StudyStatus.Solved) {
|
||||
return JBColor.GREEN;
|
||||
}
|
||||
if (myStatus == StudyStatus.Failed) {
|
||||
return JBColor.RED;
|
||||
}
|
||||
return JBColor.BLUE;
|
||||
}
|
||||
|
||||
public int getRealStartOffset(@NotNull final Document document) {
|
||||
return document.getLineStartOffset(line) + start;
|
||||
}
|
||||
|
||||
public boolean isValid(@NotNull final Document document) {
|
||||
boolean isLineValid = line < document.getLineCount() && line >= 0;
|
||||
if (!isLineValid) return false;
|
||||
boolean isStartValid = start >= 0 && start < document.getLineEndOffset(line);
|
||||
boolean isLengthValid = (getRealStartOffset(document) + length) <= document.getTextLength();
|
||||
return isLengthValid && isStartValid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull Object o) {
|
||||
AnswerPlaceholder answerPlaceholder = (AnswerPlaceholder)o;
|
||||
if (answerPlaceholder.getTaskFile() != myTaskFile) {
|
||||
throw new ClassCastException();
|
||||
}
|
||||
int lineDiff = line - answerPlaceholder.line;
|
||||
if (lineDiff == 0) {
|
||||
return start - answerPlaceholder.start;
|
||||
}
|
||||
return lineDiff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns window to its initial state
|
||||
*/
|
||||
public void reset() {
|
||||
myStatus = StudyStatus.Unchecked;
|
||||
line = myInitialState.myLine;
|
||||
start = myInitialState.myStart;
|
||||
length = myInitialState.myLength;
|
||||
}
|
||||
|
||||
private static class MyInitialState {
|
||||
public int myLine = -1;
|
||||
public int myLength = -1;
|
||||
public int myStart = -1;
|
||||
|
||||
public MyInitialState() {
|
||||
}
|
||||
|
||||
public MyInitialState(int line, int length, int start) {
|
||||
myLine = line;
|
||||
myLength = length;
|
||||
myStart = start;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.jetbrains.edu.courseFormat;
|
||||
|
||||
import com.intellij.lang.Language;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Course {
|
||||
public List<Lesson> lessons = new ArrayList<Lesson>();
|
||||
|
||||
private String description;
|
||||
private String name;
|
||||
private String myCourseDirectory = "";
|
||||
private String author="";
|
||||
private boolean myUpToDate;
|
||||
private String myLanguage;
|
||||
|
||||
/**
|
||||
* Initializes state of course
|
||||
*/
|
||||
public void init(boolean isRestarted) {
|
||||
for (Lesson lesson : lessons) {
|
||||
lesson.init(this, isRestarted);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Lesson> getLessons() {
|
||||
return lessons;
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(String author) {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getCourseDirectory() {
|
||||
return myCourseDirectory;
|
||||
}
|
||||
|
||||
public void setCourseDirectory(@NotNull final String courseDirectory) {
|
||||
myCourseDirectory = courseDirectory;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public boolean isUpToDate() {
|
||||
return myUpToDate;
|
||||
}
|
||||
|
||||
public void setUpToDate(boolean upToDate) {
|
||||
myUpToDate = upToDate;
|
||||
}
|
||||
|
||||
public Language getLanguageById() {
|
||||
return Language.findLanguageByID(myLanguage);
|
||||
}
|
||||
|
||||
public String getLanguage() {
|
||||
return myLanguage;
|
||||
}
|
||||
|
||||
public void setLanguage(@NotNull final String language) {
|
||||
myLanguage = language;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.jetbrains.edu.courseFormat;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.intellij.util.xmlb.annotations.Transient;
|
||||
import com.jetbrains.edu.courseFormat.info.LessonInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Lesson implements StudyStateful {
|
||||
@Transient
|
||||
String id;
|
||||
@Transient
|
||||
public List<Integer> steps;
|
||||
@Transient
|
||||
public List<String> tags;
|
||||
@Transient
|
||||
Boolean is_public;
|
||||
@SerializedName("title")
|
||||
private String name;
|
||||
|
||||
public List<Task> taskList = new ArrayList<Task>();
|
||||
private Course myCourse = null;
|
||||
private int myIndex = -1;
|
||||
private LessonInfo myLessonInfo = new LessonInfo();
|
||||
|
||||
|
||||
public void init(final Course course, boolean isRestarted) {
|
||||
myCourse = course;
|
||||
myLessonInfo.setTaskNum(taskList.size());
|
||||
myLessonInfo.setTaskUnchecked(taskList.size());
|
||||
for (Task task : taskList) {
|
||||
task.init(this, isRestarted);
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return myIndex;
|
||||
}
|
||||
|
||||
public void setIndex(int index) {
|
||||
myIndex = index;
|
||||
}
|
||||
|
||||
public LessonInfo getLessonInfo() {
|
||||
return myLessonInfo;
|
||||
}
|
||||
|
||||
@Transient
|
||||
public StudyStatus getStatus() {
|
||||
for (Task task : taskList) {
|
||||
StudyStatus taskStatus = task.getStatus();
|
||||
if (taskStatus == StudyStatus.Unchecked || taskStatus == StudyStatus.Failed) {
|
||||
return StudyStatus.Unchecked;
|
||||
}
|
||||
}
|
||||
return StudyStatus.Solved;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatus(StudyStatus status, StudyStatus oldStatus) {
|
||||
for (Task task : taskList) {
|
||||
task.setStatus(status, oldStatus);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Task> getTaskList() {
|
||||
return taskList;
|
||||
}
|
||||
|
||||
public Course getCourse() {
|
||||
return myCourse;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.jetbrains.edu.courseFormat;
|
||||
|
||||
public interface StudyStateful {
|
||||
StudyStatus getStatus();
|
||||
void setStatus(StudyStatus status, StudyStatus oldStatus);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.jetbrains.edu.courseFormat;
|
||||
|
||||
/**
|
||||
* @see {@link AnswerPlaceholder#myStatus}
|
||||
*/
|
||||
public enum StudyStatus {
|
||||
Unchecked, Solved, Failed
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package com.jetbrains.edu.courseFormat;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.xmlb.annotations.Transient;
|
||||
import com.jetbrains.edu.StudyNames;
|
||||
import com.jetbrains.edu.courseFormat.info.LessonInfo;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Implementation of task which contains task files, tests, input file for tests
|
||||
*/
|
||||
public class Task implements StudyStateful {
|
||||
private String name;
|
||||
private int myIndex;
|
||||
public Map<String, TaskFile> taskFiles = new HashMap<String, TaskFile>();
|
||||
|
||||
private String text;
|
||||
private String testsText;
|
||||
|
||||
private Lesson myLesson;
|
||||
private List<UserTest> userTests = new ArrayList<UserTest>();
|
||||
|
||||
|
||||
/**
|
||||
* Initializes state of task file
|
||||
*
|
||||
* @param lesson lesson which task belongs to
|
||||
*/
|
||||
public void init(final Lesson lesson, boolean isRestarted) {
|
||||
myLesson = lesson;
|
||||
for (TaskFile taskFile : taskFiles.values()) {
|
||||
taskFile.init(this, isRestarted);
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void setText(@NotNull final String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return myIndex;
|
||||
}
|
||||
|
||||
public void setIndex(int index) {
|
||||
myIndex = index;
|
||||
}
|
||||
|
||||
public String getTestsText() {
|
||||
return testsText;
|
||||
}
|
||||
|
||||
public void setTestsText(@NotNull final String testsText) {
|
||||
this.testsText = testsText;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Map<String, TaskFile> getTaskFiles() {
|
||||
return taskFiles;
|
||||
}
|
||||
|
||||
@Transient
|
||||
public StudyStatus getStatus() {
|
||||
for (TaskFile taskFile : taskFiles.values()) {
|
||||
StudyStatus taskFileStatus = taskFile.getStatus();
|
||||
if (taskFileStatus == StudyStatus.Unchecked) {
|
||||
return StudyStatus.Unchecked;
|
||||
}
|
||||
if (taskFileStatus == StudyStatus.Failed) {
|
||||
return StudyStatus.Failed;
|
||||
}
|
||||
}
|
||||
return StudyStatus.Solved;
|
||||
}
|
||||
|
||||
public void setStatus(@NotNull final StudyStatus status, @NotNull final StudyStatus oldStatus) {
|
||||
LessonInfo lessonInfo = myLesson.getLessonInfo();
|
||||
if (status != oldStatus) {
|
||||
lessonInfo.update(oldStatus, -1);
|
||||
lessonInfo.update(status, +1);
|
||||
}
|
||||
for (TaskFile taskFile : taskFiles.values()) {
|
||||
taskFile.setStatus(status, oldStatus);
|
||||
}
|
||||
}
|
||||
|
||||
public List<UserTest> getUserTests() {
|
||||
return userTests;
|
||||
}
|
||||
|
||||
public void setUserTests(@NotNull final List<UserTest> userTests) {
|
||||
this.userTests = userTests;
|
||||
}
|
||||
|
||||
public boolean isTaskFile(@NotNull final String fileName) {
|
||||
return taskFiles.get(fileName) != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public TaskFile getFile(@NotNull final String fileName) {
|
||||
return taskFiles.get(fileName);
|
||||
}
|
||||
|
||||
public Lesson getLesson() {
|
||||
return myLesson;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
public VirtualFile getTaskDir(Project project) {
|
||||
String lessonDirName = StudyNames.LESSON_DIR + String.valueOf(myLesson.getIndex() + 1);
|
||||
String taskDirName = StudyNames.TASK_DIR + String.valueOf(myIndex + 1);
|
||||
VirtualFile courseDir = project.getBaseDir();
|
||||
if (courseDir != null) {
|
||||
VirtualFile lessonDir = courseDir.findChild(lessonDirName);
|
||||
if (lessonDir != null) {
|
||||
return lessonDir.findChild(taskDirName);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
package com.jetbrains.edu.courseFormat;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.LogicalPosition;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Implementation of task file which contains task windows for student to type in and
|
||||
* which is visible to student in project view
|
||||
*/
|
||||
|
||||
public class TaskFile implements StudyStateful {
|
||||
@SerializedName("placeholders")
|
||||
private List<AnswerPlaceholder> myAnswerPlaceholders = new ArrayList<AnswerPlaceholder>();
|
||||
private int myIndex = -1;
|
||||
|
||||
|
||||
public String name;
|
||||
public String text;
|
||||
private Task myTask;
|
||||
@Transient
|
||||
private AnswerPlaceholder mySelectedAnswerPlaceholder = null;
|
||||
private boolean myUserCreated = false;
|
||||
private boolean myTrackChanges = true;
|
||||
private boolean myHighlightErrors = false;
|
||||
|
||||
public void init(final Task task, boolean isRestarted) {
|
||||
myTask = task;
|
||||
for (AnswerPlaceholder answerPlaceholder : myAnswerPlaceholders) {
|
||||
answerPlaceholder.init(this, isRestarted);
|
||||
}
|
||||
Collections.sort(myAnswerPlaceholders);
|
||||
for (int i = 0; i < myAnswerPlaceholders.size(); i++) {
|
||||
myAnswerPlaceholders.get(i).setIndex(i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if all the windows in task file are marked as resolved
|
||||
*/
|
||||
@Transient
|
||||
public StudyStatus getStatus() {
|
||||
for (AnswerPlaceholder answerPlaceholder : myAnswerPlaceholders) {
|
||||
StudyStatus windowStatus = answerPlaceholder.getStatus();
|
||||
if (windowStatus == StudyStatus.Failed) {
|
||||
return StudyStatus.Failed;
|
||||
}
|
||||
if (windowStatus == StudyStatus.Unchecked) {
|
||||
return StudyStatus.Unchecked;
|
||||
}
|
||||
}
|
||||
return StudyStatus.Solved;
|
||||
}
|
||||
|
||||
public void setStatus(@NotNull final StudyStatus status, @NotNull final StudyStatus oldStatus) {
|
||||
for (AnswerPlaceholder answerPlaceholder : myAnswerPlaceholders) {
|
||||
answerPlaceholder.setStatus(status, oldStatus);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Transient
|
||||
public AnswerPlaceholder getSelectedAnswerPlaceholder() {
|
||||
return mySelectedAnswerPlaceholder;
|
||||
}
|
||||
|
||||
public void setSelectedAnswerPlaceholder(@NotNull final AnswerPlaceholder selectedAnswerPlaceholder) {
|
||||
if (selectedAnswerPlaceholder.getTaskFile() == this) {
|
||||
mySelectedAnswerPlaceholder = selectedAnswerPlaceholder;
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Window may be set as selected only in task file which it belongs to");
|
||||
}
|
||||
}
|
||||
|
||||
public List<AnswerPlaceholder> getAnswerPlaceholders() {
|
||||
return myAnswerPlaceholders;
|
||||
}
|
||||
|
||||
public void setAnswerPlaceholders(List<AnswerPlaceholder> answerPlaceholders) {
|
||||
this.myAnswerPlaceholders = answerPlaceholders;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return myIndex;
|
||||
}
|
||||
|
||||
public void setIndex(int index) {
|
||||
myIndex = index;
|
||||
}
|
||||
|
||||
public Task getTask() {
|
||||
return myTask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pos position in editor
|
||||
* @return task window located in specified position or null if there is no task window in this position
|
||||
*/
|
||||
@Nullable
|
||||
public AnswerPlaceholder getAnswerPlaceholder(@NotNull final Document document, @NotNull final LogicalPosition pos) {
|
||||
int line = pos.line;
|
||||
if (line >= document.getLineCount()) {
|
||||
return null;
|
||||
}
|
||||
int column = pos.column;
|
||||
int offset = document.getLineStartOffset(line) + column;
|
||||
for (AnswerPlaceholder tw : myAnswerPlaceholders) {
|
||||
if (tw.getLine() <= line) {
|
||||
int twStartOffset = tw.getRealStartOffset(document);
|
||||
final int length = tw.getLength() > 0 ? tw.getLength() : 0;
|
||||
int twEndOffset = twStartOffset + length;
|
||||
if (twStartOffset <= offset && offset <= twEndOffset) {
|
||||
return tw;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static void copy(@NotNull final TaskFile source, @NotNull final TaskFile target) {
|
||||
List<AnswerPlaceholder> sourceAnswerPlaceholders = source.getAnswerPlaceholders();
|
||||
List<AnswerPlaceholder> windowsCopy = new ArrayList<AnswerPlaceholder>(sourceAnswerPlaceholders.size());
|
||||
for (AnswerPlaceholder answerPlaceholder : sourceAnswerPlaceholders) {
|
||||
AnswerPlaceholder answerPlaceholderCopy = new AnswerPlaceholder();
|
||||
answerPlaceholderCopy.setLine(answerPlaceholder.getLine());
|
||||
answerPlaceholderCopy.setStart(answerPlaceholder.getStart());
|
||||
answerPlaceholderCopy.setLength(answerPlaceholder.getLength());
|
||||
answerPlaceholderCopy.setPossibleAnswer(answerPlaceholder.getPossibleAnswer());
|
||||
answerPlaceholderCopy.setIndex(answerPlaceholder.getIndex());
|
||||
windowsCopy.add(answerPlaceholderCopy);
|
||||
}
|
||||
target.setAnswerPlaceholders(windowsCopy);
|
||||
}
|
||||
|
||||
|
||||
public void setUserCreated(boolean userCreated) {
|
||||
myUserCreated = userCreated;
|
||||
}
|
||||
|
||||
public boolean isUserCreated() {
|
||||
return myUserCreated;
|
||||
}
|
||||
|
||||
public boolean hasFailedTaskWindows() {
|
||||
return myAnswerPlaceholders.size() > 0 && getStatus() == StudyStatus.Failed;
|
||||
}
|
||||
|
||||
public boolean isTrackChanges() {
|
||||
return myTrackChanges;
|
||||
}
|
||||
|
||||
public void setTrackChanges(boolean trackChanges) {
|
||||
myTrackChanges = trackChanges;
|
||||
}
|
||||
|
||||
public boolean isHighlightErrors() {
|
||||
return myHighlightErrors;
|
||||
}
|
||||
|
||||
public void setHighlightErrors(boolean highlightErrors) {
|
||||
myHighlightErrors = highlightErrors;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.jetbrains.edu.courseFormat;
|
||||
|
||||
public class UserTest {
|
||||
private String input;
|
||||
private String output;
|
||||
private StringBuilder myInputBuffer = new StringBuilder();
|
||||
private StringBuilder myOutputBuffer = new StringBuilder();
|
||||
private boolean myEditable = false;
|
||||
|
||||
public String getInput() {
|
||||
return input;
|
||||
}
|
||||
|
||||
public void setInput(String input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
public String getOutput() {
|
||||
return output;
|
||||
}
|
||||
|
||||
public void setOutput(String output) {
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
public StringBuilder getInputBuffer() {
|
||||
return myInputBuffer;
|
||||
}
|
||||
|
||||
public StringBuilder getOutputBuffer() {
|
||||
return myOutputBuffer;
|
||||
}
|
||||
|
||||
public boolean isEditable() {
|
||||
return myEditable;
|
||||
}
|
||||
|
||||
public void setEditable(boolean editable) {
|
||||
myEditable = editable;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.jetbrains.edu.courseFormat.info;
|
||||
|
||||
import com.jetbrains.edu.courseFormat.StudyStatus;
|
||||
|
||||
/**
|
||||
* Implementation of class which contains information about student progress in current lesson
|
||||
*/
|
||||
public class LessonInfo {
|
||||
private int myTaskNum;
|
||||
private int myTaskFailed;
|
||||
private int myTaskSolved;
|
||||
private int myTaskUnchecked;
|
||||
|
||||
public int getTaskNum() {
|
||||
return myTaskNum;
|
||||
}
|
||||
|
||||
public void setTaskNum(int taskNum) {
|
||||
myTaskNum = taskNum;
|
||||
}
|
||||
|
||||
public int getTaskFailed() {
|
||||
return myTaskFailed;
|
||||
}
|
||||
|
||||
public void setTaskFailed(int taskFailed) {
|
||||
myTaskFailed = taskFailed;
|
||||
}
|
||||
|
||||
public int getTaskSolved() {
|
||||
return myTaskSolved;
|
||||
}
|
||||
|
||||
public void setTaskSolved(int taskSolved) {
|
||||
myTaskSolved = taskSolved;
|
||||
}
|
||||
|
||||
public int getTaskUnchecked() {
|
||||
return myTaskUnchecked;
|
||||
}
|
||||
|
||||
public void setTaskUnchecked(int taskUnchecked) {
|
||||
myTaskUnchecked = taskUnchecked;
|
||||
}
|
||||
|
||||
public void update(StudyStatus status, int delta) {
|
||||
switch (status) {
|
||||
case Solved: {
|
||||
myTaskSolved += delta;
|
||||
break;
|
||||
}
|
||||
case Failed: {
|
||||
myTaskFailed += delta;
|
||||
break;
|
||||
}
|
||||
case Unchecked: {
|
||||
myTaskUnchecked += delta;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user