diff --git a/python/educational-core/course-creator/resources/META-INF/plugin.xml b/python/educational-core/course-creator/resources/META-INF/plugin.xml
index 131d9f5b46d8..421b23fef48e 100644
--- a/python/educational-core/course-creator/resources/META-INF/plugin.xml
+++ b/python/educational-core/course-creator/resources/META-INF/plugin.xml
@@ -19,18 +19,17 @@
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
com.jetbrains.edu.coursecreator.CCProjectComponent
@@ -46,49 +45,40 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCEditorFactoryListener.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCEditorFactoryListener.java
deleted file mode 100644
index 0ecea377388c..000000000000
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCEditorFactoryListener.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package com.jetbrains.edu.coursecreator;
-
-import com.intellij.openapi.editor.Document;
-import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.editor.actionSystem.EditorActionManager;
-import com.intellij.openapi.editor.colors.EditorColors;
-import com.intellij.openapi.editor.event.EditorFactoryEvent;
-import com.intellij.openapi.editor.event.EditorFactoryListener;
-import com.intellij.openapi.fileEditor.FileDocumentManager;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.jetbrains.edu.learning.core.EduAnswerPlaceholderDeleteHandler;
-import com.jetbrains.edu.learning.core.EduAnswerPlaceholderPainter;
-import com.jetbrains.edu.learning.core.EduDocumentListener;
-import com.jetbrains.edu.learning.core.EduNames;
-import com.jetbrains.edu.learning.courseFormat.Course;
-import com.jetbrains.edu.learning.courseFormat.TaskFile;
-import org.jetbrains.annotations.NotNull;
-
-public class CCEditorFactoryListener implements EditorFactoryListener {
- @Override
- public void editorCreated(@NotNull EditorFactoryEvent event) {
- Editor editor = event.getEditor();
- Project project = editor.getProject();
- if (project == null) {
- return;
- }
- VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(editor.getDocument());
- if (virtualFile == null) {
- return;
- }
- final CCProjectService service = CCProjectService.getInstance(project);
- Course course = service.getCourse();
- if (course == null) {
- return;
- }
- final VirtualFile taskDir = virtualFile.getParent();
- if (taskDir == null || !taskDir.getName().contains(EduNames.TASK)) {
- return;
- }
- final VirtualFile lessonDir = taskDir.getParent();
- if (lessonDir == null) return;
- final TaskFile taskFile = service.getTaskFile(virtualFile);
- if (taskFile == null) {
- return;
- }
- EduDocumentListener listener = new EduDocumentListener(taskFile, true, true);
- CCProjectService.addDocumentListener(editor.getDocument(), listener);
- editor.getDocument().addDocumentListener(listener);
- EditorActionManager.getInstance()
- .setReadonlyFragmentModificationHandler(editor.getDocument(), new EduAnswerPlaceholderDeleteHandler(editor));
- service.drawAnswerPlaceholders(virtualFile, editor);
- editor.getColorsScheme().setColor(EditorColors.READONLY_FRAGMENT_BACKGROUND_COLOR, null);
- EduAnswerPlaceholderPainter.createGuardedBlocks(editor, taskFile, false);
- }
-
- @Override
- public void editorReleased(@NotNull EditorFactoryEvent event) {
- Editor editor = event.getEditor();
- Document document = editor.getDocument();
- EduDocumentListener listener = CCProjectService.getListener(document);
- if (listener != null) {
- document.removeDocumentListener(listener);
- CCProjectService.removeListener(document);
- }
- editor.getMarkupModel().removeAllHighlighters();
- editor.getSelectionModel().removeSelection();
- }
-}
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCLanguageManager.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCLanguageManager.java
index 5ab5f5591ed8..b6c8fd4ecf53 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCLanguageManager.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCLanguageManager.java
@@ -3,6 +3,7 @@ package com.jetbrains.edu.coursecreator;
import com.intellij.ide.fileTemplates.FileTemplate;
import com.intellij.lang.LanguageExtension;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -21,4 +22,8 @@ public interface CCLanguageManager {
FileTemplate getTestsTemplate(@NotNull final Project project);
boolean doNotPackFile(File pathname);
+
+ default boolean isTestFile(VirtualFile file) {
+ return false;
+ }
}
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectComponent.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectComponent.java
index e5871848ecf1..b5a23ba917ed 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectComponent.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectComponent.java
@@ -1,33 +1,40 @@
package com.jetbrains.edu.coursecreator;
-import com.intellij.openapi.components.ProjectComponent;
-import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.editor.EditorFactory;
-import com.intellij.openapi.editor.event.EditorFactoryEvent;
-import com.intellij.openapi.editor.impl.EditorFactoryImpl;
-import com.intellij.openapi.fileEditor.FileEditor;
-import com.intellij.openapi.fileEditor.FileEditorManager;
-import com.intellij.openapi.fileEditor.impl.text.PsiAwareTextEditorImpl;
+import com.intellij.openapi.application.PathManager;
+import com.intellij.openapi.components.AbstractProjectComponent;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.project.ProjectManager;
-import com.intellij.openapi.startup.StartupManager;
-import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
+import com.jetbrains.edu.learning.StudyProjectComponent;
+import com.jetbrains.edu.learning.StudyTaskManager;
import com.jetbrains.edu.learning.courseFormat.Course;
import org.jetbrains.annotations.NotNull;
-public class CCProjectComponent implements ProjectComponent {
- private final Project myProject;
- private CCFileDeletedListener myListener;
+import java.io.File;
- public CCProjectComponent(Project project) {
+public class CCProjectComponent extends AbstractProjectComponent {
+ private final CCVirtualFileListener myTaskFileLifeListener = new CCVirtualFileListener();
+ private final Project myProject;
+
+ protected CCProjectComponent(Project project) {
+ super(project);
myProject = project;
}
public void initComponent() {
+ VirtualFileManager.getInstance().addVirtualFileListener(myTaskFileLifeListener);
}
- public void disposeComponent() {
+ public void migrateIfNeeded() {
+ Course studyCourse = StudyTaskManager.getInstance(myProject).getCourse();
+ Course course = CCProjectService.getInstance(myProject).getCourse();
+ if (studyCourse == null && course != null) {
+ course.setCourseMode(CCUtils.COURSE_MODE);
+ File coursesDir = new File(PathManager.getConfigPath(), "courses");
+ File courseDir = new File(coursesDir, course.getName() + "-" + myProject.getName());
+ course.setCourseDirectory(courseDir.getPath());
+ StudyTaskManager.getInstance(myProject).setCourse(course);
+ StudyProjectComponent.getInstance(myProject).registerStudyToolWindow(course);
+ }
}
@NotNull
@@ -36,36 +43,11 @@ public class CCProjectComponent implements ProjectComponent {
}
public void projectOpened() {
- StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new Runnable() {
- @Override
- public void run() {
- final Course course = CCProjectService.getInstance(myProject).getCourse();
- if (course != null) {
- course.initCourse(true);
- myListener = new CCFileDeletedListener(myProject);
- VirtualFileManager.getInstance().addVirtualFileListener(myListener);
- final CCEditorFactoryListener editorFactoryListener = new CCEditorFactoryListener();
- EditorFactory.getInstance().addEditorFactoryListener(editorFactoryListener, myProject);
- VirtualFile[] files = FileEditorManager.getInstance(myProject).getOpenFiles();
- for (VirtualFile file : files) {
- if (CCProjectService.getInstance(myProject).isTaskFile(file)) {
- FileEditorManager.getInstance(myProject).closeFile(file);
- continue;
- }
- FileEditor fileEditor = FileEditorManager.getInstance(myProject).getSelectedEditor(file);
- if (fileEditor instanceof PsiAwareTextEditorImpl) {
- Editor editor = ((PsiAwareTextEditorImpl)fileEditor).getEditor();
- editorFactoryListener.editorCreated(new EditorFactoryEvent(new EditorFactoryImpl(ProjectManager.getInstance()), editor));
- }
- }
- }
- }
- });
+ migrateIfNeeded();
+ VirtualFileManager.getInstance().addVirtualFileListener(myTaskFileLifeListener);
}
public void projectClosed() {
- if (myListener != null) {
- VirtualFileManager.getInstance().removeVirtualFileListener(myListener);
- }
+ VirtualFileManager.getInstance().removeVirtualFileListener(myTaskFileLifeListener);
}
}
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectService.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectService.java
index ba9886692671..2ff6f8051033 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectService.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectService.java
@@ -15,140 +15,24 @@
*/
package com.jetbrains.edu.coursecreator;
-import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
-import com.intellij.openapi.editor.Document;
-import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.ui.JBColor;
import com.intellij.util.xmlb.XmlSerializerUtil;
-import com.jetbrains.edu.learning.core.EduAnswerPlaceholderPainter;
-import com.jetbrains.edu.learning.core.EduDocumentListener;
-import com.jetbrains.edu.learning.core.EduNames;
-import com.jetbrains.edu.learning.core.EduUtils;
-import com.jetbrains.edu.learning.courseFormat.*;
+import com.jetbrains.edu.learning.courseFormat.Course;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
@State(name = "CCProjectService", storages = @Storage("course_service.xml"))
public class CCProjectService implements PersistentStateComponent {
private Course myCourse;
- private static final Map myDocumentListeners = new HashMap();
-
- @Nullable
- public TaskFile getTaskFile(@NotNull final VirtualFile virtualFile) {
- VirtualFile taskDir = virtualFile.getParent();
- if (taskDir == null) {
- return null;
- }
- String taskDirName = taskDir.getName();
- if (!taskDirName.contains(EduNames.TASK)) {
- return null;
- }
- VirtualFile lessonDir = taskDir.getParent();
- if (lessonDir == null) {
- return null;
- }
- String lessonDirName = lessonDir.getName();
- if (!lessonDirName.contains(EduNames.LESSON)) {
- return null;
- }
- Lesson lesson = myCourse.getLesson(lessonDirName);
- if (lesson == null) {
- return null;
- }
- Task task = lesson.getTask(taskDir.getName());
- if (task == null) {
- return null;
- }
- return task.getTaskFile(virtualFile.getName());
- }
-
- public void drawAnswerPlaceholders(@NotNull final VirtualFile virtualFile, @NotNull final Editor editor) {
- TaskFile taskFile = getTaskFile(virtualFile);
- if (taskFile == null) {
- return;
- }
- List answerPlaceholders = taskFile.getAnswerPlaceholders();
- for (AnswerPlaceholder answerPlaceholder : answerPlaceholders) {
- EduAnswerPlaceholderPainter.drawAnswerPlaceholder(editor, answerPlaceholder, false, JBColor.BLUE);
- }
- }
-
- public static void addDocumentListener(Document document, EduDocumentListener listener) {
- myDocumentListeners.put(document, listener);
- }
-
- public static EduDocumentListener getListener(Document document) {
- return myDocumentListeners.get(document);
- }
-
- public static void removeListener(Document document) {
- myDocumentListeners.remove(document);
- }
-
- @Nullable
- public Task getTask(VirtualFile file) {
- if (myCourse == null || file == null) {
- return null;
- }
- VirtualFile taskDir = file.getParent();
- if (taskDir != null) {
- String taskDirName = taskDir.getName();
- if (taskDirName.contains(EduNames.TASK)) {
- VirtualFile lessonDir = taskDir.getParent();
- if (lessonDir != null) {
- String lessonDirName = lessonDir.getName();
- int lessonIndex = EduUtils.getIndex(lessonDirName, EduNames.LESSON);
- List lessons = myCourse.getLessons();
- if (!EduUtils.indexIsValid(lessonIndex, lessons)) {
- return null;
- }
- Lesson lesson = lessons.get(lessonIndex);
- int taskIndex = EduUtils.getIndex(taskDirName, EduNames.TASK);
- List tasks = lesson.getTaskList();
- if (!EduUtils.indexIsValid(taskIndex, tasks)) {
- return null;
- }
- return tasks.get(taskIndex);
- }
- }
- }
- return null;
- }
-
- public boolean isTaskFile(VirtualFile file) {
- Task task = getTask(file);
- return task != null && task.isTaskFile(file.getName());
- }
-
- public static boolean setCCActionAvailable(@NotNull AnActionEvent e) {
- final Project project = e.getProject();
- if (project == null) {
- return false;
- }
- if (getInstance(project).getCourse() == null) {
- EduUtils.enableAction(e, false);
- return false;
- }
- EduUtils.enableAction(e, true);
- return true;
- }
-
public Course getCourse() {
return myCourse;
}
- public void setCourse(@NotNull final Course course) {
+ public void setCourse(Course course) {
myCourse = course;
}
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCRefactoringElementListenerProvider.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCRefactoringElementListenerProvider.java
index ed9b404e04a5..7dbd894d8980 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCRefactoringElementListenerProvider.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCRefactoringElementListenerProvider.java
@@ -16,24 +16,30 @@
package com.jetbrains.edu.coursecreator;
import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.refactoring.listeners.RefactoringElementAdapter;
import com.intellij.refactoring.listeners.RefactoringElementListener;
import com.intellij.refactoring.listeners.RefactoringElementListenerProvider;
+import com.jetbrains.edu.learning.StudyTaskManager;
+import com.jetbrains.edu.learning.StudyUtils;
import com.jetbrains.edu.learning.core.EduNames;
import com.jetbrains.edu.learning.courseFormat.Course;
import com.jetbrains.edu.learning.courseFormat.Lesson;
import com.jetbrains.edu.learning.courseFormat.Task;
import com.jetbrains.edu.learning.courseFormat.TaskFile;
-import com.jetbrains.edu.coursecreator.actions.CCRunTestsAction;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.io.IOException;
import java.util.Map;
public class CCRefactoringElementListenerProvider implements RefactoringElementListenerProvider {
+ private static final Logger LOG = Logger.getInstance(CCRefactoringElementListenerProvider.class);
+
@Nullable
@Override
public RefactoringElementListener getListener(PsiElement element) {
@@ -62,8 +68,7 @@ public class CCRefactoringElementListenerProvider implements RefactoringElementL
private static void tryToRenameTaskFile(PsiFile file, String oldName) {
final PsiDirectory taskDir = file.getContainingDirectory();
- final CCProjectService service = CCProjectService.getInstance(file.getProject());
- Course course = service.getCourse();
+ Course course = StudyTaskManager.getInstance(file.getProject()).getCourse();
if (course == null) {
return;
}
@@ -82,16 +87,29 @@ public class CCRefactoringElementListenerProvider implements RefactoringElementL
if (task == null) {
return;
}
+ Map taskFiles = task.getTaskFiles();
+ TaskFile taskFile = task.getTaskFile(oldName);
+ if (taskFile == null) {
+ return;
+ }
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
- CCRunTestsAction.clearTestEnvironment(taskDir.getVirtualFile(), taskDir.getProject());
+ VirtualFile patternFile = StudyUtils.getPatternFile(taskFile, oldName);
+ if (patternFile != null) {
+ try {
+ patternFile.delete(CCRefactoringElementListenerProvider.class);
+ }
+ catch (IOException e) {
+ LOG.info(e);
+ }
+ }
}
});
- Map taskFiles = task.getTaskFiles();
- TaskFile taskFile = task.getTaskFile(oldName);
+
taskFiles.remove(oldName);
taskFiles.put(file.getName(), taskFile);
+ CCUtils.createResourceFile(file.getVirtualFile(), course, taskDir.getVirtualFile());
}
@Override
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCStudyActionListener.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCStudyActionListener.java
new file mode 100644
index 000000000000..945026bd1ff9
--- /dev/null
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCStudyActionListener.java
@@ -0,0 +1,36 @@
+package com.jetbrains.edu.coursecreator;
+
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.edu.learning.StudyActionListener;
+import com.jetbrains.edu.learning.StudyUtils;
+import com.jetbrains.edu.learning.courseFormat.Task;
+import com.jetbrains.edu.learning.courseFormat.TaskFile;
+
+public class CCStudyActionListener implements StudyActionListener {
+ @Override
+ public void beforeCheck(AnActionEvent event) {
+ Project project = event.getProject();
+ if (project == null) {
+ return;
+ }
+ VirtualFile virtualFile = CommonDataKeys.VIRTUAL_FILE.getData(event.getDataContext());
+ if (virtualFile == null) {
+ return;
+ }
+
+ TaskFile taskFile = StudyUtils.getTaskFile(project, virtualFile);
+ if (taskFile == null) {
+ return;
+ }
+
+ Task task = taskFile.getTask();
+ VirtualFile taskDir = StudyUtils.getTaskDir(virtualFile);
+ if (taskDir == null) {
+ return;
+ }
+ CCUtils.createResources(project, task, taskDir);
+ }
+}
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCStudyActionsProvider.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCStudyActionsProvider.java
new file mode 100644
index 000000000000..7ccdc075ebe3
--- /dev/null
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCStudyActionsProvider.java
@@ -0,0 +1,12 @@
+package com.jetbrains.edu.coursecreator;
+
+import com.intellij.openapi.actionSystem.AnAction;
+import com.jetbrains.edu.coursecreator.actions.CCEditTaskTextAction;
+import com.jetbrains.edu.learning.StudyActionsProvider;
+
+public class CCStudyActionsProvider implements StudyActionsProvider{
+ @Override
+ public AnAction[] getActions() {
+ return new AnAction[]{new CCEditTaskTextAction()};
+ }
+}
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java
index 65131d0b36ae..f6dd7417a32d 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java
@@ -6,6 +6,8 @@ import com.intellij.ide.projectView.actions.MarkRootActionBase;
import com.intellij.lang.Language;
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.module.Module;
import com.intellij.openapi.project.DumbModePermission;
import com.intellij.openapi.project.DumbService;
@@ -14,27 +16,27 @@ import com.intellij.openapi.roots.ContentEntry;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.util.Ref;
+import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileEvent;
import com.intellij.psi.PsiDirectory;
+import com.intellij.util.DocumentUtil;
import com.intellij.util.Function;
+import com.jetbrains.edu.learning.StudyTaskManager;
+import com.jetbrains.edu.learning.StudyUtils;
import com.jetbrains.edu.learning.core.EduUtils;
-import com.jetbrains.edu.learning.courseFormat.Course;
-import com.jetbrains.edu.learning.courseFormat.StudyItem;
+import com.jetbrains.edu.learning.courseFormat.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.io.File;
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
+import java.util.*;
public class CCUtils {
private static final Logger LOG = Logger.getInstance(CCUtils.class);
public static final String GENERATED_FILES_FOLDER = ".coursecreator";
- public static final String TESTS = "coursecreatortests";
- public static final String RESOURCES = "coursecreatorresources";
+ public static final String COURSE_MODE = "Course Creator";
@Nullable
public static CCLanguageManager getStudyLanguageManager(@NotNull final Course course) {
@@ -100,9 +102,9 @@ public class CCUtils {
if (sourceDirectory == null) {
return false;
}
- CCProjectService service = CCProjectService.getInstance(sourceDirectory.getProject());
- Course course = service.getCourse();
- if (course != null && course.getLesson(sourceDirectory.getName()) != null) {
+ Project project = sourceDirectory.getProject();
+ Course course = StudyTaskManager.getInstance(project).getCourse();
+ if (course != null && isCourseCreator(project) && course.getLesson(sourceDirectory.getName()) != null) {
return true;
}
return false;
@@ -169,4 +171,74 @@ public class CCUtils {
});
return folder.get();
}
+
+ public static boolean isCourseCreator(@NotNull Project project) {
+ Course course = StudyTaskManager.getInstance(project).getCourse();
+ if (course == null) {
+ return false;
+ }
+
+ return COURSE_MODE.equals(course.getCourseMode());
+ }
+
+ public static boolean isTestsFile(@NotNull Project project, @NotNull VirtualFile file) {
+ Course course = StudyTaskManager.getInstance(project).getCourse();
+ if (course == null) {
+ return false;
+ }
+ CCLanguageManager manager = getStudyLanguageManager(course);
+ if (manager == null) {
+ return false;
+ }
+ return manager.isTestFile(file);
+ }
+
+ public static void createResourceFile(VirtualFile createdFile, Course course, VirtualFile taskVF) {
+ VirtualFile lessonVF = taskVF.getParent();
+ if (lessonVF == null) {
+ return;
+ }
+
+ String taskResourcesPath = FileUtil.join(course.getCourseDirectory(), lessonVF.getName(), taskVF.getName());
+ File taskResourceFile = new File(taskResourcesPath);
+ if (!taskResourceFile.exists()) {
+ if (!taskResourceFile.mkdirs()) {
+ LOG.info("Failed to create resources for task " + taskResourcesPath);
+ }
+ }
+ try {
+ File toFile = new File(taskResourceFile, createdFile.getName());
+ FileUtil.copy(new File(createdFile.getPath()), toFile);
+ }
+ catch (IOException e) {
+ LOG.info("Failed to copy created task file to resources " + createdFile.getPath());
+ }
+ }
+
+
+ public static void createResources(Project project, Task task, VirtualFile taskDir) {
+ Map files = task.getTaskFiles();
+ for (Map.Entry entry : files.entrySet()) {
+ String name = entry.getKey();
+ VirtualFile child = taskDir.findChild(name);
+ if (child == null) {
+ continue;
+ }
+ Document patternDocument = StudyUtils.getPatternDocument(entry.getValue(), name);
+ Document document = FileDocumentManager.getInstance().getDocument(child);
+ if (document == null || patternDocument == null) {
+ return;
+ }
+ DocumentUtil.writeInRunUndoTransparentAction(() -> {
+ patternDocument.replaceString(0, patternDocument.getTextLength(), document.getCharsSequence());
+ FileDocumentManager.getInstance().saveDocument(patternDocument);
+ });
+ TaskFile target = new TaskFile();
+ TaskFile.copy(entry.getValue(), target);
+ for (AnswerPlaceholder placeholder : target.getAnswerPlaceholders()) {
+ placeholder.setUseLength(false);
+ }
+ EduUtils.createStudentDocument(project, target, child, patternDocument);
+ }
+ }
}
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCFileDeletedListener.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java
similarity index 54%
rename from python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCFileDeletedListener.java
rename to python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java
index 1d840f0c5943..3c3be598ca7f 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCFileDeletedListener.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java
@@ -1,54 +1,95 @@
package com.jetbrains.edu.coursecreator;
+import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ProjectUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileAdapter;
import com.intellij.openapi.vfs.VirtualFileEvent;
import com.intellij.util.Function;
+import com.jetbrains.edu.learning.StudyTaskManager;
+import com.jetbrains.edu.learning.StudyUtils;
import com.jetbrains.edu.learning.core.EduNames;
import com.jetbrains.edu.learning.courseFormat.*;
import org.jetbrains.annotations.NotNull;
-class CCFileDeletedListener extends VirtualFileAdapter {
+public class CCVirtualFileListener extends VirtualFileAdapter {
- private final Project myProject;
+ private static final Logger LOG = Logger.getInstance(CCVirtualFileListener.class);
- CCFileDeletedListener(@NotNull final Project project) {
- myProject = project;
+ @Override
+ public void fileCreated(@NotNull VirtualFileEvent event) {
+ VirtualFile createdFile = event.getFile();
+ Project project = ProjectUtil.guessProjectForFile(createdFile);
+ if (project == null) {
+ return;
+ }
+ Course course = StudyTaskManager.getInstance(project).getCourse();
+ if (course == null || !CCUtils.isCourseCreator(project)) {
+ return;
+ }
+ TaskFile taskFile = StudyUtils.getTaskFile(project, createdFile);
+ if (taskFile != null) {
+ return;
+ }
+
+ String name = createdFile.getName();
+ if (CCUtils.isTestsFile(project, createdFile)
+ || EduNames.TASK_HTML.equals(name)
+ || name.contains(EduNames.WINDOW_POSTFIX)
+ || name.contains(EduNames.WINDOWS_POSTFIX)
+ || name.contains(EduNames.ANSWERS_POSTFIX)) {
+ return;
+ }
+
+ VirtualFile taskVF = createdFile.getParent();
+ if (taskVF == null) {
+ return;
+ }
+ Task task = StudyUtils.getTask(project, taskVF);
+ if (task == null) {
+ return;
+ }
+
+ CCUtils.createResourceFile(createdFile, course, taskVF);
+
+ task.addTaskFile(name, 1);
}
@Override
public void fileDeleted(@NotNull VirtualFileEvent event) {
- if (myProject.isDisposed() || !myProject.isOpen()) {
- return;
- }
VirtualFile removedFile = event.getFile();
if (removedFile.getPath().contains(CCUtils.GENERATED_FILES_FOLDER)) {
return;
}
- final TaskFile taskFile = CCProjectService.getInstance(myProject).getTaskFile(removedFile);
+
+ Project project = ProjectUtil.guessProjectForFile(removedFile);
+ if (project == null) {
+ return;
+ }
+ Course course = StudyTaskManager.getInstance(project).getCourse();
+ if (course == null) {
+ return;
+ }
+ final TaskFile taskFile = StudyUtils.getTaskFile(project, removedFile);
if (taskFile != null) {
deleteTaskFile(removedFile, taskFile);
return;
}
- Course course = CCProjectService.getInstance(myProject).getCourse();
- if (course == null) {
- return;
- }
if (removedFile.getName().contains(EduNames.TASK)) {
- deleteTask(course, removedFile, myProject);
+ deleteTask(course, removedFile);
}
if (removedFile.getName().contains(EduNames.LESSON)) {
- deleteLesson(course, removedFile);
+ deleteLesson(course, removedFile, project);
}
}
- private void deleteLesson(@NotNull final Course course, @NotNull final VirtualFile removedLessonFile) {
+ private static void deleteLesson(@NotNull final Course course, @NotNull final VirtualFile removedLessonFile, Project project) {
Lesson removedLesson = course.getLesson(removedLessonFile.getName());
if (removedLesson == null) {
return;
}
- VirtualFile courseDir = myProject.getBaseDir();
+ VirtualFile courseDir = project.getBaseDir();
CCUtils.updateHigherElements(courseDir.getChildren(), new Function() {
@Override
public StudyItem fun(VirtualFile file) {
@@ -58,7 +99,7 @@ class CCFileDeletedListener extends VirtualFileAdapter {
course.getLessons().remove(removedLesson);
}
- private static void deleteTask(@NotNull final Course course, @NotNull final VirtualFile removedTask, @NotNull final Project project) {
+ private static void deleteTask(@NotNull final Course course, @NotNull final VirtualFile removedTask) {
VirtualFile lessonDir = removedTask.getParent();
if (lessonDir == null || !lessonDir.getName().contains(EduNames.LESSON)) {
return;
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAnswerPlaceholder.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAnswerPlaceholder.java
index 791d7fb0efae..5eae370909ee 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAnswerPlaceholder.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAnswerPlaceholder.java
@@ -1,32 +1,32 @@
package com.jetbrains.edu.coursecreator.actions;
import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.Presentation;
-import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.SelectionModel;
-import com.intellij.openapi.project.DumbAwareAction;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
-import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.ui.JBColor;
-import com.jetbrains.edu.learning.core.EduAnswerPlaceholderPainter;
-import com.jetbrains.edu.coursecreator.CCProjectService;
+import com.intellij.util.DocumentUtil;
import com.jetbrains.edu.coursecreator.ui.CCCreateAnswerPlaceholderDialog;
-import com.jetbrains.edu.learning.courseFormat.*;
+import com.jetbrains.edu.learning.StudyUtils;
+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.TaskFile;
import org.jetbrains.annotations.NotNull;
import java.util.List;
-public class CCAddAnswerPlaceholder extends DumbAwareAction {
- private static final Logger LOG = Logger.getInstance(CCAddAnswerPlaceholder.class);
+public class CCAddAnswerPlaceholder extends CCAnswerPlaceholderAction {
public CCAddAnswerPlaceholder() {
- super("Add Answer Placeholder", "Add answer placeholder", null);
+ super("Add/Delete Answer Placeholder", "Add/Delete answer placeholder", null);
}
@@ -43,114 +43,131 @@ public class CCAddAnswerPlaceholder extends DumbAwareAction {
return false;
}
- @Override
- public void actionPerformed(@NotNull AnActionEvent e) {
- final Project project = e.getData(CommonDataKeys.PROJECT);
- if (project == null) {
+ private static void addPlaceholder(@NotNull CCState state) {
+ Editor editor = state.getEditor();
+ Project project = state.getProject();
+ PsiFile file = state.getFile();
+
+ final Document document = PsiDocumentManager.getInstance(project).getDocument(file);
+ if (document == null) {
return;
}
- final PsiFile file = CommonDataKeys.PSI_FILE.getData(e.getDataContext());
- if (file == null) return;
- final Editor editor = CommonDataKeys.EDITOR.getData(e.getDataContext());
- if (editor == null) return;
+
final SelectionModel model = editor.getSelectionModel();
- final Document document = PsiDocumentManager.getInstance(project).getDocument(file);
- if (document == null) return;
final int start = model.getSelectionStart();
- final int end = model.getSelectionEnd();
final int lineNumber = document.getLineNumber(start);
int realStart = start - document.getLineStartOffset(lineNumber);
-
- final CCProjectService service = CCProjectService.getInstance(project);
- final PsiDirectory taskDir = file.getContainingDirectory();
- final PsiDirectory lessonDir = taskDir.getParent();
- if (lessonDir == null) return;
-
- final TaskFile taskFile = service.getTaskFile(file.getVirtualFile());
- if (taskFile == null) {
- return;
- }
- if (arePlaceholdersIntersect(taskFile, document, start, end)) {
- return;
- }
final AnswerPlaceholder answerPlaceholder = new AnswerPlaceholder();
answerPlaceholder.setLine(lineNumber);
answerPlaceholder.setStart(realStart);
- answerPlaceholder.setPossibleAnswer(model.getSelectedText());
+ answerPlaceholder.setUseLength(false);
+ String selectedText = model.getSelectedText();
+ answerPlaceholder.setPossibleAnswer(selectedText);
- CCCreateAnswerPlaceholderDialog dlg = new CCCreateAnswerPlaceholderDialog(project, answerPlaceholder
- );
+ CCCreateAnswerPlaceholderDialog dlg = new CCCreateAnswerPlaceholderDialog(project, answerPlaceholder);
dlg.show();
if (dlg.getExitCode() != DialogWrapper.OK_EXIT_CODE) {
return;
}
+
+ TaskFile taskFile = state.getTaskFile();
int index = taskFile.getAnswerPlaceholders().size() + 1;
answerPlaceholder.setIndex(index);
taskFile.addAnswerPlaceholder(answerPlaceholder);
+ answerPlaceholder.setTaskFile(taskFile);
taskFile.sortAnswerPlaceholders();
- EduAnswerPlaceholderPainter.drawAnswerPlaceholder(editor, answerPlaceholder, false, JBColor.BLUE);
- EduAnswerPlaceholderPainter.createGuardedBlocks(editor, answerPlaceholder, false);
+
+
+ computeInitialState(project, file, taskFile, document);
+
+ EduAnswerPlaceholderPainter.drawAnswerPlaceholder(editor, answerPlaceholder, JBColor.BLUE);
+ EduAnswerPlaceholderPainter.createGuardedBlocks(editor, answerPlaceholder);
+ }
+
+ private static void computeInitialState(Project project, PsiFile file, TaskFile taskFile, Document document) {
+ Document patternDocument = StudyUtils.getPatternDocument(taskFile, file.getName());
+ if (patternDocument == null) {
+ return;
+ }
+ DocumentUtil.writeInRunUndoTransparentAction(() -> {
+ patternDocument.replaceString(0, patternDocument.getTextLength(), document.getCharsSequence());
+ FileDocumentManager.getInstance().saveDocument(patternDocument);
+ });
+ TaskFile target = new TaskFile();
+ TaskFile.copy(taskFile, target);
+ List placeholders = target.getAnswerPlaceholders();
+ for (AnswerPlaceholder placeholder : placeholders) {
+ placeholder.setUseLength(false);
+ }
+ EduUtils.createStudentDocument(project, target, file.getVirtualFile(), patternDocument);
+
+ for (int i = 0; i < placeholders.size(); i++) {
+ AnswerPlaceholder fromPlaceholder = placeholders.get(i);
+ taskFile.getAnswerPlaceholders().get(i).setInitialState(fromPlaceholder);
+ }
+ }
+
+ @Override
+ protected void performAnswerPlaceholderAction(@NotNull CCState state) {
+ if (canAddPlaceholder(state)) {
+ addPlaceholder(state);
+ return;
+ }
+ if (canDeletePlaceholder(state)) {
+ deletePlaceholder(state);
+ }
+ }
+
+ private static void deletePlaceholder(@NotNull CCState state) {
+ Project project = state.getProject();
+ PsiFile psiFile = state.getFile();
+ final Document document = PsiDocumentManager.getInstance(project).getDocument(psiFile);
+ if (document == null) return;
+ TaskFile taskFile = state.getTaskFile();
+ AnswerPlaceholder answerPlaceholder = state.getAnswerPlaceholder();
+ final List answerPlaceholders = taskFile.getAnswerPlaceholders();
+ if (answerPlaceholders.contains(answerPlaceholder)) {
+ answerPlaceholders.remove(answerPlaceholder);
+ final Editor editor = state.getEditor();
+ editor.getMarkupModel().removeAllHighlighters();
+ StudyUtils.drawAllWindows(editor, taskFile);
+ EduAnswerPlaceholderPainter.createGuardedBlocks(editor, taskFile);
+ }
}
@Override
public void update(@NotNull AnActionEvent event) {
- if (!CCProjectService.setCCActionAvailable(event)) {
- return;
- }
final Presentation presentation = event.getPresentation();
- final Project project = event.getData(CommonDataKeys.PROJECT);
- if (project == null) {
- presentation.setVisible(false);
- presentation.setEnabled(false);
+ presentation.setEnabledAndVisible(false);
+
+ CCState state = getState(event);
+ if (state == null) {
return;
}
- final Editor editor = CommonDataKeys.EDITOR.getData(event.getDataContext());
- final PsiFile file = CommonDataKeys.PSI_FILE.getData(event.getDataContext());
- if (editor == null || file == null) {
- presentation.setVisible(false);
- presentation.setEnabled(false);
- return;
+
+ presentation.setVisible(true);
+ if (canAddPlaceholder(state) || canDeletePlaceholder(state)) {
+ presentation.setEnabled(true);
+ presentation.setText((state.getAnswerPlaceholder() == null ? "Add " : "Delete ") + EduNames.PLACEHOLDER);
}
+ }
+
+
+ private static boolean canAddPlaceholder(@NotNull CCState state) {
+ Editor editor = state.getEditor();
SelectionModel selectionModel = editor.getSelectionModel();
if (!selectionModel.hasSelection()) {
- presentation.setVisible(false);
- presentation.setEnabled(false);
- return;
+ return false;
}
int start = selectionModel.getSelectionStart();
int end = selectionModel.getSelectionEnd();
+ return !arePlaceholdersIntersect(state.getTaskFile(), editor.getDocument(), start, end);
+ }
- final CCProjectService service = CCProjectService.getInstance(project);
- final PsiDirectory taskDir = file.getContainingDirectory();
- final PsiDirectory lessonDir = taskDir.getParent();
- if (lessonDir == null) return;
-
- final Course course = service.getCourse();
- final Lesson lesson = course.getLesson(lessonDir.getName());
- if (lesson == null) {
- presentation.setVisible(false);
- presentation.setEnabled(false);
- return;
+ private static boolean canDeletePlaceholder(@NotNull CCState state) {
+ if (state.getEditor().getSelectionModel().hasSelection()) {
+ return false;
}
- final Task task = lesson.getTask(taskDir.getName());
- if (task == null) {
- presentation.setVisible(false);
- presentation.setEnabled(false);
- return;
- }
- TaskFile taskFile = service.getTaskFile(file.getVirtualFile());
- if (taskFile == null) {
- LOG.info("could not find task file");
- presentation.setVisible(false);
- presentation.setEnabled(false);
- return;
- }
- if (arePlaceholdersIntersect(taskFile, editor.getDocument(), start, end)) {
- presentation.setVisible(false);
- presentation.setEnabled(false);
- return;
- }
- presentation.setVisible(true);
- presentation.setEnabled(true);
+ return state.getAnswerPlaceholder() != null;
}
}
\ No newline at end of file
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAsTaskFile.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAsTaskFile.java
index 867cc77440b6..c62bd5e1e069 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAsTaskFile.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAsTaskFile.java
@@ -1,46 +1,20 @@
package com.jetbrains.edu.coursecreator.actions;
-import com.intellij.ide.projectView.ProjectView;
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.CommonDataKeys;
-import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.edu.coursecreator.CCUtils;
+import com.jetbrains.edu.learning.StudyUtils;
+import com.jetbrains.edu.learning.courseFormat.Course;
import com.jetbrains.edu.learning.courseFormat.Task;
-import com.jetbrains.edu.coursecreator.CCProjectService;
-public class CCAddAsTaskFile extends AnAction {
- @Override
- public void actionPerformed(final AnActionEvent e) {
- Project project = e.getProject();
- if (project == null) {
- return;
- }
- final VirtualFile file = CommonDataKeys.VIRTUAL_FILE.getData(e.getDataContext());
- if (file == null) {
- return;
- }
- Task task = CCProjectService.getInstance(project).getTask(file);
- if (task == null) {
- return;
- }
+public class CCAddAsTaskFile extends CCTaskFileActionBase {
+
+ protected void performAction(VirtualFile file, Task task, Course course, Project project) {
task.addTaskFile(file.getName(), task.getTaskFiles().size());
- ProjectView.getInstance(project).refresh();
+ CCUtils.createResourceFile(file, course, StudyUtils.getTaskDir(file));
}
-
- @Override
- public void update(AnActionEvent e) {
- Project project = e.getProject();
- Presentation presentation = e.getPresentation();
- if (project == null) {
- presentation.setEnabledAndVisible(false);
- return;
- }
- VirtualFile file = CommonDataKeys.VIRTUAL_FILE.getData(e.getDataContext());
- if (file == null || file.isDirectory() || CCProjectService.getInstance(project).getTaskFile(file) != null) {
- presentation.setEnabledAndVisible(false);
- }
+ protected boolean isAvailable(Project project, VirtualFile file) {
+ return StudyUtils.getTaskFile(project, file) == null && !CCUtils.isTestsFile(project, file);
}
}
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAnswerPlaceholderAction.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAnswerPlaceholderAction.java
index 48425e247100..e1633044d5e6 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAnswerPlaceholderAction.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAnswerPlaceholderAction.java
@@ -2,15 +2,15 @@ package com.jetbrains.edu.coursecreator.actions;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
-import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
+import com.jetbrains.edu.coursecreator.CCUtils;
+import com.jetbrains.edu.learning.StudyUtils;
import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
import com.jetbrains.edu.learning.courseFormat.TaskFile;
-import com.jetbrains.edu.coursecreator.CCProjectService;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -23,9 +23,9 @@ abstract public class CCAnswerPlaceholderAction extends DumbAwareAction {
}
@Nullable
- private static CCState getState(@NotNull AnActionEvent e) {
+ protected static CCState getState(@NotNull AnActionEvent e) {
final Project project = e.getProject();
- if (project == null || CCProjectService.getInstance(project).getCourse() == null) {
+ if (project == null || !CCUtils.isCourseCreator(project)) {
return null;
}
final PsiFile psiFile = CommonDataKeys.PSI_FILE.getData(e.getDataContext());
@@ -40,27 +40,16 @@ abstract public class CCAnswerPlaceholderAction extends DumbAwareAction {
if (editor == null) {
return null;
}
- TaskFile taskFile = CCProjectService.getInstance(project).getTaskFile(virtualFile);
+ TaskFile taskFile = StudyUtils.getTaskFile(project, virtualFile);
if (taskFile == null) {
return null;
}
AnswerPlaceholder answerPlaceholder = taskFile.getAnswerPlaceholder(editor.getDocument(),
editor.getCaretModel().getLogicalPosition(),
true);
- if (answerPlaceholder == null) {
- return null;
- }
return new CCState(taskFile, answerPlaceholder, psiFile, editor, project);
}
- @Override
- public void update(@NotNull AnActionEvent e) {
- Presentation presentation = e.getPresentation();
- boolean isAvailable = getState(e) != null;
- presentation.setEnabled(isAvailable);
- presentation.setVisible(isAvailable);
- }
-
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
CCState state = getState(e);
@@ -80,7 +69,7 @@ abstract public class CCAnswerPlaceholderAction extends DumbAwareAction {
private Project myProject;
public CCState(@NotNull final TaskFile taskFile,
- @NotNull final AnswerPlaceholder answerPlaceholder,
+ @Nullable final AnswerPlaceholder answerPlaceholder,
@NotNull final PsiFile file,
@NotNull final Editor editor,
@NotNull final Project project) {
@@ -96,7 +85,7 @@ abstract public class CCAnswerPlaceholderAction extends DumbAwareAction {
return myTaskFile;
}
- @NotNull
+ @Nullable
public AnswerPlaceholder getAnswerPlaceholder() {
return myAnswerPlaceholder;
}
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCChangeCourseInfo.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCChangeCourseInfo.java
index 28706dae9a72..3423c822aae8 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCChangeCourseInfo.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCChangeCourseInfo.java
@@ -2,39 +2,39 @@ package com.jetbrains.edu.coursecreator.actions;
import com.intellij.ide.IdeView;
import com.intellij.ide.projectView.ProjectView;
-import com.intellij.ide.util.DirectoryChooserUtil;
import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.ui.DialogBuilder;
import com.intellij.psi.PsiDirectory;
-import com.jetbrains.edu.learning.courseFormat.Course;
-import com.jetbrains.edu.coursecreator.CCProjectService;
+import com.intellij.util.ui.JBUI;
+import com.jetbrains.edu.coursecreator.CCUtils;
import com.jetbrains.edu.coursecreator.ui.CCNewProjectPanel;
+import com.jetbrains.edu.learning.StudyTaskManager;
+import com.jetbrains.edu.learning.courseFormat.Course;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
import javax.swing.*;
-import java.awt.*;
public class CCChangeCourseInfo extends DumbAwareAction {
+
+ private static final String ACTION_TEXT = "Change Course Information";
+
public CCChangeCourseInfo() {
- super("Change Course Information", "Change Course Information", null);
+ super(ACTION_TEXT, ACTION_TEXT, null);
}
@Override
public void update(@NotNull AnActionEvent event) {
- if (!CCProjectService.setCCActionAvailable(event)) {
+ final Project project = event.getProject();
+ final Presentation presentation = event.getPresentation();
+ if (project == null) {
return;
}
- final Presentation presentation = event.getPresentation();
- presentation.setVisible(false);
- presentation.setEnabled(false);
- final Project project = event.getData(CommonDataKeys.PROJECT);
- if (project == null) {
+ presentation.setEnabledAndVisible(false);
+ if (!CCUtils.isCourseCreator(project)) {
return;
}
final IdeView view = event.getData(LangDataKeys.IDE_VIEW);
@@ -45,45 +45,24 @@ public class CCChangeCourseInfo extends DumbAwareAction {
if (directories.length == 0) {
return;
}
- final PsiDirectory directory = DirectoryChooserUtil.getOrChooseDirectory(view);
- if (directory != null && !project.getBaseDir().equals(directory.getVirtualFile())) {
- return;
- }
- presentation.setVisible(true);
- presentation.setEnabled(true);
-
+ presentation.setEnabledAndVisible(true);
}
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
- if (!CCProjectService.setCCActionAvailable(e)) {
- return;
- }
- final Project project = e.getProject();
+ Project project = e.getProject();
if (project == null) {
return;
}
- Course course = CCProjectService.getInstance(project).getCourse();
+ Course course = StudyTaskManager.getInstance(project).getCourse();
if (course == null) {
return;
}
- final IdeView view = e.getData(LangDataKeys.IDE_VIEW);
- if (view == null) {
- return;
- }
- final PsiDirectory[] directories = view.getDirectories();
- if (directories.length == 0) {
- return;
- }
- final PsiDirectory directory = DirectoryChooserUtil.getOrChooseDirectory(view);
- if (directory != null && !project.getBaseDir().equals(directory.getVirtualFile())) {
- return;
- }
- CCNewProjectPanel panel = new CCNewProjectPanel(course.getName(), Course.getAuthorsString(course.getAuthors()), course.getDescription());
- ChangeCourseInfoDialog changeCourseInfoDialog =
- new ChangeCourseInfoDialog(project, panel);
- changeCourseInfoDialog.show();
- if (changeCourseInfoDialog.getExitCode() == DialogWrapper.OK_EXIT_CODE) {
+
+ CCNewProjectPanel panel =
+ new CCNewProjectPanel(course.getName(), Course.getAuthorsString(course.getAuthors()), course.getDescription());
+ DialogBuilder builder = createChangeInfoDialog(project, panel);
+ if (builder.showAndGet()) {
course.setAuthors(panel.getAuthors());
course.setName(panel.getName());
course.setDescription(panel.getDescription());
@@ -91,24 +70,14 @@ public class CCChangeCourseInfo extends DumbAwareAction {
}
}
- static class ChangeCourseInfoDialog extends DialogWrapper {
+ private static DialogBuilder createChangeInfoDialog(Project project, @NotNull CCNewProjectPanel panel) {
+ DialogBuilder builder = new DialogBuilder(project);
- private final JPanel myMainPanel;
+ builder.setTitle(ACTION_TEXT);
+ JPanel changeInfoPanel = panel.getMainPanel();
+ changeInfoPanel.setMinimumSize(JBUI.size(400, 300));
+ builder.setCenterPanel(changeInfoPanel);
- public ChangeCourseInfoDialog(@Nullable Project project, CCNewProjectPanel panel) {
- super(project);
- setTitle("Change Course Information");
- myMainPanel = panel.getMainPanel();
- init();
- }
-
- @Nullable
- @Override
- protected JComponent createCenterPanel() {
- myMainPanel.setPreferredSize(new Dimension(400, 300));
- myMainPanel.setSize(new Dimension(400, 300));
- myMainPanel.setMaximumSize(new Dimension(400, 300));
- return myMainPanel;
- }
+ return builder;
}
}
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateCourseArchive.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateCourseArchive.java
index 486f3b247c5d..bbef6bc15515 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateCourseArchive.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateCourseArchive.java
@@ -7,6 +7,7 @@ import com.intellij.ide.projectView.ProjectView;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.LangDataKeys;
+import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
@@ -20,6 +21,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.util.containers.HashMap;
import com.intellij.util.io.ZipUtil;
+import com.jetbrains.edu.learning.StudyTaskManager;
import com.jetbrains.edu.learning.core.EduNames;
import com.jetbrains.edu.learning.core.EduUtils;
import com.jetbrains.edu.learning.courseFormat.Course;
@@ -27,7 +29,6 @@ import com.jetbrains.edu.learning.courseFormat.Lesson;
import com.jetbrains.edu.learning.courseFormat.Task;
import com.jetbrains.edu.learning.courseFormat.TaskFile;
import com.jetbrains.edu.coursecreator.CCLanguageManager;
-import com.jetbrains.edu.coursecreator.CCProjectService;
import com.jetbrains.edu.coursecreator.CCUtils;
import com.jetbrains.edu.coursecreator.ui.CreateCourseArchiveDialog;
import org.jetbrains.annotations.NotNull;
@@ -56,7 +57,9 @@ public class CCCreateCourseArchive extends DumbAwareAction {
@Override
public void update(@NotNull AnActionEvent e) {
- CCProjectService.setCCActionAvailable(e);
+ Presentation presentation = e.getPresentation();
+ Project project = e.getProject();
+ presentation.setEnabledAndVisible(project != null && CCUtils.isCourseCreator(project));
}
@Override
@@ -70,8 +73,7 @@ public class CCCreateCourseArchive extends DumbAwareAction {
}
private void createCourseArchive(final Project project, Module module) {
- final CCProjectService service = CCProjectService.getInstance(project);
- final Course course = service.getCourse();
+ final Course course = StudyTaskManager.getInstance(project).getCourse();
if (course == null) return;
CreateCourseArchiveDialog dlg = new CreateCourseArchiveDialog(project, this);
dlg.show();
@@ -195,8 +197,7 @@ public class CCCreateCourseArchive extends DumbAwareAction {
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
private static void generateJson(@NotNull final Project project, VirtualFile parentDir) {
- final CCProjectService service = CCProjectService.getInstance(project);
- final Course course = service.getCourse();
+ final Course course = StudyTaskManager.getInstance(project).getCourse();
final Gson gson = new GsonBuilder().setPrettyPrinting().excludeFieldsWithoutExposeAnnotation().create();
final String json = gson.toJson(course);
final File courseJson = new File(parentDir.getPath(), EduNames.COURSE_META_FILE);
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateStudyItemActionBase.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateStudyItemActionBase.java
index 520ce0961a6a..45310c7c0e8f 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateStudyItemActionBase.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateStudyItemActionBase.java
@@ -14,12 +14,13 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.util.Function;
+import com.jetbrains.edu.coursecreator.CCUtils;
+import com.jetbrains.edu.coursecreator.ui.CCCreateStudyItemDialog;
+import com.jetbrains.edu.learning.StudyTaskManager;
+import com.jetbrains.edu.learning.StudyUtils;
import com.jetbrains.edu.learning.core.EduUtils;
import com.jetbrains.edu.learning.courseFormat.Course;
import com.jetbrains.edu.learning.courseFormat.StudyItem;
-import com.jetbrains.edu.coursecreator.CCProjectService;
-import com.jetbrains.edu.coursecreator.CCUtils;
-import com.jetbrains.edu.coursecreator.ui.CCCreateStudyItemDialog;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -33,18 +34,16 @@ public abstract class CCCreateStudyItemActionBase extends DumbAwareAction {
super(text, description, icon);
}
-
@Override
public void actionPerformed(AnActionEvent e) {
final IdeView view = e.getData(LangDataKeys.IDE_VIEW);
- final Project project = e.getData(CommonDataKeys.PROJECT);
+ final Project project = e.getProject();
if (view == null || project == null) {
return;
}
final PsiDirectory directory = DirectoryChooserUtil.getOrChooseDirectory(view);
if (directory == null) return;
- final CCProjectService service = CCProjectService.getInstance(project);
- final Course course = service.getCourse();
+ final Course course = StudyTaskManager.getInstance(project).getCourse();
if (course == null) {
return;
}
@@ -54,47 +53,45 @@ public abstract class CCCreateStudyItemActionBase extends DumbAwareAction {
@Override
public void update(@NotNull AnActionEvent event) {
- if (!CCProjectService.setCCActionAvailable(event)) {
- return;
- }
final Presentation presentation = event.getPresentation();
+ presentation.setEnabledAndVisible(false);
final Project project = event.getData(CommonDataKeys.PROJECT);
final IdeView view = event.getData(LangDataKeys.IDE_VIEW);
if (project == null || view == null) {
presentation.setEnabledAndVisible(false);
return;
}
+ if (!StudyUtils.isStudyProject(project)) {
+ return;
+ }
final PsiDirectory[] directories = view.getDirectories();
if (directories.length == 0) {
- presentation.setEnabledAndVisible(false);
return;
}
final PsiDirectory sourceDirectory = DirectoryChooserUtil.getOrChooseDirectory(view);
- final CCProjectService service = CCProjectService.getInstance(project);
- final Course course = service.getCourse();
+ final Course course = StudyTaskManager.getInstance(project).getCourse();
if (course == null || sourceDirectory == null) {
- presentation.setEnabledAndVisible(false);
return;
}
- if (!isAddedAsLast(sourceDirectory, project, course) &&
- getThresholdItem(course, sourceDirectory) == null) {
- presentation.setEnabledAndVisible(false);
+ if (!isAddedAsLast(sourceDirectory, project, course) && getThresholdItem(course, sourceDirectory) == null) {
+ return;
}
if (CommonDataKeys.PSI_FILE.getData(event.getDataContext()) != null) {
- presentation.setEnabledAndVisible(false);
+ return;
}
+ presentation.setEnabledAndVisible(true);
}
@Nullable
protected abstract PsiDirectory getParentDir(@NotNull final Project project,
- @NotNull final Course course,
- @NotNull final PsiDirectory directory);
+ @NotNull final Course course,
+ @NotNull final PsiDirectory directory);
@Nullable
public PsiDirectory createItem(@Nullable final IdeView view, @NotNull final Project project,
- @NotNull final PsiDirectory sourceDirectory, @NotNull final Course course) {
+ @NotNull final PsiDirectory sourceDirectory, @NotNull final Course course) {
StudyItem parentItem = getParentItem(course, sourceDirectory);
final StudyItem item = getItem(sourceDirectory, project, course, view, parentItem);
if (item == null) {
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateTask.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateTask.java
index 316b06d77c04..844fc9ad3796 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateTask.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateTask.java
@@ -9,19 +9,19 @@ import com.intellij.ide.util.EditorHelper;
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.util.Ref;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
import com.intellij.util.Function;
+import com.jetbrains.edu.coursecreator.CCLanguageManager;
+import com.jetbrains.edu.coursecreator.CCUtils;
import com.jetbrains.edu.learning.core.EduNames;
import com.jetbrains.edu.learning.core.EduUtils;
import com.jetbrains.edu.learning.courseFormat.Course;
import com.jetbrains.edu.learning.courseFormat.Lesson;
import com.jetbrains.edu.learning.courseFormat.StudyItem;
import com.jetbrains.edu.learning.courseFormat.Task;
-import com.jetbrains.edu.coursecreator.CCLanguageManager;
-import com.jetbrains.edu.coursecreator.CCUtils;
import icons.InteractiveLearningIcons;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -38,15 +38,15 @@ public class CCCreateTask extends CCCreateStudyItemActionBase {
}
- private static void createFromTemplateAndOpen(@NotNull final PsiDirectory taskDirectory,
- @Nullable final FileTemplate template,
- @Nullable IdeView view) {
+ private static void createFromTemplate(@NotNull final PsiDirectory taskDirectory,
+ @Nullable final FileTemplate template,
+ @Nullable IdeView view, boolean open) {
if (template == null) {
return;
}
try {
final PsiElement file = FileTemplateUtil.createFromTemplate(template, template.getName(), null, taskDirectory);
- if (view != null) {
+ if (view != null && open) {
EditorHelper.openInEditor(file, false);
view.selectElement(file);
}
@@ -91,31 +91,29 @@ public class CCCreateTask extends CCCreateStudyItemActionBase {
protected PsiDirectory createItemDir(@NotNull final Project project, @NotNull final StudyItem item,
@Nullable final IdeView view, @NotNull final PsiDirectory parentDirectory,
@NotNull final Course course) {
- final PsiDirectory[] taskDirectory = new PsiDirectory[1];
+
+ final Ref taskDirectory = new Ref<>();
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
- taskDirectory[0] = DirectoryUtil.createSubdirectories(EduNames.TASK + item.getIndex(), parentDirectory, "\\/");
- if (taskDirectory[0] != null) {
+ String taskDirName = EduNames.TASK + item.getIndex();
+ taskDirectory.set(DirectoryUtil.createSubdirectories(taskDirName, parentDirectory, "\\/"));
+ if (taskDirectory.get() != null) {
CCLanguageManager manager = CCUtils.getStudyLanguageManager(course);
if (manager == null) {
return;
}
- createFromTemplateAndOpen(taskDirectory[0], manager.getTestsTemplate(project), view);
- createFromTemplateAndOpen(taskDirectory[0], FileTemplateManager.getInstance(project).getInternalTemplate("task.html"), view);
+ createFromTemplate(taskDirectory.get(), manager.getTestsTemplate(project), view, false);
+ createFromTemplate(taskDirectory.get(), FileTemplateManager.getInstance(project).getInternalTemplate(EduNames.TASK_HTML), view, false);
String defaultExtension = manager.getDefaultTaskFileExtension();
if (defaultExtension != null) {
FileTemplate taskFileTemplate = manager.getTaskFileTemplateForExtension(project, defaultExtension);
- createFromTemplateAndOpen(taskDirectory[0], taskFileTemplate, view);
- if (taskFileTemplate != null) {
- String taskFileName = FileUtil.getNameWithoutExtension(taskFileTemplate.getName());
- ((Task)item).addTaskFile(taskFileName + "." + defaultExtension, 1);
- }
+ createFromTemplate(taskDirectory.get(), taskFileTemplate, view, true);
}
}
}
});
- return taskDirectory[0];
+ return taskDirectory.get();
}
@Override
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateTaskFile.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateTaskFile.java
deleted file mode 100644
index eb5598625cce..000000000000
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateTaskFile.java
+++ /dev/null
@@ -1,143 +0,0 @@
-package com.jetbrains.edu.coursecreator.actions;
-
-import com.intellij.icons.AllIcons;
-import com.intellij.ide.IdeView;
-import com.intellij.ide.fileTemplates.FileTemplate;
-import com.intellij.ide.fileTemplates.FileTemplateUtil;
-import com.intellij.ide.projectView.ProjectView;
-import com.intellij.ide.util.DirectoryChooserUtil;
-import com.intellij.ide.util.EditorHelper;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.CommonDataKeys;
-import com.intellij.openapi.actionSystem.LangDataKeys;
-import com.intellij.openapi.actionSystem.Presentation;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.fileEditor.FileEditorManager;
-import com.intellij.openapi.fileTypes.FileType;
-import com.intellij.openapi.project.DumbAwareAction;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.psi.PsiDirectory;
-import com.intellij.psi.PsiElement;
-import com.jetbrains.edu.learning.core.EduNames;
-import com.jetbrains.edu.learning.courseFormat.Course;
-import com.jetbrains.edu.learning.courseFormat.Lesson;
-import com.jetbrains.edu.learning.courseFormat.Task;
-import com.jetbrains.edu.coursecreator.CCLanguageManager;
-import com.jetbrains.edu.coursecreator.CCProjectService;
-import com.jetbrains.edu.coursecreator.CCUtils;
-import com.jetbrains.edu.coursecreator.ui.CreateTaskFileDialog;
-import org.jetbrains.annotations.NotNull;
-
-import static com.intellij.openapi.ui.DialogWrapper.OK_EXIT_CODE;
-
-public class CCCreateTaskFile extends DumbAwareAction {
-
- public CCCreateTaskFile() {
- super("Task File", "Create new Task File", AllIcons.FileTypes.Text);
- }
-
- @Override
- public void actionPerformed(final AnActionEvent e) {
- final IdeView view = e.getData(LangDataKeys.IDE_VIEW);
- final Project project = e.getData(CommonDataKeys.PROJECT);
-
- if (view == null || project == null) {
- return;
- }
- final PsiDirectory taskDir = DirectoryChooserUtil.getOrChooseDirectory(view);
- if (taskDir == null) return;
- PsiDirectory lessonDir = taskDir.getParent();
- if (lessonDir == null) {
- return;
- }
- final CCProjectService service = CCProjectService.getInstance(project);
- final Course course = service.getCourse();
- final Lesson lesson = course.getLesson(lessonDir.getName());
- final Task task = lesson.getTask(taskDir.getName());
-
- final int index = task.getTaskFiles().size() + 1;
- String generatedName = "file" + index;
- CreateTaskFileDialog dialog = new CreateTaskFileDialog(project, generatedName, course);
- dialog.show();
- if (dialog.getExitCode() != OK_EXIT_CODE) {
- return;
- }
- final String name = dialog.getFileName();
- if (name == null) return;
- FileType type = dialog.getFileType();
- if (type == null) {
- return;
- }
- final CCLanguageManager CCLanguageManager = CCUtils.getStudyLanguageManager(course);
- if (CCLanguageManager == null) {
- return;
- }
- final String extension = type.getDefaultExtension();
- ApplicationManager.getApplication().runWriteAction(new Runnable() {
- @Override
- public void run() {
- final FileTemplate taskTemplate = CCLanguageManager.getTaskFileTemplateForExtension(project, extension);
- final String taskFileName = name + "." + extension;
- try {
- if (taskTemplate == null) {
- VirtualFile file = taskDir.getVirtualFile().createChildData(this, taskFileName);
- ProjectView.getInstance(project).select(file, file, false);
- FileEditorManager.getInstance(project).openFile(file, true);
- }
- else {
- final PsiElement taskFile = FileTemplateUtil.createFromTemplate(taskTemplate, taskFileName, null, taskDir);
- ApplicationManager.getApplication().invokeLater(new Runnable() {
- @Override
- public void run() {
- EditorHelper.openInEditor(taskFile, false);
- view.selectElement(taskFile);
- }
- });
- }
- task.addTaskFile(taskFileName, index);
- }
- catch (Exception ignored) {
- }
- }
- });
- }
-
- @Override
- public void update(@NotNull AnActionEvent event) {
- if (!CCProjectService.setCCActionAvailable(event)) {
- return;
- }
- final Presentation presentation = event.getPresentation();
- final Project project = event.getData(CommonDataKeys.PROJECT);
- if (project == null) {
- presentation.setVisible(false);
- presentation.setEnabled(false);
- return;
- }
-
- final IdeView view = event.getData(LangDataKeys.IDE_VIEW);
- if (view == null) {
- presentation.setVisible(false);
- presentation.setEnabled(false);
- return;
- }
-
- final PsiDirectory[] directories = view.getDirectories();
- if (directories.length == 0) {
- presentation.setVisible(false);
- presentation.setEnabled(false);
- return;
- }
- final PsiDirectory directory = DirectoryChooserUtil.getOrChooseDirectory(view);
- final CCProjectService service = CCProjectService.getInstance(project);
- final Course course = service.getCourse();
- if (course != null && directory != null && !directory.getName().contains(EduNames.TASK)) {
- presentation.setVisible(false);
- presentation.setEnabled(false);
- return;
- }
- presentation.setVisible(true);
- presentation.setEnabled(true);
- }
-}
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCDeleteAllAnswerPlaceholdersAction.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCDeleteAllAnswerPlaceholdersAction.java
index 55915d05bae4..0916e1b678f4 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCDeleteAllAnswerPlaceholdersAction.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCDeleteAllAnswerPlaceholdersAction.java
@@ -3,6 +3,7 @@ package com.jetbrains.edu.coursecreator.actions;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.UndoConfirmationPolicy;
import com.intellij.openapi.command.WriteCommandAction;
@@ -14,10 +15,11 @@ import com.intellij.openapi.fileEditor.TextEditor;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
-import com.jetbrains.edu.learning.core.EduUtils;
+import com.jetbrains.edu.coursecreator.CCUtils;
+import com.jetbrains.edu.learning.StudyUtils;
+import com.jetbrains.edu.learning.core.EduNames;
import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
import com.jetbrains.edu.learning.courseFormat.TaskFile;
-import com.jetbrains.edu.coursecreator.CCProjectService;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -26,7 +28,7 @@ import java.util.List;
public class CCDeleteAllAnswerPlaceholdersAction extends DumbAwareAction {
- public static final String ACTION_NAME = "Delete All Answer Placeholders";
+ public static final String ACTION_NAME = "Delete All " + EduNames.PLACEHOLDER + "s";
public CCDeleteAllAnswerPlaceholdersAction() {
super(ACTION_NAME);
@@ -40,7 +42,7 @@ public class CCDeleteAllAnswerPlaceholdersAction extends DumbAwareAction {
if (file == null || project == null) {
return;
}
- final TaskFile taskFile = CCProjectService.getInstance(project).getTaskFile(file);
+ final TaskFile taskFile = StudyUtils.getTaskFile(project, file);
if (taskFile == null) {
return;
}
@@ -57,7 +59,7 @@ public class CCDeleteAllAnswerPlaceholdersAction extends DumbAwareAction {
editor = ((TextEditor)fileEditor).getEditor();
}
List placeholders = new ArrayList(taskFile.getAnswerPlaceholders());
- final ClearPlaceholders action = new ClearPlaceholders(taskFile, placeholders, editor, file, project);
+ final ClearPlaceholders action = new ClearPlaceholders(taskFile, placeholders, editor);
new WriteCommandAction(project, ACTION_NAME) {
protected void run(@NotNull final Result result) throws Throwable {
action.redo();
@@ -72,60 +74,57 @@ public class CCDeleteAllAnswerPlaceholdersAction extends DumbAwareAction {
}
private static void updateView(@NotNull final Editor editor,
- @NotNull final VirtualFile file,
- @NotNull final Project project) {
+ @NotNull final TaskFile taskFile) {
editor.getMarkupModel().removeAllHighlighters();
- CCProjectService.getInstance(project).drawAnswerPlaceholders(file, editor);
+ StudyUtils.drawAllWindows(editor, taskFile);
}
@Override
public void update(AnActionEvent e) {
- if (!CCProjectService.setCCActionAvailable(e)) {
+ Presentation presentation = e.getPresentation();
+ presentation.setEnabledAndVisible(false);
+
+ Project project = e.getProject();
+ if (project == null) {
+ return;
+ }
+ if (!CCUtils.isCourseCreator(project)) {
return;
}
DataContext context = e.getDataContext();
VirtualFile file = CommonDataKeys.VIRTUAL_FILE.getData(context);
- final Project project = e.getProject();
- if (file == null || project == null) {
- EduUtils.enableAction(e, false);
+ if (file == null ) {
return;
}
- TaskFile taskFile = CCProjectService.getInstance(project).getTaskFile(file);
- if (taskFile == null) {
- EduUtils.enableAction(e, false);
+ TaskFile taskFile = StudyUtils.getTaskFile(project, file);
+ if (taskFile == null || taskFile.getAnswerPlaceholders().isEmpty()) {
return;
}
- if (taskFile.getAnswerPlaceholders().isEmpty()) {
- EduUtils.enableAction(e, false);
- }
+ presentation.setEnabledAndVisible(true);
}
private static class ClearPlaceholders implements UndoableAction {
private final List myPlaceholders;
private final Editor myEditor;
- private final VirtualFile myFile;
- private final Project myProject;
TaskFile myTaskFile;
- public ClearPlaceholders(TaskFile taskFile, List placeholders, Editor editor, VirtualFile file, Project project) {
+ public ClearPlaceholders(TaskFile taskFile, List placeholders, Editor editor) {
myTaskFile = taskFile;
myPlaceholders = placeholders;
myEditor = editor;
- myFile = file;
- myProject = project;
}
@Override
public void undo() throws UnexpectedUndoException {
myTaskFile.getAnswerPlaceholders().addAll(myPlaceholders);
- updateView(myEditor, myFile, myProject);
+ updateView(myEditor, myTaskFile);
}
@Override
public void redo() throws UnexpectedUndoException {
myTaskFile.getAnswerPlaceholders().clear();
- updateView(myEditor, myFile, myProject);
+ updateView(myEditor, myTaskFile);
}
@Nullable
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCDeleteAnswerPlaceholder.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCDeleteAnswerPlaceholder.java
deleted file mode 100644
index e385589b32bd..000000000000
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCDeleteAnswerPlaceholder.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.jetbrains.edu.coursecreator.actions;
-
-import com.intellij.openapi.editor.Document;
-import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.project.Project;
-import com.intellij.psi.PsiDocumentManager;
-import com.intellij.psi.PsiFile;
-import com.jetbrains.edu.learning.core.EduAnswerPlaceholderPainter;
-import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
-import com.jetbrains.edu.learning.courseFormat.TaskFile;
-import com.jetbrains.edu.coursecreator.CCProjectService;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.List;
-
-public class CCDeleteAnswerPlaceholder extends CCAnswerPlaceholderAction {
-
- public CCDeleteAnswerPlaceholder() {
- super("Delete Answer Placeholder","Delete answer placeholder", null);
- }
-
- @Override
- protected void performAnswerPlaceholderAction(@NotNull CCState state) {
- Project project = state.getProject();
- PsiFile psiFile = state.getFile();
- final Document document = PsiDocumentManager.getInstance(project).getDocument(psiFile);
- if (document == null) return;
- TaskFile taskFile = state.getTaskFile();
- AnswerPlaceholder answerPlaceholder = state.getAnswerPlaceholder();
- final List answerPlaceholders = taskFile.getAnswerPlaceholders();
- if (answerPlaceholders.contains(answerPlaceholder)) {
- answerPlaceholders.remove(answerPlaceholder);
- final Editor editor = state.getEditor();
- editor.getMarkupModel().removeAllHighlighters();
- CCProjectService.getInstance(project).drawAnswerPlaceholders(psiFile.getVirtualFile(), editor);
- EduAnswerPlaceholderPainter.createGuardedBlocks(editor, taskFile, false);
- }
- }
-}
\ No newline at end of file
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCShowAnswerPlaceholderDetails.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCEditAnswerPlaceholder.java
similarity index 62%
rename from python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCShowAnswerPlaceholderDetails.java
rename to python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCEditAnswerPlaceholder.java
index 7068c5e1c572..622ddacf1cac 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCShowAnswerPlaceholderDetails.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCEditAnswerPlaceholder.java
@@ -1,5 +1,7 @@
package com.jetbrains.edu.coursecreator.actions;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiFile;
@@ -7,9 +9,9 @@ import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
import com.jetbrains.edu.coursecreator.ui.CCCreateAnswerPlaceholderDialog;
import org.jetbrains.annotations.NotNull;
-public class CCShowAnswerPlaceholderDetails extends CCAnswerPlaceholderAction {
+public class CCEditAnswerPlaceholder extends CCAnswerPlaceholderAction {
- public CCShowAnswerPlaceholderDetails() {
+ public CCEditAnswerPlaceholder() {
super("Edit Answer Placeholder", "Edit answer placeholder", null);
}
@@ -21,9 +23,23 @@ public class CCShowAnswerPlaceholderDetails extends CCAnswerPlaceholderAction {
final PsiDirectory lessonDir = taskDir.getParent();
if (lessonDir == null) return;
AnswerPlaceholder answerPlaceholder = state.getAnswerPlaceholder();
+ if (answerPlaceholder == null) {
+ return;
+ }
CCCreateAnswerPlaceholderDialog dlg = new CCCreateAnswerPlaceholderDialog(project, answerPlaceholder
);
dlg.setTitle("Edit Answer Placeholder");
dlg.show();
}
+
+ @Override
+ public void update(AnActionEvent e) {
+ Presentation presentation = e.getPresentation();
+ presentation.setEnabledAndVisible(false);
+ CCState state = getState(e);
+ if (state == null || state.getAnswerPlaceholder() == null) {
+ return;
+ }
+ presentation.setEnabledAndVisible(true);
+ }
}
\ No newline at end of file
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCEditTaskTextAction.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCEditTaskTextAction.java
new file mode 100644
index 000000000000..d86a0ae61754
--- /dev/null
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCEditTaskTextAction.java
@@ -0,0 +1,81 @@
+package com.jetbrains.edu.coursecreator.actions;
+
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.ToggleAction;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.project.DumbAware;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.edu.coursecreator.CCUtils;
+import com.jetbrains.edu.learning.StudyState;
+import com.jetbrains.edu.learning.StudyTaskManager;
+import com.jetbrains.edu.learning.StudyUtils;
+import com.jetbrains.edu.learning.core.EduNames;
+import com.jetbrains.edu.learning.editor.StudyEditor;
+import com.jetbrains.edu.learning.ui.StudyToolWindow;
+import org.jetbrains.annotations.NotNull;
+
+public class CCEditTaskTextAction extends ToggleAction implements DumbAware {
+ private static final Logger LOG = Logger.getInstance(CCEditTaskTextAction.class);
+
+ public CCEditTaskTextAction() {
+ super("Editing Mode", "Editing Mode", AllIcons.Modules.Edit);
+ }
+
+ @Override
+ public boolean isSelected(AnActionEvent e) {
+ Project project = e.getProject();
+ if (project == null) {
+ return false;
+ }
+ return StudyTaskManager.getInstance(project).getToolWindowMode() == StudyToolWindow.StudyToolWindowMode.EDITING;
+ }
+
+ @Override
+ public void setSelected(AnActionEvent e, boolean state) {
+ Project project = e.getProject();
+ if (project == null) {
+ return;
+ }
+ StudyToolWindow window = StudyUtils.getStudyToolWindow(project);
+ if (window == null) {
+ return;
+ }
+
+ final StudyEditor selectedEditor = StudyUtils.getSelectedStudyEditor(project);
+ if (selectedEditor == null) {
+ StudyTaskManager.getInstance(project).setTurnEditingMode(true);
+ return;
+ }
+ final StudyState studyState = new StudyState(selectedEditor);
+ VirtualFile taskTextFile = studyState.getTaskDir().findChild(EduNames.TASK_HTML);
+ if (taskTextFile == null) {
+ LOG.info("Failed to find task.html");
+ return;
+ }
+ Document document = FileDocumentManager.getInstance().getDocument(taskTextFile);
+ if (!state) {
+ if (document != null) {
+ FileDocumentManager.getInstance().saveDocument(document);
+ }
+ window.leaveEditingMode(project);
+ return;
+ }
+ window.enterEditingMode(taskTextFile, project);
+ }
+
+ @Override
+ public void update(@NotNull AnActionEvent e) {
+ Project project = e.getProject();
+ if (project == null) {
+ return;
+ }
+
+ if (!CCUtils.isCourseCreator(project)) {
+ e.getPresentation().setEnabledAndVisible(false);
+ }
+ }
+}
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java
index a7c6a91dc52e..97fdb1ec2e57 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java
@@ -22,10 +22,11 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.platform.templates.github.ZipUtil;
+import com.jetbrains.edu.coursecreator.CCUtils;
+import com.jetbrains.edu.learning.StudyTaskManager;
import com.jetbrains.edu.learning.core.EduDocumentListener;
import com.jetbrains.edu.learning.core.EduNames;
import com.jetbrains.edu.learning.core.EduUtils;
-import com.jetbrains.edu.coursecreator.CCProjectService;
import com.jetbrains.edu.learning.courseFormat.*;
import com.jetbrains.edu.learning.oldCourseFormat.OldCourse;
import org.jetbrains.annotations.NotNull;
@@ -58,7 +59,6 @@ public class CCFromCourseArchive extends DumbAwareAction {
}
final String basePath = project.getBasePath();
if (basePath == null) return;
- final CCProjectService service = CCProjectService.getInstance(project);
Reader reader = null;
try {
ZipUtil.unzip(null, new File(basePath), new File(virtualFile.getPath()), null, null, true);
@@ -77,7 +77,8 @@ public class CCFromCourseArchive extends DumbAwareAction {
course = EduUtils.transformOldCourse(oldCourse);
}
- service.setCourse(course);
+ StudyTaskManager.getInstance(project).setCourse(course);
+ course.setCourseMode(CCUtils.COURSE_MODE);
project.getBaseDir().refresh(false, true);
int index = 1;
int taskIndex = 1;
@@ -94,7 +95,7 @@ public class CCFromCourseArchive extends DumbAwareAction {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
- createAnswerFile(project, taskDir, taskDir, entry);
+ createAnswerFile(project, taskDir, entry);
}
});
}
@@ -103,6 +104,7 @@ public class CCFromCourseArchive extends DumbAwareAction {
index += 1;
taskIndex = 1;
}
+ course.initCourse(true);
}
catch (FileNotFoundException e) {
LOG.error(e.getMessage());
@@ -128,7 +130,6 @@ public class CCFromCourseArchive extends DumbAwareAction {
public static void createAnswerFile(@NotNull final Project project,
@NotNull final VirtualFile userFileDir,
- @NotNull final VirtualFile answerFileDir,
@NotNull final Map.Entry taskFileEntry) {
final String name = taskFileEntry.getKey();
final TaskFile taskFile = taskFileEntry.getValue();
@@ -183,8 +184,9 @@ public class CCFromCourseArchive extends DumbAwareAction {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
- final String text = document.getText(TextRange.create(offset, offset + answerPlaceholder.getLength()));
+ final String text = document.getText(TextRange.create(offset, offset + answerPlaceholder.getRealLength()));
answerPlaceholder.setTaskText(text);
+ answerPlaceholder.init();
final VirtualFile hints = project.getBaseDir().findChild(EduNames.HINTS);
if (hints != null) {
final String hintFile = answerPlaceholder.getHint();
@@ -198,7 +200,7 @@ public class CCFromCourseArchive extends DumbAwareAction {
}
}
- document.replaceString(offset, offset + answerPlaceholder.getLength(), answerPlaceholder.getPossibleAnswer());
+ document.replaceString(offset, offset + answerPlaceholder.getRealLength(), answerPlaceholder.getPossibleAnswer());
FileDocumentManager.getInstance().saveDocument(document);
}
});
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCHideFromStudent.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCHideFromStudent.java
new file mode 100644
index 000000000000..07cd46cfdf20
--- /dev/null
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCHideFromStudent.java
@@ -0,0 +1,45 @@
+package com.jetbrains.edu.coursecreator.actions;
+
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.edu.learning.StudyUtils;
+import com.jetbrains.edu.learning.courseFormat.Course;
+import com.jetbrains.edu.learning.courseFormat.Task;
+import com.jetbrains.edu.learning.courseFormat.TaskFile;
+
+import java.io.IOException;
+import java.util.Map;
+
+public class CCHideFromStudent extends CCTaskFileActionBase {
+
+ private static final Logger LOG = Logger.getInstance(CCHideFromStudent.class);
+
+ @Override
+ protected void performAction(VirtualFile file, Task task, Course course, Project project) {
+ Map taskFiles = task.getTaskFiles();
+ TaskFile taskFile = StudyUtils.getTaskFile(project, file);
+ if (taskFile == null) {
+ return;
+ }
+ String name = file.getName();
+ VirtualFile patternFile = StudyUtils.getPatternFile(taskFile, name);
+ ApplicationManager.getApplication().runWriteAction(() -> {
+ if (patternFile != null) {
+ try {
+ patternFile.delete(CCHideFromStudent.class);
+ }
+ catch (IOException e) {
+ LOG.info(e);
+ }
+ }
+ });
+ taskFiles.remove(name);
+ }
+
+ @Override
+ protected boolean isAvailable(Project project, VirtualFile file) {
+ return StudyUtils.getTaskFile(project, file) != null;
+ }
+}
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCPushCourse.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCPushCourse.java
index 78410c9ad3a1..f1a1f3006bf6 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCPushCourse.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCPushCourse.java
@@ -4,10 +4,12 @@ import com.intellij.ide.IdeView;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.LangDataKeys;
+import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
+import com.jetbrains.edu.coursecreator.CCUtils;
+import com.jetbrains.edu.learning.StudyTaskManager;
import com.jetbrains.edu.learning.courseFormat.Course;
-import com.jetbrains.edu.coursecreator.CCProjectService;
import com.jetbrains.edu.learning.stepic.EduStepicConnector;
import org.jetbrains.annotations.NotNull;
@@ -18,7 +20,9 @@ public class CCPushCourse extends DumbAwareAction {
@Override
public void update(@NotNull AnActionEvent e) {
- CCProjectService.setCCActionAvailable(e);
+ Presentation presentation = e.getPresentation();
+ Project project = e.getProject();
+ presentation.setEnabledAndVisible(project != null && CCUtils.isCourseCreator(project));
}
@Override
@@ -28,7 +32,7 @@ public class CCPushCourse extends DumbAwareAction {
if (view == null || project == null) {
return;
}
- final Course course = CCProjectService.getInstance(project).getCourse();
+ final Course course = StudyTaskManager.getInstance(project).getCourse();
if (course == null) {
return;
}
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCPushLesson.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCPushLesson.java
index 068b82bf0b1a..4e3f7ecc7414 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCPushLesson.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCPushLesson.java
@@ -11,9 +11,9 @@ import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiDirectory;
+import com.jetbrains.edu.learning.StudyTaskManager;
import com.jetbrains.edu.learning.courseFormat.Course;
import com.jetbrains.edu.learning.courseFormat.Lesson;
-import com.jetbrains.edu.coursecreator.CCProjectService;
import com.jetbrains.edu.learning.stepic.EduStepicConnector;
import org.jetbrains.annotations.NotNull;
@@ -30,7 +30,7 @@ public class CCPushLesson extends DumbAwareAction {
if (view == null || project == null) {
return;
}
- final Course course = CCProjectService.getInstance(project).getCourse();
+ final Course course = StudyTaskManager.getInstance(project).getCourse();
if (course == null) {
return;
}
@@ -51,7 +51,7 @@ public class CCPushLesson extends DumbAwareAction {
if (view == null || project == null) {
return;
}
- final Course course = CCProjectService.getInstance(project).getCourse();
+ final Course course = StudyTaskManager.getInstance(project).getCourse();
if (course == null) {
return;
}
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCRunTestsAction.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCRunTestsAction.java
deleted file mode 100644
index f6982733db5b..000000000000
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCRunTestsAction.java
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Copyright 2000-2014 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.jetbrains.edu.coursecreator.actions;
-
-import com.intellij.execution.Location;
-import com.intellij.execution.actions.ConfigurationContext;
-import com.intellij.icons.AllIcons;
-import com.intellij.ide.fileTemplates.FileTemplate;
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.Presentation;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.fileEditor.FileDocumentManager;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
-import com.jetbrains.edu.learning.core.EduNames;
-import com.jetbrains.edu.learning.core.EduUtils;
-import com.jetbrains.edu.learning.courseFormat.Course;
-import com.jetbrains.edu.learning.courseFormat.Lesson;
-import com.jetbrains.edu.learning.courseFormat.Task;
-import com.jetbrains.edu.learning.courseFormat.TaskFile;
-import com.jetbrains.edu.coursecreator.CCLanguageManager;
-import com.jetbrains.edu.coursecreator.CCProjectService;
-import com.jetbrains.edu.coursecreator.CCUtils;
-import org.jetbrains.annotations.NotNull;
-
-import java.io.IOException;
-import java.util.Map;
-
-public abstract class CCRunTestsAction extends AnAction {
- private static final Logger LOG = Logger.getInstance(CCRunTestsAction.class.getName());
-
- public CCRunTestsAction() {
- getTemplatePresentation().setIcon(AllIcons.Actions.Lightning);
- }
-
- @Override
- public void update(@NotNull AnActionEvent e) {
- final Presentation presentation = e.getPresentation();
- if (!CCProjectService.setCCActionAvailable(e)) {
- presentation.setEnabledAndVisible(false);
- return;
- }
-
- presentation.setEnabledAndVisible(false);
-
- final ConfigurationContext context = ConfigurationContext.getFromContext(e.getDataContext());
- Location location = context.getLocation();
- if (location == null) {
- return;
- }
- PsiElement psiElement = location.getPsiElement();
- PsiFile psiFile = psiElement.getContainingFile();
- Project project = e.getProject();
- if (project == null || psiFile == null) {
- return;
- }
- TaskFile taskFile = CCProjectService.getInstance(project).getTaskFile(psiFile.getVirtualFile());
- if (taskFile == null) {
- return;
- }
- presentation.setEnabledAndVisible(true);
- presentation.setText("Run tests from '" + FileUtil.getNameWithoutExtension(psiFile.getName()) + "'");
- }
-
- public void actionPerformed(@NotNull AnActionEvent e) {
- final ConfigurationContext context = ConfigurationContext.getFromContext(e.getDataContext());
- run(context);
- }
-
- private void run(final @NotNull ConfigurationContext context) {
- ApplicationManager.getApplication().runWriteAction(new Runnable() {
- @Override
- public void run() {
- final Project project = context.getProject();
- PsiElement location = context.getPsiLocation();
- final Course course = CCProjectService.getInstance(project).getCourse();
- if (course == null || location == null) {
- return;
- }
- PsiFile psiFile = location.getContainingFile();
- final VirtualFile virtualFile = psiFile.getVirtualFile();
- final VirtualFile taskDir = virtualFile.getParent();
- if (taskDir == null) {
- return;
- }
- VirtualFile lessonDir = taskDir.getParent();
- Lesson lesson = course.getLesson(lessonDir.getName());
- if (lesson == null) {
- return;
- }
- final Task task = lesson.getTask(taskDir.getName());
- if (task == null) {
- return;
- }
- clearTestEnvironment(taskDir, project);
- CCLanguageManager manager = CCUtils.getStudyLanguageManager(course);
- if (manager == null) {
- return;
- }
- for (final Map.Entry entry : task.getTaskFiles().entrySet()) {
- final String name = entry.getKey();
- createTaskFileForTest(taskDir, name, entry.getValue(), project);
- }
- FileTemplate testsTemplate = manager.getTestsTemplate(project);
- if (testsTemplate == null) {
- return;
- }
- VirtualFile testFile = taskDir.findChild(testsTemplate.getName() + "." + testsTemplate.getExtension());
- if (testFile == null) {
- return;
- }
- executeTests(project, virtualFile, taskDir, testFile);
- }
- });
- }
-
- private static void createTaskFileForTest(@NotNull final VirtualFile taskDir, final String fileName, @NotNull final TaskFile taskFile,
- @NotNull final Project project) {
- final VirtualFile answerFile = taskDir.findChild(fileName);
- if (answerFile == null) {
- LOG.debug("could not find answer file " + fileName);
- return;
- }
- ApplicationManager.getApplication().runWriteAction(new Runnable() {
- @Override
- public void run() {
- final FileDocumentManager documentManager = FileDocumentManager.getInstance();
- documentManager.saveAllDocuments();
- }
- });
- EduUtils.flushWindows(taskFile, answerFile, false);
- createResourceFiles(answerFile, project);
- }
-
- public static void clearTestEnvironment(@NotNull final VirtualFile taskDir, @NotNull final Project project) {
- try {
- VirtualFile ideaDir = project.getBaseDir().findChild(".idea");
- if (ideaDir == null) {
- LOG.debug("idea directory doesn't exist");
- return;
- }
- VirtualFile courseResourceDir = ideaDir.findChild(EduNames.COURSE);
- if (courseResourceDir != null) {
- courseResourceDir.delete(project);
- }
- VirtualFile[] taskDirChildren = taskDir.getChildren();
- for (VirtualFile file : taskDirChildren) {
- if (file.getName().contains(EduNames.WINDOWS_POSTFIX)) {
- file.delete(project);
- }
- }
- }
- catch (IOException e) {
- LOG.error(e);
- }
- }
-
- protected abstract void executeTests(@NotNull final Project project,
- @NotNull final VirtualFile virtualFile,
- @NotNull final VirtualFile taskDir,
- @NotNull final VirtualFile testFile);
-
- //some tests could compare task files after user modifications with initial task files
- private static void createResourceFiles(@NotNull final VirtualFile file, @NotNull final Project project) {
- VirtualFile taskDir = file.getParent();
- int index = EduUtils.getIndex(taskDir.getName(), EduNames.TASK);
- VirtualFile lessonDir = taskDir.getParent();
- int lessonIndex = EduUtils.getIndex(lessonDir.getName(), EduNames.LESSON);
- Course course = CCProjectService.getInstance(project).getCourse();
- if (course == null) {
- return;
- }
- VirtualFile ideaDir = project.getBaseDir().findChild(".idea");
- assert ideaDir != null;
- try {
- VirtualFile courseResourceDir = findOrCreateDir(project, ideaDir, EduNames.COURSE);
- VirtualFile lessonResourceDir = findOrCreateDir(project, courseResourceDir, lessonDir.getName());
- VirtualFile taskResourceDir = findOrCreateDir(project, lessonResourceDir, taskDir.getName());
- if (EduUtils.indexIsValid(lessonIndex, course.getLessons())) {
- Lesson lesson = course.getLessons().get(lessonIndex);
- if (EduUtils.indexIsValid(index, lesson.getTaskList())) {
- Task task = lesson.getTaskList().get(index);
- for (Map.Entry entry : task.getTaskFiles().entrySet()) {
- TaskFile taskFile = new TaskFile();
- TaskFile.copy(entry.getValue(), taskFile);
- EduUtils.createStudentFileFromAnswer(project, taskResourceDir, taskDir, entry.getKey(), taskFile);
- }
- }
- }
- }
- catch (IOException e) {
- LOG.error(e);
- }
- }
-
- private static VirtualFile findOrCreateDir(@NotNull final Project project, @NotNull final VirtualFile dir, String name)
- throws IOException {
- VirtualFile targetDir = dir.findChild(name);
- if (targetDir == null) {
- targetDir = dir.createChildDirectory(project, name);
- }
- return targetDir;
- }
-}
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCShowPreview.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCShowPreview.java
index f0662db25052..39a2ce7f4e0d 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCShowPreview.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCShowPreview.java
@@ -37,12 +37,13 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiFile;
import com.intellij.ui.JBColor;
+import com.jetbrains.edu.learning.StudyTaskManager;
+import com.jetbrains.edu.learning.StudyUtils;
import com.jetbrains.edu.learning.core.EduAnswerPlaceholderPainter;
import com.jetbrains.edu.learning.core.EduUtils;
import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
import com.jetbrains.edu.learning.courseFormat.Course;
import com.jetbrains.edu.learning.courseFormat.TaskFile;
-import com.jetbrains.edu.coursecreator.CCProjectService;
import com.jetbrains.edu.coursecreator.CCUtils;
import org.jetbrains.annotations.NotNull;
@@ -61,24 +62,23 @@ public class CCShowPreview extends DumbAwareAction {
@Override
public void update(@NotNull AnActionEvent e) {
- if (!CCProjectService.setCCActionAvailable(e)) {
- return;
- }
+ Presentation presentation = e.getPresentation();
+ presentation.setEnabledAndVisible(false);
Project project = e.getProject();
if (project == null) {
return;
}
- Presentation presentation = e.getPresentation();
- presentation.setEnabledAndVisible(false);
+ if (!CCUtils.isCourseCreator(project)) {
+ return;
+ }
final PsiFile file = CommonDataKeys.PSI_FILE.getData(e.getDataContext());
- if (file != null && CCProjectService.getInstance(project).getTaskFile(file.getVirtualFile()) != null) {
+ if (file != null && StudyUtils.getTaskFile(project, file.getVirtualFile()) != null) {
presentation.setEnabledAndVisible(true);
}
}
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
- //TODO: need to rewrite this action using new GENERATED_ROOT_FOLDER
final Project project = e.getProject();
Module module = LangDataKeys.MODULE.getData(e.getDataContext());
if (project == null || module == null) {
@@ -88,13 +88,12 @@ public class CCShowPreview extends DumbAwareAction {
if (file == null) {
return;
}
- final CCProjectService service = CCProjectService.getInstance(project);
- Course course = service.getCourse();
+ Course course = StudyTaskManager.getInstance(project).getCourse();
if (course == null) {
return;
}
VirtualFile virtualFile = file.getVirtualFile();
- TaskFile taskFile = service.getTaskFile(virtualFile);
+ TaskFile taskFile = StudyUtils.getTaskFile(project, virtualFile);
if (taskFile == null) {
return;
}
@@ -149,7 +148,7 @@ public class CCShowPreview extends DumbAwareAction {
}
});
for (AnswerPlaceholder answerPlaceholder : taskFileCopy.getAnswerPlaceholders()) {
- EduAnswerPlaceholderPainter.drawAnswerPlaceholder(createdEditor, answerPlaceholder, true, JBColor.BLUE);
+ EduAnswerPlaceholderPainter.drawAnswerPlaceholder(createdEditor, answerPlaceholder, JBColor.BLUE);
}
JPanel header = new JPanel();
header.setLayout(new BoxLayout(header, BoxLayout.Y_AXIS));
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCTaskFileActionBase.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCTaskFileActionBase.java
new file mode 100644
index 000000000000..4f0632e82ee8
--- /dev/null
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCTaskFileActionBase.java
@@ -0,0 +1,59 @@
+package com.jetbrains.edu.coursecreator.actions;
+
+import com.intellij.ide.projectView.ProjectView;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.edu.coursecreator.CCUtils;
+import com.jetbrains.edu.learning.StudyTaskManager;
+import com.jetbrains.edu.learning.StudyUtils;
+import com.jetbrains.edu.learning.courseFormat.Course;
+import com.jetbrains.edu.learning.courseFormat.Task;
+
+public abstract class CCTaskFileActionBase extends AnAction {
+
+ @Override
+ public void actionPerformed(final AnActionEvent e) {
+ Project project = e.getProject();
+ if (project == null) {
+ return;
+ }
+ final VirtualFile file = CommonDataKeys.VIRTUAL_FILE.getData(e.getDataContext());
+ if (file == null) {
+ return;
+ }
+ VirtualFile taskVF = file.getParent();
+ if (taskVF == null) {
+ return;
+ }
+ Task task = StudyUtils.getTask(project, taskVF);
+ if (task == null) {
+ return;
+ }
+ Course course = StudyTaskManager.getInstance(project).getCourse();
+ performAction(file, task, course, project);
+ ProjectView.getInstance(project).refresh();
+ }
+
+ protected abstract void performAction(VirtualFile file, Task task, Course course, Project project);
+
+
+ @Override
+ public void update(AnActionEvent e) {
+ Project project = e.getProject();
+ Presentation presentation = e.getPresentation();
+ if (project == null || !CCUtils.isCourseCreator(project)) {
+ presentation.setEnabledAndVisible(false);
+ return;
+ }
+ VirtualFile file = CommonDataKeys.VIRTUAL_FILE.getData(e.getDataContext());
+ if (file == null || file.isDirectory() || !isAvailable(project, file)) {
+ presentation.setEnabledAndVisible(false);
+ }
+ }
+
+ protected abstract boolean isAvailable(Project project, VirtualFile file);
+}
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCLessonMoveHandlerDelegate.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCLessonMoveHandlerDelegate.java
similarity index 93%
rename from python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCLessonMoveHandlerDelegate.java
rename to python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCLessonMoveHandlerDelegate.java
index 685ac3741785..18ca9364c96f 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCLessonMoveHandlerDelegate.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCLessonMoveHandlerDelegate.java
@@ -1,4 +1,4 @@
-package com.jetbrains.edu.coursecreator;
+package com.jetbrains.edu.coursecreator.handlers;
import com.intellij.ide.IdeView;
import com.intellij.ide.util.DirectoryChooserUtil;
@@ -18,7 +18,10 @@ import com.intellij.psi.PsiReference;
import com.intellij.refactoring.move.MoveCallback;
import com.intellij.refactoring.move.MoveHandlerDelegate;
import com.intellij.util.Function;
+import com.jetbrains.edu.coursecreator.CCUtils;
import com.jetbrains.edu.coursecreator.ui.CCMoveStudyItemDialog;
+import com.jetbrains.edu.learning.StudyTaskManager;
+import com.jetbrains.edu.coursecreator.CCUtils;
import com.jetbrains.edu.learning.core.EduNames;
import com.jetbrains.edu.learning.core.EduUtils;
import com.jetbrains.edu.learning.courseFormat.Course;
@@ -67,7 +70,10 @@ public class CCLessonMoveHandlerDelegate extends MoveHandlerDelegate {
if (targetContainer == null || !(targetContainer instanceof PsiDirectory)) {
return;
}
- final Course course = CCProjectService.getInstance(project).getCourse();
+ final Course course = StudyTaskManager.getInstance(project).getCourse();
+ if (course == null) {
+ return;
+ }
final PsiDirectory sourceDirectory = (PsiDirectory)elements[0];
final Lesson sourceLesson = course.getLesson(sourceDirectory.getName());
final Lesson targetLesson = course.getLesson(((PsiDirectory)targetContainer).getName());
@@ -129,6 +135,6 @@ public class CCLessonMoveHandlerDelegate extends MoveHandlerDelegate {
DataContext dataContext,
@Nullable PsiReference reference,
Editor editor) {
- return CCProjectService.getInstance(project).getCourse() != null;
+ return CCUtils.isCourseCreator(project);
}
}
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCLessonRenameHandler.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCLessonRenameHandler.java
similarity index 94%
rename from python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCLessonRenameHandler.java
rename to python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCLessonRenameHandler.java
index 9b29cbafec2e..0efe1110a8ca 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCLessonRenameHandler.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCLessonRenameHandler.java
@@ -1,4 +1,4 @@
-package com.jetbrains.edu.coursecreator;
+package com.jetbrains.edu.coursecreator.handlers;
import com.intellij.ide.TitledHandler;
import com.intellij.openapi.project.Project;
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCRenameHandler.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCRenameHandler.java
similarity index 88%
rename from python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCRenameHandler.java
rename to python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCRenameHandler.java
index 27bd42ca2484..e98ba1ab133f 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCRenameHandler.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCRenameHandler.java
@@ -1,4 +1,4 @@
-package com.jetbrains.edu.coursecreator;
+package com.jetbrains.edu.coursecreator.handlers;
import com.intellij.ide.projectView.ProjectView;
import com.intellij.openapi.actionSystem.CommonDataKeys;
@@ -12,6 +12,8 @@ import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.refactoring.rename.RenameHandler;
+import com.jetbrains.edu.coursecreator.CCUtils;
+import com.jetbrains.edu.learning.StudyTaskManager;
import com.jetbrains.edu.learning.courseFormat.Course;
import com.jetbrains.edu.learning.courseFormat.StudyItem;
import org.jetbrains.annotations.NotNull;
@@ -23,9 +25,7 @@ public abstract class CCRenameHandler implements RenameHandler {
if (element == null || !(element instanceof PsiDirectory)) {
return false;
}
- CCProjectService instance = CCProjectService.getInstance(element.getProject());
- Course course = instance.getCourse();
- if (course == null) {
+ if (!CCUtils.isCourseCreator(element.getProject())) {
return false;
}
VirtualFile directory = ((PsiDirectory)element).getVirtualFile();
@@ -44,8 +44,10 @@ public abstract class CCRenameHandler implements RenameHandler {
PsiElement element = CommonDataKeys.PSI_ELEMENT.getData(dataContext);
assert element != null;
PsiDirectory directory = (PsiDirectory)element;
- CCProjectService instance = CCProjectService.getInstance(project);
- Course course = instance.getCourse();
+ Course course = StudyTaskManager.getInstance(project).getCourse();
+ if (course == null) {
+ return;
+ }
rename(project, course, directory);
ProjectView.getInstance(project).refresh();
}
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCTaskMoveHandlerDelegate.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCTaskMoveHandlerDelegate.java
similarity index 94%
rename from python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCTaskMoveHandlerDelegate.java
rename to python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCTaskMoveHandlerDelegate.java
index 380e0556112b..91083e9f9edb 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCTaskMoveHandlerDelegate.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCTaskMoveHandlerDelegate.java
@@ -1,4 +1,4 @@
-package com.jetbrains.edu.coursecreator;
+package com.jetbrains.edu.coursecreator.handlers;
import com.intellij.ide.IdeView;
import com.intellij.ide.util.DirectoryChooserUtil;
@@ -18,13 +18,15 @@ import com.intellij.psi.PsiReference;
import com.intellij.refactoring.move.MoveCallback;
import com.intellij.refactoring.move.MoveHandlerDelegate;
import com.intellij.util.Function;
+import com.jetbrains.edu.coursecreator.CCUtils;
+import com.jetbrains.edu.coursecreator.ui.CCMoveStudyItemDialog;
+import com.jetbrains.edu.learning.StudyTaskManager;
import com.jetbrains.edu.learning.core.EduNames;
import com.jetbrains.edu.learning.core.EduUtils;
import com.jetbrains.edu.learning.courseFormat.Course;
import com.jetbrains.edu.learning.courseFormat.Lesson;
import com.jetbrains.edu.learning.courseFormat.StudyItem;
import com.jetbrains.edu.learning.courseFormat.Task;
-import com.jetbrains.edu.coursecreator.ui.CCMoveStudyItemDialog;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
@@ -59,9 +61,9 @@ public class CCTaskMoveHandlerDelegate extends MoveHandlerDelegate {
if (sourceDirectory == null) {
return false;
}
- CCProjectService service = CCProjectService.getInstance(sourceDirectory.getProject());
- Course course = service.getCourse();
- if (course == null) {
+ Project project = sourceDirectory.getProject();
+ Course course = StudyTaskManager.getInstance(project).getCourse();
+ if (course == null || !CCUtils.isCourseCreator(project)) {
return false;
}
return EduUtils.getTask(sourceDirectory, course) != null;
@@ -86,7 +88,7 @@ public class CCTaskMoveHandlerDelegate extends MoveHandlerDelegate {
Messages.showInfoMessage("Tasks can be moved only to other lessons or inside lesson", "Incorrect Target For Move");
return;
}
- final Course course = CCProjectService.getInstance(project).getCourse();
+ final Course course = StudyTaskManager.getInstance(project).getCourse();
final PsiDirectory sourceDirectory = (PsiDirectory)elements[0];
final Task taskToMove = EduUtils.getTask(sourceDirectory, course);
@@ -192,6 +194,6 @@ public class CCTaskMoveHandlerDelegate extends MoveHandlerDelegate {
DataContext dataContext,
@Nullable PsiReference reference,
Editor editor) {
- return CCProjectService.getInstance(project).getCourse() != null;
+ return CCUtils.isCourseCreator(project);
}
}
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCTaskRenameHandler.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCTaskRenameHandler.java
similarity index 96%
rename from python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCTaskRenameHandler.java
rename to python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCTaskRenameHandler.java
index 0f30a1d689f5..98bcba87c6c8 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCTaskRenameHandler.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCTaskRenameHandler.java
@@ -1,4 +1,4 @@
-package com.jetbrains.edu.coursecreator;
+package com.jetbrains.edu.coursecreator.handlers;
import com.intellij.ide.TitledHandler;
import com.intellij.openapi.project.Project;
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCDirectoryNode.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCDirectoryNode.java
deleted file mode 100644
index 551d344e3772..000000000000
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCDirectoryNode.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package com.jetbrains.edu.coursecreator.projectView;
-
-import com.intellij.ide.projectView.PresentationData;
-import com.intellij.ide.projectView.ViewSettings;
-import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode;
-import com.intellij.openapi.project.Project;
-import com.intellij.psi.PsiDirectory;
-import com.intellij.ui.SimpleTextAttributes;
-import com.jetbrains.edu.learning.core.EduNames;
-import com.jetbrains.edu.learning.core.EduUtils;
-import com.jetbrains.edu.learning.courseFormat.Course;
-import com.jetbrains.edu.learning.courseFormat.Lesson;
-import com.jetbrains.edu.learning.courseFormat.Task;
-import com.jetbrains.edu.coursecreator.CCProjectService;
-import icons.InteractiveLearningIcons;
-import org.jetbrains.annotations.NotNull;
-
-public class CCDirectoryNode extends PsiDirectoryNode {
- private final PsiDirectory myValue;
- private final Project myProject;
-
- public CCDirectoryNode(@NotNull final Project project,
- PsiDirectory value,
- ViewSettings viewSettings) {
- super(project, value, viewSettings);
- myValue = value;
- myProject = project;
- }
-
- @Override
- protected void updateImpl(PresentationData data) {
- String valueName = myValue.getName();
- final CCProjectService service = CCProjectService.getInstance(myProject);
- final Course course = service.getCourse();
- if (course == null) return;
- if (myProject.getBaseDir().equals(myValue.getVirtualFile())) {
- data.clearText();
- data.setIcon(InteractiveLearningIcons.Course);
- data.addText(course.getName(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
- data.addText(" (" + valueName + ")", SimpleTextAttributes.GRAYED_ATTRIBUTES);
- return;
- }
- final Lesson lesson = course.getLesson(valueName);
- if (lesson != null) {
- data.clearText();
- data.setIcon(InteractiveLearningIcons.Lesson);
- data.addText(lesson.getName(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
- return;
- }
- else {
- final PsiDirectory parentDir = myValue.getParentDirectory();
- if (parentDir != null) {
- final Lesson parentLesson = course.getLesson(parentDir.getName());
- if (parentLesson != null) {
- final Task task = parentLesson.getTask(valueName);
- if (task != null) {
- data.clearText();
- data.setIcon(InteractiveLearningIcons.Task);
- data.addText(task.getName(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
- return;
- }
- }
- }
- }
- data.setPresentableText(valueName);
- }
-
- @Override
- public int getTypeSortWeight(boolean sortByType) {
- String name = myValue.getName();
- if (name.startsWith(EduNames.LESSON) || name.startsWith(EduNames.TASK)) {
- String logicalName = name.contains(EduNames.LESSON) ? EduNames.LESSON : EduNames.TASK;
- int index = EduUtils.getIndex(name, logicalName) + 1;
- return index != -1 ? index + 1: 0;
- }
- return 0;
- }
-
- @Override
- public String getNavigateActionText(boolean focusEditor) {
- return null;
- }
-}
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCTreeStructureProvider.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCTreeStructureProvider.java
index d4f39fbefd2f..2702e3d4cf56 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCTreeStructureProvider.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCTreeStructureProvider.java
@@ -1,23 +1,22 @@
package com.jetbrains.edu.coursecreator.projectView;
-import com.intellij.ide.projectView.TreeStructureProvider;
import com.intellij.ide.projectView.ViewSettings;
import com.intellij.ide.projectView.impl.nodes.PsiFileNode;
import com.intellij.ide.util.treeView.AbstractTreeNode;
-import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
-import com.jetbrains.edu.learning.core.EduNames;
-import com.jetbrains.edu.coursecreator.CCProjectService;
import com.jetbrains.edu.coursecreator.CCUtils;
+import com.jetbrains.edu.learning.StudyUtils;
+import com.jetbrains.edu.learning.core.EduNames;
+import com.jetbrains.edu.learning.projectView.StudyTreeStructureProvider;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
-public class CCTreeStructureProvider implements TreeStructureProvider, DumbAware {
+public class CCTreeStructureProvider extends StudyTreeStructureProvider {
@NotNull
@Override
public Collection modify(@NotNull AbstractTreeNode parent,
@@ -26,18 +25,16 @@ public class CCTreeStructureProvider implements TreeStructureProvider, DumbAware
if (!needModify(parent)) {
return children;
}
- Collection nodes = new ArrayList();
+ Collection modifiedChildren = new ArrayList(super.modify(parent, children, settings));
+
for (AbstractTreeNode node : children) {
Project project = node.getProject();
- if (project != null) {
if (node.getValue() instanceof PsiDirectory) {
String name = ((PsiDirectory)node.getValue()).getName();
- if (CCUtils.GENERATED_FILES_FOLDER.equals(name)) {
+ if ("zip".equals(FileUtilRt.getExtension(name))) {
+ modifiedChildren.add(node);
continue;
}
- PsiDirectory directory = (PsiDirectory)node.getValue();
- nodes.add(new CCDirectoryNode(project, directory, settings));
- continue;
}
if (node instanceof PsiFileNode) {
PsiFileNode fileNode = (PsiFileNode)node;
@@ -45,34 +42,19 @@ public class CCTreeStructureProvider implements TreeStructureProvider, DumbAware
if (virtualFile == null) {
continue;
}
- if (virtualFile.getName().contains(EduNames.WINDOWS_POSTFIX)) {
- continue;
- }
-
- if (virtualFile.getParent().getName().contains(EduNames.TASK) && !CCProjectService.getInstance(project).isTaskFile(virtualFile)) {
- nodes.add(new CCStudentInvisibleFileNode(project, ((PsiFileNode)node).getValue(), settings));
- continue;
+ if (StudyUtils.getTaskFile(project, virtualFile) == null && !EduNames.TASK_HTML.equals(virtualFile.getName())) {
+ modifiedChildren.add(new CCStudentInvisibleFileNode(project, ((PsiFileNode)node).getValue(), settings));
}
}
- nodes.add(node);
- }
}
- return nodes;
+ return modifiedChildren;
}
- private static boolean needModify(@NotNull final AbstractTreeNode parent) {
+ protected boolean needModify(@NotNull final AbstractTreeNode parent) {
Project project = parent.getProject();
- if (project != null) {
- if (CCProjectService.getInstance(project).getCourse() == null) {
- return false;
- }
+ if (project == null) {
+ return false;
}
- return true;
- }
-
- @Nullable
- @Override
- public Object getData(Collection selected, String dataName) {
- return null;
+ return CCUtils.isCourseCreator(project);
}
}
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CreateCourseArchiveDialog.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CreateCourseArchiveDialog.java
index d1bc4fca3469..538665e54864 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CreateCourseArchiveDialog.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CreateCourseArchiveDialog.java
@@ -2,8 +2,8 @@ package com.jetbrains.edu.coursecreator.ui;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
+import com.jetbrains.edu.learning.StudyTaskManager;
import com.jetbrains.edu.learning.courseFormat.Course;
-import com.jetbrains.edu.coursecreator.CCProjectService;
import com.jetbrains.edu.coursecreator.actions.CCCreateCourseArchive;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -17,7 +17,7 @@ public class CreateCourseArchiveDialog extends DialogWrapper {
public CreateCourseArchiveDialog(@NotNull final Project project, CCCreateCourseArchive action) {
super(project);
- Course course = CCProjectService.getInstance(project).getCourse();
+ Course course = StudyTaskManager.getInstance(project).getCourse();
assert course != null;
setTitle("Create Course Archive");
myPanel = new CreateCourseArchivePanel(project, this, course.getName());
diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CreateCourseArchivePanel.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CreateCourseArchivePanel.java
index c84a5cdf2b26..1eeb2edd0b14 100644
--- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CreateCourseArchivePanel.java
+++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CreateCourseArchivePanel.java
@@ -33,7 +33,7 @@ public class CreateCourseArchivePanel extends JPanel {
myNameField.setText(sanitizedName.startsWith("_") ? EduNames.COURSE : sanitizedName);
myLocationField.setText(project.getBasePath());
FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
- myLocationField.addBrowseFolderListener("Choose location folder", null, project, descriptor);
+ myLocationField.addBrowseFolderListener("Choose Location Folder", null, project, descriptor);
myLocationField.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
diff --git a/python/educational-core/student/resources/META-INF/plugin.xml b/python/educational-core/student/resources/META-INF/plugin.xml
index 296fd98bd005..1ebb41dc0aed 100644
--- a/python/educational-core/student/resources/META-INF/plugin.xml
+++ b/python/educational-core/student/resources/META-INF/plugin.xml
@@ -36,7 +36,9 @@
+
+
>
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyActionListener.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyActionListener.java
new file mode 100644
index 000000000000..525adc2eddd3
--- /dev/null
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyActionListener.java
@@ -0,0 +1,10 @@
+package com.jetbrains.edu.learning;
+
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.extensions.ExtensionPointName;
+
+public interface StudyActionListener {
+ ExtensionPointName EP_NAME = ExtensionPointName.create("Edu.studyActionListener");
+
+ void beforeCheck(AnActionEvent event);
+}
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyActionsProvider.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyActionsProvider.java
new file mode 100644
index 000000000000..4aca599efea7
--- /dev/null
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyActionsProvider.java
@@ -0,0 +1,10 @@
+package com.jetbrains.edu.learning;
+
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.extensions.ExtensionPointName;
+
+public interface StudyActionsProvider {
+ ExtensionPointName EP_NAME = ExtensionPointName.create("Edu.studyActionsProvider");
+
+ AnAction[] getActions();
+}
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyAnswerPlaceholderExtendWordHandler.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyAnswerPlaceholderExtendWordHandler.java
index 8ebc8f4dadd6..ad364dfc02f2 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyAnswerPlaceholderExtendWordHandler.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyAnswerPlaceholderExtendWordHandler.java
@@ -59,6 +59,6 @@ public class StudyAnswerPlaceholderExtendWordHandler implements ExtendWordSelect
Document document = FileDocumentManager.getInstance().getDocument(file);
assert document != null;
int startOffset = placeholder.getRealStartOffset(document);
- return Collections.singletonList(new TextRange(startOffset, startOffset + placeholder.getLength()));
+ return Collections.singletonList(new TextRange(startOffset, startOffset + placeholder.getRealLength()));
}
}
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java
index 74410d74ce84..4fde0a889748 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java
@@ -48,9 +48,6 @@ public abstract class StudyBasePluginConfigurator implements StudyPluginConfigur
public FileEditorManagerListener getFileEditorManagerListener(@NotNull Project project, @NotNull StudyToolWindow toolWindow) {
return new FileEditorManagerListener() {
-
- private static final String EMPTY_TASK_TEXT = "Please, open any task to see task description";
-
@Override
public void fileOpened(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
Task task = getTask(file);
@@ -59,7 +56,7 @@ public abstract class StudyBasePluginConfigurator implements StudyPluginConfigur
@Override
public void fileClosed(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
- toolWindow.setTaskText(EMPTY_TASK_TEXT);
+ toolWindow.setEmptyText(project);
}
@Override
@@ -85,10 +82,10 @@ public abstract class StudyBasePluginConfigurator implements StudyPluginConfigur
private void setTaskText(@Nullable final Task task, @Nullable final VirtualFile taskDirectory) {
String text = StudyUtils.getTaskTextFromTask(task, taskDirectory);
if (text == null) {
- toolWindow.setTaskText(EMPTY_TASK_TEXT);
+ toolWindow.setEmptyText(project);
return;
}
- toolWindow.setTaskText(text);
+ toolWindow.setTaskText(text, taskDirectory, project);
}
};
}
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyMoveDelegate.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyMoveDelegate.java
index 7cd21a26b510..abac20c57afe 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyMoveDelegate.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyMoveDelegate.java
@@ -8,6 +8,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.refactoring.move.MoveCallback;
import com.intellij.refactoring.move.MoveHandlerDelegate;
+import com.jetbrains.edu.learning.core.EduNames;
import com.jetbrains.edu.learning.courseFormat.Course;
import org.jetbrains.annotations.Nullable;
@@ -22,7 +23,7 @@ public class StudyMoveDelegate extends MoveHandlerDelegate{
if (elements.length == 1) {
Project project = elements[0].getProject();
Course course = StudyTaskManager.getInstance(project).getCourse();
- if (course == null) {
+ if (course == null || !EduNames.STUDY.equals(course.getCourseMode())) {
return false;
}
return !StudyUtils.isRenameableOrMoveable(project, course, elements[0]);
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyPluginConfigurator.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyPluginConfigurator.java
index 61d9e78570d6..db5ee3b39143 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyPluginConfigurator.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyPluginConfigurator.java
@@ -40,6 +40,6 @@ public interface StudyPluginConfigurator {
StudyAfterCheckAction[] getAfterCheckActions();
@NotNull String getLanguageScriptUrl();
-
+
boolean accept(@NotNull final Project project);
}
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java
index 205b7929960a..ac816c7ebde5 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java
@@ -25,13 +25,13 @@ import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowAnchor;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.util.containers.hash.HashMap;
-import com.jetbrains.edu.learning.actions.StudyToolbarAction;
import com.jetbrains.edu.learning.core.EduNames;
import com.jetbrains.edu.learning.core.EduUtils;
import com.jetbrains.edu.learning.courseFormat.Course;
import com.jetbrains.edu.learning.courseFormat.Lesson;
import com.jetbrains.edu.learning.courseFormat.Task;
import com.jetbrains.edu.learning.courseFormat.TaskFile;
+import com.jetbrains.edu.learning.actions.*;
import com.jetbrains.edu.learning.editor.StudyEditorFactoryListener;
import com.jetbrains.edu.learning.ui.StudyProgressToolWindowFactory;
import com.jetbrains.edu.learning.ui.StudyToolWindow;
@@ -110,9 +110,9 @@ public class StudyProjectComponent implements ProjectComponent {
List actionsOnToolbar = window.getActions(true);
if (actionsOnToolbar != null) {
for (AnAction action : actionsOnToolbar) {
- if (action instanceof StudyToolbarAction) {
- String id = ((StudyToolbarAction)action).getActionId();
- String[] shortcuts = ((StudyToolbarAction)action).getShortcuts();
+ if (action instanceof StudyActionWithShortcut) {
+ String id = ((StudyActionWithShortcut)action).getActionId();
+ String[] shortcuts = ((StudyActionWithShortcut)action).getShortcuts();
if (shortcuts != null) {
addShortcut(id, shortcuts);
}
@@ -227,7 +227,7 @@ public class StudyProjectComponent implements ProjectComponent {
keymap.addShortcut(actionShortcut.first, new KeyboardShortcut(KeyStroke.getKeyStroke(actionShortcut.second), null));
}
}
- }
+ }
}
myListener = null;
}
@@ -287,30 +287,30 @@ public class StudyProjectComponent implements ProjectComponent {
final VirtualFile createdFile = event.getFile();
final VirtualFile taskDir = createdFile.getParent();
final Course course = StudyTaskManager.getInstance(myProject).getCourse();
+ if (course == null || !EduNames.STUDY.equals(course.getCourseMode())) {
+ return;
+ }
if (taskDir != null && taskDir.getName().contains(EduNames.TASK)) {
int taskIndex = EduUtils.getIndex(taskDir.getName(), EduNames.TASK);
final VirtualFile lessonDir = taskDir.getParent();
if (lessonDir != null && lessonDir.getName().contains(EduNames.LESSON)) {
int lessonIndex = EduUtils.getIndex(lessonDir.getName(), EduNames.LESSON);
- if (course != null) {
- List lessons = course.getLessons();
- if (StudyUtils.indexIsValid(lessonIndex, lessons)) {
- final Lesson lesson = lessons.get(lessonIndex);
- final List tasks = lesson.getTaskList();
- if (StudyUtils.indexIsValid(taskIndex, tasks)) {
- final Task task = tasks.get(taskIndex);
- final TaskFile taskFile = new TaskFile();
- taskFile.initTaskFile(task, false);
- taskFile.setUserCreated(true);
- final String name = createdFile.getName();
- taskFile.name = name;
- task.getTaskFiles().put(name, taskFile);
- }
+ List lessons = course.getLessons();
+ if (StudyUtils.indexIsValid(lessonIndex, lessons)) {
+ final Lesson lesson = lessons.get(lessonIndex);
+ final List tasks = lesson.getTaskList();
+ if (StudyUtils.indexIsValid(taskIndex, tasks)) {
+ final Task task = tasks.get(taskIndex);
+ final TaskFile taskFile = new TaskFile();
+ taskFile.initTaskFile(task, false);
+ taskFile.setUserCreated(true);
+ final String name = createdFile.getName();
+ taskFile.name = name;
+ task.getTaskFiles().put(name, taskFile);
}
}
}
}
}
}
-
}
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyTaskManager.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyTaskManager.java
index b534bba9118b..024cd09e9245 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyTaskManager.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyTaskManager.java
@@ -14,6 +14,7 @@ import com.intellij.util.xmlb.XmlSerializer;
import com.jetbrains.edu.learning.core.EduUtils;
import com.jetbrains.edu.learning.courseFormat.*;
import com.jetbrains.edu.learning.oldCourseFormat.OldCourse;
+import com.jetbrains.edu.learning.ui.StudyToolWindow;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -38,6 +39,8 @@ public class StudyTaskManager implements PersistentStateComponent, Dumb
public Map> myUserTests = new HashMap<>();
public List myInvisibleFiles = new ArrayList<>();
public boolean myShouldUseJavaFx = StudyUtils.hasJavaFx();
+ private StudyToolWindow.StudyToolWindowMode myToolWindowMode = StudyToolWindow.StudyToolWindowMode.TEXT;
+ private boolean myTurnEditingMode = false;
private StudyTaskManager() {
}
@@ -71,7 +74,7 @@ public class StudyTaskManager implements PersistentStateComponent, Dumb
@NotNull
public List getUserTests(@NotNull final Task task) {
final List userTests = myUserTests.get(task);
- return userTests != null ? userTests : Collections.emptyList();
+ return userTests != null ? userTests : Collections.emptyList();
}
public void removeUserTest(@NotNull final Task task, @NotNull final UserTest userTest) {
@@ -260,4 +263,20 @@ public class StudyTaskManager implements PersistentStateComponent, Dumb
public void setShouldUseJavaFx(boolean shouldUseJavaFx) {
this.myShouldUseJavaFx = shouldUseJavaFx;
}
+
+ public StudyToolWindow.StudyToolWindowMode getToolWindowMode() {
+ return myToolWindowMode;
+ }
+
+ public void setToolWindowMode(StudyToolWindow.StudyToolWindowMode toolWindowMode) {
+ myToolWindowMode = toolWindowMode;
+ }
+
+ public boolean isTurnEditingMode() {
+ return myTurnEditingMode;
+ }
+
+ public void setTurnEditingMode(boolean turnEditingMode) {
+ myTurnEditingMode = turnEditingMode;
+ }
}
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java
index 73d7843efcc8..2c41cda8d574 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java
@@ -128,7 +128,7 @@ public class StudyUtils {
}
public static void updateToolWindows(@NotNull final Project project) {
- update(project);
+ updateStudyToolWindow(project);
final ToolWindowManager windowManager = ToolWindowManager.getInstance(project);
createProgressToolWindowContent(project, windowManager);
@@ -300,7 +300,6 @@ public class StudyUtils {
return null;
}
-
public static void drawAllWindows(Editor editor, TaskFile taskFile) {
editor.getMarkupModel().removeAllHighlighters();
final Project project = editor.getProject();
@@ -308,12 +307,12 @@ public class StudyUtils {
final StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
for (AnswerPlaceholder answerPlaceholder : taskFile.getAnswerPlaceholders()) {
final JBColor color = taskManager.getColor(answerPlaceholder);
- EduAnswerPlaceholderPainter.drawAnswerPlaceholder(editor, answerPlaceholder, true, color);
+ EduAnswerPlaceholderPainter.drawAnswerPlaceholder(editor, answerPlaceholder, color);
}
final Document document = editor.getDocument();
EditorActionManager.getInstance()
.setReadonlyFragmentModificationHandler(document, new EduAnswerPlaceholderDeleteHandler(editor));
- EduAnswerPlaceholderPainter.createGuardedBlocks(editor, taskFile, true);
+ EduAnswerPlaceholderPainter.createGuardedBlocks(editor, taskFile);
editor.getColorsScheme().setColor(EditorColors.READONLY_FRAGMENT_BACKGROUND_COLOR, null);
}
@@ -353,21 +352,31 @@ public class StudyUtils {
}
}
+
@Nullable
- public static Document getPatternDocument(@NotNull final TaskFile taskFile, String name) {
+ public static VirtualFile getPatternFile(@NotNull TaskFile taskFile, String name) {
Task task = taskFile.getTask();
String lessonDir = EduNames.LESSON + String.valueOf(task.getLesson().getIndex());
String taskDir = EduNames.TASK + String.valueOf(task.getIndex());
Course course = task.getLesson().getCourse();
File resourceFile = new File(course.getCourseDirectory());
if (!resourceFile.exists()) {
- return null;
+ return null;
}
String patternPath = FileUtil.join(resourceFile.getPath(), lessonDir, taskDir, name);
VirtualFile patternFile = VfsUtil.findFileByIoFile(new File(patternPath), true);
if (patternFile == null) {
return null;
}
+ return patternFile;
+ }
+
+ @Nullable
+ public static Document getPatternDocument(@NotNull final TaskFile taskFile, String name) {
+ VirtualFile patternFile = getPatternFile(taskFile, name);
+ if (patternFile == null) {
+ return null;
+ }
return FileDocumentManager.getInstance().getDocument(patternFile);
}
@@ -411,9 +420,10 @@ public class StudyUtils {
return false;
}
Course course = StudyTaskManager.getInstance(project).getCourse();
- if (course == null) {
+ if (course == null || !EduNames.STUDY.equals(course.getCourseMode())) {
return false;
}
+
if (!isRenameableOrMoveable(project, course, element)) {
return true;
}
@@ -473,14 +483,7 @@ public class StudyUtils {
public static String getTaskText(@NotNull final Project project) {
- VirtualFile[] files = FileEditorManager.getInstance(project).getSelectedFiles();
- TaskFile taskFile = null;
- for (VirtualFile file : files) {
- taskFile = getTaskFile(project, file);
- if (taskFile != null) {
- break;
- }
- }
+ TaskFile taskFile = getSelectedTaskFile(project);
if (taskFile == null) {
return EMPTY_TASK_TEXT;
}
@@ -490,19 +493,31 @@ public class StudyUtils {
}
return null;
}
+ @Nullable
+ public static TaskFile getSelectedTaskFile(@NotNull Project project) {
+ VirtualFile[] files = FileEditorManager.getInstance(project).getSelectedFiles();
+ TaskFile taskFile = null;
+ for (VirtualFile file : files) {
+ taskFile = getTaskFile(project, file);
+ if (taskFile != null) {
+ break;
+ }
+ }
+ return taskFile;
+ }
- public static void update(Project project) {
+ public static void updateStudyToolWindow(Project project) {
final StudyToolWindow studyToolWindow = getStudyToolWindow(project);
if (studyToolWindow != null) {
String taskText = getTaskText(project);
- studyToolWindow.setTaskText(taskText);
+ studyToolWindow.setTaskText(taskText, null, project);
}
}
public static boolean isStudyProject(@NotNull Project project) {
return StudyTaskManager.getInstance(project).getCourse() != null;
}
-
+
public static boolean hasJavaFx() {
try {
Class.forName("javafx.application.Platform");
@@ -512,4 +527,37 @@ public class StudyUtils {
return false;
}
}
+
+ @Nullable
+ public static Task getTask(@NotNull Project project, @NotNull VirtualFile taskVF) {
+ Course course = StudyTaskManager.getInstance(project).getCourse();
+ if (course == null) {
+ return null;
+ }
+ VirtualFile lessonVF = taskVF.getParent();
+ if (lessonVF == null) {
+ return null;
+ }
+ Lesson lesson = course.getLesson(lessonVF.getName());
+ if (lesson == null) {
+ return null;
+ }
+ return lesson.getTask(taskVF.getName());
+ }
+
+ @Nullable
+ public static VirtualFile getTaskDir(@NotNull VirtualFile taskFile) {
+ VirtualFile parent = taskFile.getParent();
+ if (parent == null) {
+ return null;
+ }
+ String name = parent.getName();
+ if (name.contains(EduNames.TASK)) {
+ return parent;
+ }
+ if (EduNames.SRC.equals(name)) {
+ return parent.getParent();
+ }
+ return null;
+ }
}
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyToolbarAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyActionWithShortcut.java
similarity index 58%
rename from python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyToolbarAction.java
rename to python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyActionWithShortcut.java
index a74e547984ef..ae1fa651031c 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyToolbarAction.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyActionWithShortcut.java
@@ -6,8 +6,9 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
-public abstract class StudyToolbarAction extends DumbAwareAction {
- public StudyToolbarAction(@Nullable String text, @Nullable String description, @Nullable Icon icon) {
+public abstract class StudyActionWithShortcut extends DumbAwareAction {
+
+ public StudyActionWithShortcut(@Nullable String text, @Nullable String description, @Nullable Icon icon) {
super(text, description, icon);
}
@@ -15,5 +16,5 @@ public abstract class StudyToolbarAction extends DumbAwareAction {
public abstract String getActionId();
@Nullable
- public abstract String[] getShortcuts();
-}
+ public abstract String[] getShortcuts();
+}
\ No newline at end of file
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyCheckAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyCheckAction.java
index be3695794db6..623c7326972a 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyCheckAction.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyCheckAction.java
@@ -3,11 +3,13 @@ package com.jetbrains.edu.learning.actions;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.KeyboardShortcut;
import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.util.Ref;
+import com.jetbrains.edu.learning.StudyActionListener;
import com.jetbrains.edu.learning.StudyUtils;
import com.jetbrains.edu.learning.checker.StudyCheckUtils;
import icons.InteractiveLearningIcons;
@@ -15,7 +17,7 @@ import org.jetbrains.annotations.NotNull;
import javax.swing.*;
-public abstract class StudyCheckAction extends StudyToolbarAction {
+public abstract class StudyCheckAction extends StudyActionWithShortcut {
public static final String SHORTCUT = "ctrl alt pressed ENTER";
protected Ref myCheckInProgress = new Ref<>(false);
@@ -36,6 +38,9 @@ public abstract class StudyCheckAction extends StudyToolbarAction {
StudyCheckUtils.showTestResultPopUp("Checking is not available while indexing is in progress", MessageType.WARNING.getPopupBackground(), project);
return;
}
+ for (StudyActionListener listener : Extensions.getExtensions(StudyActionListener.EP_NAME)) {
+ listener.beforeCheck(e);
+ }
check(project);
}
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyFillPlaceholdersAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyFillPlaceholdersAction.java
index e65c8a02bd6d..54c8e2c4ac08 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyFillPlaceholdersAction.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyFillPlaceholdersAction.java
@@ -36,7 +36,7 @@ public class StudyFillPlaceholdersAction extends AnAction {
continue;
}
int offset = placeholder.getRealStartOffset(document);
- document.deleteString(offset, offset + placeholder.getLength());
+ document.deleteString(offset, offset + placeholder.getRealLength());
document.insertString(offset, answer);
}
}
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshAnswerPlaceholder.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshAnswerPlaceholder.java
index 42a7674c384b..7daa54735398 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshAnswerPlaceholder.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshAnswerPlaceholder.java
@@ -6,9 +6,11 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
+import com.jetbrains.edu.learning.StudyActionListener;
import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
import com.jetbrains.edu.learning.courseFormat.TaskFile;
import com.jetbrains.edu.learning.StudyState;
@@ -30,6 +32,9 @@ public class StudyRefreshAnswerPlaceholder extends DumbAwareAction {
if (project == null) {
return;
}
+ for (StudyActionListener listener : Extensions.getExtensions(StudyActionListener.EP_NAME)) {
+ listener.beforeCheck(e);
+ }
final AnswerPlaceholder answerPlaceholder = getAnswerPlaceholder(e);
if (answerPlaceholder == null) {
return;
@@ -51,7 +56,7 @@ public class StudyRefreshAnswerPlaceholder extends DumbAwareAction {
public void run() {
Document document = studyState.getEditor().getDocument();
int offset = answerPlaceholder.getRealStartOffset(document);
- document.deleteString(offset, offset + answerPlaceholder.getLength());
+ document.deleteString(offset, offset + answerPlaceholder.getRealLength());
document.insertString(offset, text);
}
});
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshTaskFileAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshTaskFileAction.java
index ef52729f7740..3c8057c75dea 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshTaskFileAction.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshTaskFileAction.java
@@ -9,6 +9,7 @@ import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageType;
@@ -19,13 +20,14 @@ import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.problems.WolfTheProblemSolver;
+import com.jetbrains.edu.learning.StudyActionListener;
+import com.jetbrains.edu.learning.StudyState;
+import com.jetbrains.edu.learning.StudyTaskManager;
+import com.jetbrains.edu.learning.StudyUtils;
import com.jetbrains.edu.learning.core.EduAnswerPlaceholderPainter;
import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
import com.jetbrains.edu.learning.courseFormat.StudyStatus;
import com.jetbrains.edu.learning.courseFormat.TaskFile;
-import com.jetbrains.edu.learning.StudyState;
-import com.jetbrains.edu.learning.StudyTaskManager;
-import com.jetbrains.edu.learning.StudyUtils;
import com.jetbrains.edu.learning.editor.StudyEditor;
import com.jetbrains.edu.learning.navigation.StudyNavigator;
import org.jetbrains.annotations.NotNull;
@@ -33,7 +35,7 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
-public class StudyRefreshTaskFileAction extends StudyToolbarAction {
+public class StudyRefreshTaskFileAction extends StudyActionWithShortcut {
public static final String ACTION_ID = "RefreshTaskAction";
public static final String SHORTCUT = "ctrl shift pressed X";
private static final Logger LOG = Logger.getInstance(StudyRefreshTaskFileAction.class.getName());
@@ -73,7 +75,7 @@ public class StudyRefreshTaskFileAction extends StudyToolbarAction {
WolfTheProblemSolver.getInstance(project).clearProblems(studyState.getVirtualFile());
taskFile.setHighlightErrors(false);
StudyUtils.drawAllWindows(editor, taskFile);
- EduAnswerPlaceholderPainter.createGuardedBlocks(editor, taskFile, true);
+ EduAnswerPlaceholderPainter.createGuardedBlocks(editor, taskFile);
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
@@ -148,6 +150,9 @@ public class StudyRefreshTaskFileAction extends StudyToolbarAction {
public void actionPerformed(@NotNull AnActionEvent event) {
final Project project = event.getProject();
if (project != null) {
+ for (StudyActionListener listener : Extensions.getExtensions(StudyActionListener.EP_NAME)) {
+ listener.beforeCheck(event);
+ }
refresh(project);
}
}
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyShowHintAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyShowHintAction.java
index 25642dc0cf87..75a1277c88d9 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyShowHintAction.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyShowHintAction.java
@@ -25,7 +25,7 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
-public class StudyShowHintAction extends StudyToolbarAction {
+public class StudyShowHintAction extends StudyActionWithShortcut {
public static final String ACTION_ID = "ShowHintAction";
public static final String SHORTCUT = "ctrl pressed 7";
private static final String ourWarningMessage = "Put the caret in the answer placeholder to get hint";
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyTaskNavigationAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyTaskNavigationAction.java
index 580bc3557d64..308a423d68f6 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyTaskNavigationAction.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyTaskNavigationAction.java
@@ -27,7 +27,7 @@ import javax.swing.tree.TreePath;
import java.util.Map;
-abstract public class StudyTaskNavigationAction extends StudyToolbarAction {
+abstract public class StudyTaskNavigationAction extends StudyActionWithShortcut {
public StudyTaskNavigationAction(@Nullable String text, @Nullable String description, @Nullable Icon icon) {
super(text, description, icon);
}
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyWindowNavigationAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyWindowNavigationAction.java
index 50be6069aa36..cd0b5ccf1dbe 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyWindowNavigationAction.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyWindowNavigationAction.java
@@ -16,7 +16,7 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
-abstract public class StudyWindowNavigationAction extends StudyToolbarAction implements DumbAware {
+abstract public class StudyWindowNavigationAction extends StudyActionWithShortcut implements DumbAware {
protected StudyWindowNavigationAction(String actionId, String description, Icon icon) {
super(actionId, description, icon);
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java
index 9fe0ae84ae6b..33c626a05bcb 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java
@@ -21,6 +21,7 @@ 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.core.EduDocumentListener;
+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.Task;
@@ -38,7 +39,6 @@ import java.util.List;
import java.util.Map;
public class StudyCheckUtils {
- private static final String ANSWERS_POSTFIX = "_answers";
private static final Logger LOG = Logger.getInstance(StudyCheckUtils.class);
private StudyCheckUtils() {
@@ -143,7 +143,7 @@ public class StudyCheckUtils {
VirtualFile copy = null;
try {
- copy = file.copy(taskDir, taskDir, file.getNameWithoutExtension() + ANSWERS_POSTFIX + "." + file.getExtension());
+ copy = file.copy(taskDir, taskDir, file.getNameWithoutExtension() + EduNames.ANSWERS_POSTFIX + "." + file.getExtension());
final FileDocumentManager documentManager = FileDocumentManager.getInstance();
final Document document = documentManager.getDocument(copy);
if (document != null) {
@@ -155,7 +155,7 @@ public class StudyCheckUtils {
continue;
}
final int start = answerPlaceholder.getRealStartOffset(document);
- final int end = start + answerPlaceholder.getLength();
+ final int end = start + answerPlaceholder.getRealLength();
final String text = answerPlaceholder.getPossibleAnswer();
document.replaceString(start, end, text);
}
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudySmartChecker.java b/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudySmartChecker.java
index 7cd660635d84..14870203abac 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudySmartChecker.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudySmartChecker.java
@@ -54,10 +54,10 @@ public class StudySmartChecker {
EduDocumentListener listener = new EduDocumentListener(windowTaskFile);
windowDocument.addDocumentListener(listener);
int start = placeholder.getRealStartOffset(windowDocument);
- int end = start + placeholder.getLength();
+ int end = start + placeholder.getRealLength();
final AnswerPlaceholder userAnswerPlaceholder = usersTaskFile.getAnswerPlaceholders().get(placeholder.getIndex());
int userStart = userAnswerPlaceholder.getRealStartOffset(usersDocument);
- int userEnd = userStart + userAnswerPlaceholder.getLength();
+ int userEnd = userStart + userAnswerPlaceholder.getRealLength();
String text = usersDocument.getText(new TextRange(userStart, userEnd));
windowDocument.replaceString(start, end, text);
ApplicationManager.getApplication().runWriteAction(() -> {
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduAnswerPlaceholderPainter.java b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduAnswerPlaceholderPainter.java
index 528b58e26102..81fcf85fb989 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduAnswerPlaceholderPainter.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduAnswerPlaceholderPainter.java
@@ -26,9 +26,9 @@ public class EduAnswerPlaceholderPainter {
}
public static void drawAnswerPlaceholder(@NotNull final Editor editor, @NotNull final AnswerPlaceholder placeholder,
- boolean useLength, @NotNull final JBColor color) {
+ @NotNull final JBColor color) {
final Document document = editor.getDocument();
- if (useLength && !placeholder.isValid(document)) {
+ if (!placeholder.isValid(document)) {
return;
}
EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme();
@@ -37,10 +37,8 @@ public class EduAnswerPlaceholderPainter {
final Project project = editor.getProject();
assert project != null;
final int startOffset = placeholder.getRealStartOffset(document);
- final int length = placeholder.getLength();
- final int replacementLength = placeholder.getPossibleAnswerLength();
- int highlighterLength = useLength ? length : replacementLength;
- final int endOffset = startOffset + highlighterLength;
+ final int length = placeholder.getRealLength();
+ final int endOffset = startOffset + length;
textAttributes.setEffectColor(color);
RangeHighlighter
highlighter = editor.getMarkupModel().addRangeHighlighter(startOffset, endOffset, PLACEHOLDERS_LAYER,
@@ -56,20 +54,20 @@ public class EduAnswerPlaceholderPainter {
}
- public static void createGuardedBlocks(@NotNull final Editor editor, TaskFile taskFile, boolean useLength) {
+ public static void createGuardedBlocks(@NotNull final Editor editor, TaskFile taskFile) {
for (AnswerPlaceholder answerPlaceholder : taskFile.getAnswerPlaceholders()) {
- createGuardedBlocks(editor, answerPlaceholder, useLength);
+ createGuardedBlocks(editor, answerPlaceholder);
}
}
- public static void createGuardedBlocks(@NotNull final Editor editor, AnswerPlaceholder placeholder, boolean useLength) {
+ public static void createGuardedBlocks(@NotNull final Editor editor, AnswerPlaceholder placeholder) {
Document document = editor.getDocument();
if (document instanceof DocumentImpl) {
DocumentImpl documentImpl = (DocumentImpl)document;
List blocks = documentImpl.getGuardedBlocks();
- if (useLength && !placeholder.isValid(document)) return;
+ if (!placeholder.isValid(document)) return;
int start = placeholder.getRealStartOffset(document);
- final int length = useLength ? placeholder.getLength() : placeholder.getPossibleAnswerLength();
+ final int length = placeholder.getRealLength();
int end = start + length;
if (start != 0) {
createGuardedBlock(editor, blocks, start - 1, start);
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduDocumentListener.java b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduDocumentListener.java
index 77e02bb15154..8e43bf57b26b 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduDocumentListener.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduDocumentListener.java
@@ -18,29 +18,19 @@ import java.util.List;
public class EduDocumentListener extends DocumentAdapter {
private final TaskFile myTaskFile;
private final boolean myTrackLength;
- private final boolean usePossibleAnswerLength;
private final List myAnswerPlaceholders = new ArrayList();
public EduDocumentListener(TaskFile taskFile) {
myTaskFile = taskFile;
myTrackLength = true;
- usePossibleAnswerLength = false;
}
public EduDocumentListener(TaskFile taskFile, boolean trackLength) {
myTaskFile = taskFile;
myTrackLength = trackLength;
- usePossibleAnswerLength = false;
}
- public EduDocumentListener(TaskFile taskFile, boolean trackLength, boolean usePossibleAnswerLength) {
- myTaskFile = taskFile;
- myTrackLength = trackLength;
- this.usePossibleAnswerLength = usePossibleAnswerLength;
- }
-
-
//remembering old end before document change because of problems
// with fragments containing "\n"
@Override
@@ -53,7 +43,7 @@ public class EduDocumentListener extends DocumentAdapter {
myAnswerPlaceholders.clear();
for (AnswerPlaceholder answerPlaceholder : myTaskFile.getAnswerPlaceholders()) {
int twStart = answerPlaceholder.getRealStartOffset(document);
- int length = usePossibleAnswerLength ? answerPlaceholder.getPossibleAnswerLength() : answerPlaceholder.getLength();
+ int length = answerPlaceholder.getRealLength();
int twEnd = twStart + length;
myAnswerPlaceholders.add(new AnswerPlaceholderWrapper(answerPlaceholder, twStart, twEnd));
}
@@ -85,7 +75,7 @@ public class EduDocumentListener extends DocumentAdapter {
int length = twEnd - twStart;
answerPlaceholder.setLine(line);
answerPlaceholder.setStart(start);
- if (usePossibleAnswerLength) {
+ if (!answerPlaceholder.getUseLength()) {
answerPlaceholder.setPossibleAnswer(document.getText(TextRange.create(twStart, twStart + length)));
}
else if (myTrackLength) {
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java
index 03c06d19b30d..a6062cb25339 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java
@@ -32,14 +32,19 @@ public class EduNames {
public static final String USER_TEST_OUTPUT = "output";
public static final String WINDOW_POSTFIX = "_window.";
public static final String WINDOWS_POSTFIX = "_windows";
+ public static final String ANSWERS_POSTFIX = "_answers";
public static final String USER_TESTS = "userTests";
public static final String TESTS_FILE = "tests.py";
public static final String TEST_HELPER = "test_helper.py";
public static final String SANDBOX_DIR = "Sandbox";
public static final String COURSE_META_FILE = "course.json";
+ public static final String STUDY = "Study";
public static String PYCHARM_ADDITIONAL = "PyCharm additional materials";
+ public static final String PYCHARM = "PyCharm";
+ public static String PLACEHOLDER = "Answer Placeholder";
+ public static String SRC = "src";
private EduNames() {
}
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduUtils.java
index 4b4870673a23..b095bc94815e 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduUtils.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduUtils.java
@@ -95,7 +95,7 @@ public class EduUtils {
fileWindows = taskDir.createChildData(taskFile, name);
printWriter = new PrintWriter(new FileOutputStream(fileWindows.getPath()));
for (AnswerPlaceholder answerPlaceholder : taskFile.getAnswerPlaceholders()) {
- int length = useLength ? answerPlaceholder.getLength() : answerPlaceholder.getPossibleAnswerLength();
+ int length = answerPlaceholder.getRealLength();
if (!answerPlaceholder.isValid(document, length)) {
printWriter.println("#educational_plugin_window = ");
continue;
@@ -192,6 +192,13 @@ public class EduUtils {
});
}
}, "Create Student File", "Create Student File");
+ createStudentDocument(project, taskFile, file, document);
+ }
+
+ public static void createStudentDocument(@NotNull Project project,
+ @NotNull TaskFile taskFile,
+ VirtualFile file,
+ final Document document) {
EduDocumentListener listener = new EduDocumentListener(taskFile, false);
document.addDocumentListener(listener);
taskFile.sortAnswerPlaceholders();
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/AnswerPlaceholder.java b/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/AnswerPlaceholder.java
index e086091d6d8c..72f2b422b7f8 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/AnswerPlaceholder.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/AnswerPlaceholder.java
@@ -25,6 +25,7 @@ public class AnswerPlaceholder {
private MyInitialState myInitialState;
private StudyStatus myStatus = StudyStatus.Uninitialized;
private boolean mySelected = false;
+ private boolean myUseLength = true;
@Transient private TaskFile myTaskFile;
@@ -45,6 +46,9 @@ public class AnswerPlaceholder {
myIndex = index;
}
+ /**
+ * in actions {@link AnswerPlaceholder#getRealLength()} should be used
+ */
public int getLength() {
return length;
}
@@ -138,6 +142,9 @@ public class AnswerPlaceholder {
line = myInitialState.myLine;
start = myInitialState.myStart;
length = myInitialState.myLength;
+ if (!getUseLength()) {
+ possibleAnswer = myTaskText;
+ }
}
public StudyStatus getStatus() {
@@ -156,6 +163,29 @@ public class AnswerPlaceholder {
mySelected = selected;
}
+ public void init() {
+ setInitialState(new MyInitialState(line, myTaskText.length(), start));
+ }
+
+ public boolean getUseLength() {
+ return myUseLength;
+ }
+
+ /**
+ * @return length or possible answer length
+ */
+ public int getRealLength() {
+ return myUseLength ? getLength() : getPossibleAnswerLength();
+ }
+
+ public void setUseLength(boolean useLength) {
+ myUseLength = useLength;
+ }
+
+ public void setInitialState(AnswerPlaceholder placeholder) {
+ setInitialState(new MyInitialState(placeholder.line, placeholder.length, placeholder.start));
+ }
+
public static class MyInitialState {
public int myLine = -1;
public int myLength = -1;
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/Course.java b/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/Course.java
index 5dfbebf0f609..e643d9470cc9 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/Course.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/Course.java
@@ -24,9 +24,14 @@ public class Course {
private boolean myUpToDate;
@Expose @SerializedName("language")
- private String myLanguage="Python";
+ private String myLanguage = "Python";
- private String courseType="PyCharm";
+ //this field is used to distinguish ordinary and CheckIO projects
+ //"PyCharm" is used here for historical reasons
+ private String courseType = EduNames.PYCHARM;
+
+ //this field is used to distinguish study and course creator modes
+ private String courseMode = EduNames.STUDY;
/**
* Initializes state of course
@@ -145,4 +150,12 @@ public class Course {
public void setCourseType(String courseType) {
this.courseType = courseType;
}
+
+ public String getCourseMode() {
+ return courseMode;
+ }
+
+ public void setCourseMode(String courseMode) {
+ this.courseMode = courseMode;
+ }
}
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/TaskFile.java b/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/TaskFile.java
index a235d9eb3a54..33e00d574325 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/TaskFile.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/TaskFile.java
@@ -95,7 +95,7 @@ public class TaskFile {
for (AnswerPlaceholder placeholder : myAnswerPlaceholders) {
if (placeholder.getLine() <= line) {
int realStartOffset = placeholder.getRealStartOffset(document);
- int placeholderLength = useAnswerLength ? placeholder.getPossibleAnswerLength() : placeholder.getLength();
+ int placeholderLength = placeholder.getRealLength();
final int length = placeholderLength > 0 ? placeholderLength : 0;
int endOffset = realStartOffset + length;
if (realStartOffset <= offset && offset <= endOffset) {
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/editor/StudyEditorFactoryListener.java b/python/educational-core/student/src/com/jetbrains/edu/learning/editor/StudyEditorFactoryListener.java
index 4678c7e0ba3e..8a9c17d0ef24 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/editor/StudyEditorFactoryListener.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/editor/StudyEditorFactoryListener.java
@@ -14,10 +14,13 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.problems.WolfTheProblemSolver;
-import com.jetbrains.edu.learning.core.EduDocumentListener;
-import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
-import com.jetbrains.edu.learning.courseFormat.TaskFile;
+import com.jetbrains.edu.learning.StudyTaskManager;
import com.jetbrains.edu.learning.StudyUtils;
+import com.jetbrains.edu.learning.core.EduDocumentListener;
+import com.jetbrains.edu.learning.core.EduNames;
+import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
+import com.jetbrains.edu.learning.courseFormat.Course;
+import com.jetbrains.edu.learning.courseFormat.TaskFile;
import com.jetbrains.edu.learning.navigation.StudyNavigator;
import com.jetbrains.edu.learning.ui.StudyToolWindowFactory;
import org.jetbrains.annotations.NotNull;
@@ -44,7 +47,7 @@ public class StudyEditorFactoryListener implements EditorFactoryListener {
return;
}
int startOffset = answerPlaceholder.getRealStartOffset(editor.getDocument());
- editor.getSelectionModel().setSelection(startOffset, startOffset + answerPlaceholder.getLength());
+ editor.getSelectionModel().setSelection(startOffset, startOffset + answerPlaceholder.getRealLength());
answerPlaceholder.setSelected(true);
}
}
@@ -57,6 +60,7 @@ public class StudyEditorFactoryListener implements EditorFactoryListener {
return;
}
+
final Document document = editor.getDocument();
final VirtualFile openedFile = FileDocumentManager.getInstance().getFile(document);
if (openedFile != null) {
@@ -68,11 +72,20 @@ public class StudyEditorFactoryListener implements EditorFactoryListener {
StudyUtils.updateToolWindows(project);
studyToolWindow.show(null);
}
+ Course course = StudyTaskManager.getInstance(project).getCourse();
+ if (course == null) {
+ return;
+ }
+
+ StudyEditor.addDocumentListener(document, new EduDocumentListener(taskFile, true));
+
if (!taskFile.getAnswerPlaceholders().isEmpty()) {
StudyNavigator.navigateToFirstAnswerPlaceholder(editor, taskFile);
- StudyEditor.addDocumentListener(document, new EduDocumentListener(taskFile));
+ boolean isStudyProject = EduNames.STUDY.equals(course.getCourseType());
StudyUtils.drawAllWindows(editor, taskFile);
- editor.addEditorMouseListener(new WindowSelectionListener(taskFile));
+ if (isStudyProject) {
+ editor.addEditorMouseListener(new WindowSelectionListener(taskFile));
+ }
}
}
}
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/projectView/StudyTreeStructureProvider.java b/python/educational-core/student/src/com/jetbrains/edu/learning/projectView/StudyTreeStructureProvider.java
index 6fd47eaece84..0a3a3e841feb 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/projectView/StudyTreeStructureProvider.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/projectView/StudyTreeStructureProvider.java
@@ -9,6 +9,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.jetbrains.edu.learning.core.EduNames;
+import com.jetbrains.edu.learning.courseFormat.Course;
import com.jetbrains.edu.learning.courseFormat.TaskFile;
import com.jetbrains.edu.learning.StudyTaskManager;
import com.jetbrains.edu.learning.StudyUtils;
@@ -24,7 +25,7 @@ public class StudyTreeStructureProvider implements TreeStructureProvider, DumbAw
public Collection modify(@NotNull AbstractTreeNode parent,
@NotNull Collection children,
ViewSettings settings) {
- if (!isCourseBasedProject(parent)) {
+ if (!needModify(parent)) {
return children;
}
Collection nodes = new ArrayList<>();
@@ -78,21 +79,23 @@ public class StudyTreeStructureProvider implements TreeStructureProvider, DumbAw
if (!StudyTaskManager.getInstance(project).isInvisibleFile(virtualFile.getPath())) {
String fileName = virtualFile.getName();
if (!fileName.contains(EduNames.WINDOW_POSTFIX) && !fileName.contains(EduNames.WINDOWS_POSTFIX)
- && !StudyUtils.isTestsFile(project, fileName) && !EduNames.TASK_HTML.equals(fileName) && !fileName.contains(".answer")) {
+ && !StudyUtils.isTestsFile(project, fileName) && !EduNames.TASK_HTML.equals(fileName)) {
nodes.add(node);
}
}
}
- protected boolean isCourseBasedProject(@NotNull final AbstractTreeNode parent) {
+ protected boolean needModify(@NotNull final AbstractTreeNode parent) {
final Project project = parent.getProject();
- if (project != null) {
- final StudyTaskManager studyTaskManager = StudyTaskManager.getInstance(project);
- if (studyTaskManager.getCourse() == null) {
- return false;
- }
+ if (project == null) {
+ return false;
}
- return true;
+ final StudyTaskManager studyTaskManager = StudyTaskManager.getInstance(project);
+ Course course = studyTaskManager.getCourse();
+ if (course == null) {
+ return false;
+ }
+ return EduNames.STUDY.equals(course.getCourseMode());
}
@Nullable
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyJavaFxToolWindow.java b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyJavaFxToolWindow.java
index 98bec3d50589..058bd633a29b 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyJavaFxToolWindow.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyJavaFxToolWindow.java
@@ -29,10 +29,9 @@ public class StudyJavaFxToolWindow extends StudyToolWindow {
}
@Override
- public JComponent createTaskInfoPanel(String taskText, Project project) {
+ public JComponent createTaskInfoPanel(Project project) {
myBrowserWindow = new StudyBrowserWindow(true, false);
myBrowserWindow.addBackAndOpenButtons();
- myBrowserWindow.loadContent(taskText, StudyUtils.getConfigurator(project));
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
panel.add(myBrowserWindow.getPanel());
@@ -40,7 +39,7 @@ public class StudyJavaFxToolWindow extends StudyToolWindow {
}
@Override
- public void setTaskText(String text) {
+ public void setText(String text) {
StudyPluginConfigurator configurator = StudyUtils.getConfigurator(ProjectUtil.guessCurrentProject(this));
myBrowserWindow.loadContent(text, configurator);
}
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudySwingToolWindow.java b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudySwingToolWindow.java
index ef66218d3398..ebaff662ecb8 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudySwingToolWindow.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudySwingToolWindow.java
@@ -37,7 +37,7 @@ public class StudySwingToolWindow extends StudyToolWindow {
}
@Override
- public JComponent createTaskInfoPanel(String taskText, Project project) {
+ public JComponent createTaskInfoPanel(Project project) {
myTaskTextPane = new JTextPane();
final JBScrollPane scrollPane = new JBScrollPane(myTaskTextPane);
myTaskTextPane.setContentType(new HTMLEditorKit().getContentType());
@@ -57,12 +57,11 @@ public class StudySwingToolWindow extends StudyToolWindow {
myTaskTextPane.setBackground(EditorColorsManager.getInstance().getGlobalScheme().getDefaultBackground());
}
myTaskTextPane.setBorder(new EmptyBorder(20, 20, 0, 10));
- myTaskTextPane.setText(taskText);
myTaskTextPane.addHyperlinkListener(BrowserHyperlinkListener.INSTANCE);
return scrollPane;
}
- public void setTaskText(String text) {
+ public void setText(String text) {
myTaskTextPane.setText(text);
}
}
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindow.java b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindow.java
index 7d24d27e6783..feb06b72159a 100644
--- a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindow.java
+++ b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindow.java
@@ -15,23 +15,27 @@
*/
package com.jetbrains.edu.learning.ui;
+import com.intellij.ide.browsers.WebBrowserManager;
import com.intellij.openapi.Disposable;
-import com.intellij.openapi.actionSystem.ActionManager;
-import com.intellij.openapi.actionSystem.ActionToolbar;
-import com.intellij.openapi.actionSystem.DataProvider;
-import com.intellij.openapi.actionSystem.DefaultActionGroup;
+import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.EditorFactory;
+import com.intellij.openapi.editor.ex.EditorEx;
+import com.intellij.openapi.extensions.Extensions;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditorManagerListener;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.SimpleToolWindowPanel;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.JBCardLayout;
import com.intellij.ui.OnePixelSplitter;
import com.intellij.util.ui.JBUI;
-import com.jetbrains.edu.learning.StudyBasePluginConfigurator;
-import com.jetbrains.edu.learning.StudyPluginConfigurator;
-import com.jetbrains.edu.learning.StudyTaskManager;
-import com.jetbrains.edu.learning.StudyUtils;
+import com.jetbrains.edu.learning.*;
+import com.jetbrains.edu.learning.core.EduNames;
import com.jetbrains.edu.learning.courseFormat.Course;
+import com.jetbrains.edu.learning.courseFormat.TaskFile;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
@@ -41,6 +45,7 @@ import java.util.Map;
public abstract class StudyToolWindow extends SimpleToolWindowPanel implements DataProvider, Disposable {
private static final Logger LOG = Logger.getInstance(StudyToolWindow.class);
private static final String TASK_INFO_ID = "taskInfo";
+ private static final String EMPTY_TASK_TEXT = "Please, open any task to see task description";
private final JBCardLayout myCardLayout;
private final JPanel myContentPanel;
private final OnePixelSplitter mySplitPane;
@@ -49,17 +54,17 @@ public abstract class StudyToolWindow extends SimpleToolWindowPanel implements D
super(true, true);
myCardLayout = new JBCardLayout();
myContentPanel = new JPanel(myCardLayout);
- mySplitPane = new OnePixelSplitter(myVertical=true);
+ mySplitPane = new OnePixelSplitter(myVertical = true);
}
public void init(Project project) {
String taskText = StudyUtils.getTaskText(project);
if (taskText == null) return;
- JPanel toolbarPanel = createToolbarPanel(project);
+ JPanel toolbarPanel = createToolbarPanel(getActionGroup(project));
setToolbar(toolbarPanel);
- myContentPanel.add(TASK_INFO_ID, createTaskInfoPanel(taskText, project));
+ myContentPanel.add(TASK_INFO_ID, createTaskInfoPanel(project));
mySplitPane.setFirstComponent(myContentPanel);
addAdditionalPanels(project);
myCardLayout.show(myContentPanel, TASK_INFO_ID);
@@ -71,6 +76,17 @@ public abstract class StudyToolWindow extends SimpleToolWindowPanel implements D
final FileEditorManagerListener listener = configurator.getFileEditorManagerListener(project, this);
project.getMessageBus().connect().subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, listener);
}
+
+ if (StudyTaskManager.getInstance(project).isTurnEditingMode() || StudyTaskManager.getInstance(project).getToolWindowMode() == StudyToolWindowMode.EDITING) {
+ TaskFile file = StudyUtils.getSelectedTaskFile(project);
+ if (file != null) {
+ VirtualFile taskDir = file.getTask().getTaskDir(project);
+ setTaskText(taskText, taskDir, project);
+
+ }
+ } else {
+ setTaskText(taskText, null, project);
+ }
}
private void addAdditionalPanels(Project project) {
@@ -85,7 +101,7 @@ public abstract class StudyToolWindow extends SimpleToolWindowPanel implements D
public void dispose() {
}
-
+
//used in checkiO plugin.
@SuppressWarnings("unused")
public void showPanelById(@NotNull final String panelId) {
@@ -117,24 +133,25 @@ public abstract class StudyToolWindow extends SimpleToolWindowPanel implements D
}
- public abstract JComponent createTaskInfoPanel(String taskText, Project project);
-
- private static JPanel createToolbarPanel(@NotNull final Project project) {
- final DefaultActionGroup group = getActionGroup(project);
+ public abstract JComponent createTaskInfoPanel(Project project);
+ public static JPanel createToolbarPanel(ActionGroup group) {
final ActionToolbar actionToolBar = ActionManager.getInstance().createActionToolbar("Study", group, true);
return JBUI.Panels.simplePanel(actionToolBar.getComponent());
}
- private static DefaultActionGroup getActionGroup(@NotNull final Project project) {
+ public static DefaultActionGroup getActionGroup(@NotNull final Project project) {
+ DefaultActionGroup group = new DefaultActionGroup();
Course course = StudyTaskManager.getInstance(project).getCourse();
if (course == null) {
LOG.warn("Course is null");
- return new DefaultActionGroup();
+ return group;
}
StudyPluginConfigurator configurator = StudyUtils.getConfigurator(project);
if (configurator != null) {
- return configurator.getActionGroup(project);
+ group.addAll(configurator.getActionGroup(project));
+ addAdditionalActions(group);
+ return group;
}
else {
LOG.warn("No configurator is provided for plugin");
@@ -142,5 +159,68 @@ public abstract class StudyToolWindow extends SimpleToolWindowPanel implements D
}
}
- public abstract void setTaskText(String text) ;
+ private static void addAdditionalActions(DefaultActionGroup group) {
+ StudyActionsProvider[] providers = Extensions.getExtensions(StudyActionsProvider.EP_NAME);
+ for (StudyActionsProvider provider : providers) {
+ group.addAll(provider.getActions());
+ }
+ }
+
+ public void setTaskText(String text, VirtualFile taskDirectory, Project project) {
+ if (StudyTaskManager.getInstance(project).isTurnEditingMode()) {
+ if (taskDirectory == null) {
+ LOG.info("Failed to enter editing mode for StudyToolWindow");
+ return;
+ }
+ VirtualFile taskTextFile = taskDirectory.findChild(EduNames.TASK_HTML);
+ enterEditingMode(taskTextFile, project);
+ StudyTaskManager.getInstance(project).setTurnEditingMode(false);
+ }
+ else {
+ setText(text);
+ }
+ }
+
+ protected abstract void setText(String text);
+
+ public void setEmptyText(@NotNull Project project) {
+ if (StudyTaskManager.getInstance(project).getToolWindowMode() == StudyToolWindowMode.EDITING) {
+ mySplitPane.setFirstComponent(myContentPanel);
+ StudyTaskManager.getInstance(project).setTurnEditingMode(true);
+ }
+ setTaskText(EMPTY_TASK_TEXT, null, project);
+ }
+
+ public enum StudyToolWindowMode {
+ TEXT, EDITING
+ }
+
+
+ public void enterEditingMode(VirtualFile taskFile, Project project) {
+ final EditorFactory factory = EditorFactory.getInstance();
+ Document document = FileDocumentManager.getInstance().getDocument(taskFile);
+ if (document == null) {
+ return;
+ }
+ WebBrowserManager.getInstance().setShowBrowserHover(false);
+ final EditorEx createdEditor = (EditorEx)factory.createEditor(document, project, taskFile, false);
+ Disposer.register(project, new Disposable() {
+ public void dispose() {
+ factory.releaseEditor(createdEditor);
+ }
+ });
+ JComponent editorComponent = createdEditor.getComponent();
+ mySplitPane.setFirstComponent(editorComponent);
+ mySplitPane.repaint();
+
+ StudyTaskManager.getInstance(project).setToolWindowMode(StudyToolWindowMode.EDITING);
+ }
+
+
+ public void leaveEditingMode(Project project) {
+ WebBrowserManager.getInstance().setShowBrowserHover(true);
+ mySplitPane.setFirstComponent(myContentPanel);
+ StudyTaskManager.getInstance(project).setToolWindowMode(StudyToolWindowMode.TEXT);
+ StudyUtils.updateStudyToolWindow(project);
+ }
}
diff --git a/python/educational-core/student/student.iml b/python/educational-core/student/student.iml
index e16fc06deca8..8702c7849f52 100644
--- a/python/educational-core/student/student.iml
+++ b/python/educational-core/student/student.iml
@@ -23,5 +23,6 @@
+
\ No newline at end of file
diff --git a/python/educational-python/course-creator-python/resources/META-INF/plugin.xml b/python/educational-python/course-creator-python/resources/META-INF/plugin.xml
index e87961c59b40..2399560d07b7 100644
--- a/python/educational-python/course-creator-python/resources/META-INF/plugin.xml
+++ b/python/educational-python/course-creator-python/resources/META-INF/plugin.xml
@@ -21,27 +21,16 @@
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCLanguageManager.java b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCLanguageManager.java
index f66ecff6ddd3..8628bbdecc41 100644
--- a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCLanguageManager.java
+++ b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCLanguageManager.java
@@ -3,6 +3,7 @@ package com.jetbrains.edu.coursecreator;
import com.intellij.ide.fileTemplates.FileTemplate;
import com.intellij.ide.fileTemplates.FileTemplateManager;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
import com.jetbrains.edu.learning.core.EduNames;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -40,4 +41,9 @@ public class PyCCLanguageManager implements CCLanguageManager {
private static FileTemplate getInternalTemplateByName(@NotNull final Project project, String name) {
return FileTemplateManager.getInstance(project).getInternalTemplate(name);
}
+
+ @Override
+ public boolean isTestFile(VirtualFile file) {
+ return EduNames.TESTS_FILE.equals(file.getName());
+ }
}
diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCProjectGenerator.java b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCProjectGenerator.java
index ebffadfea5d2..4af7914d2da4 100644
--- a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCProjectGenerator.java
+++ b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCProjectGenerator.java
@@ -6,19 +6,25 @@ import com.intellij.facet.ui.ValidationResult;
import com.intellij.ide.fileTemplates.FileTemplate;
import com.intellij.ide.fileTemplates.FileTemplateManager;
import com.intellij.ide.fileTemplates.FileTemplateUtil;
+import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.platform.DirectoryProjectGenerator;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiManager;
-import com.jetbrains.edu.learning.courseFormat.Course;
import com.jetbrains.edu.coursecreator.actions.CCCreateLesson;
import com.jetbrains.edu.coursecreator.actions.CCCreateTask;
import com.jetbrains.edu.coursecreator.ui.CCNewProjectPanel;
+import com.jetbrains.edu.learning.StudyProjectComponent;
+import com.jetbrains.edu.learning.StudyTaskManager;
+import com.jetbrains.edu.learning.core.EduNames;
+import com.jetbrains.edu.learning.courseFormat.Course;
+import com.jetbrains.python.PythonLanguage;
import com.jetbrains.python.newProject.PythonProjectGenerator;
import icons.CourseCreatorPythonIcons;
import org.jetbrains.annotations.Nls;
@@ -26,6 +32,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
+import java.io.File;
public class PyCCProjectGenerator extends PythonProjectGenerator implements DirectoryProjectGenerator {
@@ -55,25 +62,16 @@ public class PyCCProjectGenerator extends PythonProjectGenerator implements Dire
public static void generateProject(@NotNull final Project project, @NotNull final VirtualFile baseDir,
@NotNull final String name, @NotNull final String[] authors,
@NotNull final String description) {
- final CCProjectService service = CCProjectService.getInstance(project);
- final Course course = new Course();
- course.setName(name);
- course.setAuthors(authors);
- course.setDescription(description);
- course.setLanguage("Python");
- service.setCourse(course);
+ final Course course = getCourse(project, name, authors, description);
final PsiDirectory projectDir = PsiManager.getInstance(project).findDirectory(baseDir);
if (projectDir == null) return;
new WriteCommandAction.Simple(project) {
@Override
protected void run() throws Throwable {
- final FileTemplate template = FileTemplateManager.getInstance(project).getInternalTemplate("test_helper");
- try {
- FileTemplateUtil.createFromTemplate(template, "test_helper.py", null, projectDir);
- }
- catch (Exception ignored) {
- }
+
+ createTestHelper(project, projectDir);
+
PsiDirectory lessonDir = new CCCreateLesson().createItem(null, project, projectDir, course);
if (lessonDir == null) {
LOG.error("Failed to create lesson");
@@ -84,6 +82,33 @@ public class PyCCProjectGenerator extends PythonProjectGenerator implements Dire
}.execute();
}
+ private static void createTestHelper(@NotNull Project project, PsiDirectory projectDir) {
+ final FileTemplate template = FileTemplateManager.getInstance(project).getInternalTemplate(FileUtil.getNameWithoutExtension(EduNames.TEST_HELPER));
+ try {
+ FileTemplateUtil.createFromTemplate(template, EduNames.TEST_HELPER, null, projectDir);
+ }
+ catch (Exception ignored) {
+ }
+ }
+
+ @NotNull
+ private static Course getCourse(@NotNull Project project, @NotNull String name, @NotNull String[] authors, @NotNull String description) {
+ final Course course = new Course();
+ course.setName(name);
+ course.setAuthors(authors);
+ course.setDescription(description);
+ course.setLanguage(PythonLanguage.getInstance().getID());
+ course.setCourseMode(CCUtils.COURSE_MODE);
+
+ File coursesDir = new File(PathManager.getConfigPath(), "courses");
+ File courseDir = new File(coursesDir, name + "-" + project.getName());
+ course.setCourseDirectory(courseDir.getPath());
+
+ StudyTaskManager.getInstance(project).setCourse(course);
+ StudyProjectComponent.getInstance(project).registerStudyToolWindow(course);
+ return course;
+ }
+
@NotNull
@Override
public ValidationResult validate(@NotNull String s) {
diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCReferenceResolveProvider.java b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCReferenceResolveProvider.java
index 95cf9321df3b..e1bb8ee267d6 100644
--- a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCReferenceResolveProvider.java
+++ b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCReferenceResolveProvider.java
@@ -1,5 +1,6 @@
package com.jetbrains.edu.coursecreator;
+import com.intellij.openapi.project.Project;
import com.jetbrains.python.edu.PyEduUtils;
import com.jetbrains.python.psi.PyQualifiedExpression;
import com.jetbrains.python.psi.resolve.PyReferenceResolveProvider;
@@ -13,7 +14,8 @@ public class PyCCReferenceResolveProvider implements PyReferenceResolveProvider
@NotNull
@Override
public List resolveName(@NotNull final PyQualifiedExpression element) {
- if (CCProjectService.getInstance(element.getProject()).getCourse() == null) {
+ Project project = element.getProject();
+ if (!CCUtils.isCourseCreator(project)) {
return Collections.emptyList();
}
return PyEduUtils.getResolveResultFromContainingDirectory(element);
diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCRunTests.java b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCRunTests.java
deleted file mode 100644
index 5af7f8b164e8..000000000000
--- a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCRunTests.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.jetbrains.edu.coursecreator;
-
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.project.Project;
-import com.jetbrains.edu.coursecreator.actions.PyCCRunTestsAction;
-import com.jetbrains.python.edu.PyExecuteFileExtensionPoint;
-import org.jetbrains.annotations.NotNull;
-
-public class PyCCRunTests implements PyExecuteFileExtensionPoint {
-
- @NotNull
- public AnAction getRunAction() {
- return new PyCCRunTestsAction();
- }
-
- @Override
- public boolean accept(Project project) {
- return CCProjectService.getInstance(project).getCourse() != null;
- }
-}
\ No newline at end of file
diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/actions/PyCCRunTestsAction.java b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/actions/PyCCRunTestsAction.java
deleted file mode 100644
index ebda0f8976f1..000000000000
--- a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/actions/PyCCRunTestsAction.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2000-2014 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.jetbrains.edu.coursecreator.actions;
-
-import com.intellij.execution.Executor;
-import com.intellij.execution.ProgramRunnerUtil;
-import com.intellij.execution.RunManager;
-import com.intellij.execution.RunnerAndConfigurationSettings;
-import com.intellij.execution.configurations.ConfigurationFactory;
-import com.intellij.execution.executors.DefaultRunExecutor;
-import com.intellij.ide.projectView.ProjectView;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.openapi.vfs.VirtualFileManager;
-import com.intellij.util.PathUtil;
-import com.jetbrains.python.run.PythonConfigurationType;
-import com.jetbrains.python.run.PythonRunConfiguration;
-import org.jetbrains.annotations.NotNull;
-
-public class PyCCRunTestsAction extends CCRunTestsAction {
-
- @Override
- protected void executeTests(@NotNull final Project project,
- @NotNull final VirtualFile virtualFile,
- @NotNull final VirtualFile taskDir,
- @NotNull final VirtualFile testFile) {
- final ConfigurationFactory factory = PythonConfigurationType.getInstance().getConfigurationFactories()[0];
- final RunnerAndConfigurationSettings settings =
- RunManager.getInstance(project).createRunConfiguration("test", factory);
-
- final PythonRunConfiguration configuration = (PythonRunConfiguration)settings.getConfiguration();
- configuration.setScriptName(testFile.getPath());
- configuration.setWorkingDirectory(taskDir.getPath());
- String taskFileName = virtualFile.getName();
- VirtualFile userFile = taskDir.findChild(taskFileName);
- if (userFile == null) {
- return;
- }
- VirtualFile ideaDir = project.getBaseDir().findChild(".idea");
- if (ideaDir == null) {
- return;
- }
- VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
- ProjectView.getInstance(project).refresh();
- configuration.setScriptParameters(PathUtil.toSystemDependentName(project.getBasePath()) + " " + PathUtil.toSystemDependentName(userFile.getPath()));
- Executor executor = DefaultRunExecutor.getRunExecutorInstance();
- ProgramRunnerUtil.executeConfiguration(project, settings, executor);
- }
-}
diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCCommandLineState.java b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCCommandLineState.java
new file mode 100644
index 000000000000..0bde8098b28f
--- /dev/null
+++ b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCCommandLineState.java
@@ -0,0 +1,89 @@
+package com.jetbrains.edu.coursecreator.run;
+
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.ExecutionResult;
+import com.intellij.execution.Executor;
+import com.intellij.execution.configurations.GeneralCommandLine;
+import com.intellij.execution.configurations.ParamsGroup;
+import com.intellij.execution.process.ProcessAdapter;
+import com.intellij.execution.process.ProcessEvent;
+import com.intellij.execution.process.ProcessHandler;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.edu.coursecreator.CCUtils;
+import com.jetbrains.edu.learning.StudyTaskManager;
+import com.jetbrains.edu.learning.StudyUtils;
+import com.jetbrains.edu.learning.checker.StudyCheckUtils;
+import com.jetbrains.edu.learning.core.EduNames;
+import com.jetbrains.edu.learning.core.EduUtils;
+import com.jetbrains.edu.learning.courseFormat.Course;
+import com.jetbrains.edu.learning.courseFormat.Task;
+import com.jetbrains.python.run.CommandLinePatcher;
+import com.jetbrains.python.run.PythonCommandLineState;
+import org.jetbrains.annotations.NotNull;
+
+public class PyCCCommandLineState extends PythonCommandLineState {
+ private final PyCCRunTestConfiguration myRunConfiguration;
+ private final VirtualFile myTaskDir;
+ private final Task myTask;
+
+ public PyCCCommandLineState(PyCCRunTestConfiguration runConfiguration,
+ ExecutionEnvironment env) {
+ super(runConfiguration, env);
+ myRunConfiguration = runConfiguration;
+
+ VirtualFile testsFile = LocalFileSystem.getInstance().findFileByPath(myRunConfiguration.getPathToTest());
+ assert testsFile != null;
+ myTaskDir = StudyUtils.getTaskDir(testsFile);
+ assert myTaskDir != null;
+ myTask = StudyUtils.getTask(myRunConfiguration.getProject(), myTaskDir);
+ assert myTask != null;
+ }
+
+ @Override
+ protected void buildCommandLineParameters(GeneralCommandLine commandLine) {
+ ParamsGroup group = commandLine.getParametersList().getParamsGroup(GROUP_SCRIPT);
+ assert group != null;
+
+ Project project = myRunConfiguration.getProject();
+ Course course = StudyTaskManager.getInstance(project).getCourse();
+ assert course != null;
+
+ group.addParameter(myRunConfiguration.getPathToTest());
+ group.addParameter(course.getCourseDirectory());
+
+ group.addParameter(getFirstTaskFilePath());
+ }
+
+ @NotNull
+ private String getFirstTaskFilePath() {
+ String firstTaskFileName = StudyUtils.getFirst(myTask.getTaskFiles().keySet());
+ return myTaskDir.findChild(EduNames.SRC) != null ?
+ FileUtil.join(myTaskDir.getPath(), EduNames.SRC, firstTaskFileName) :
+ FileUtil.join(myTaskDir.getPath(), firstTaskFileName);
+ }
+
+ @Override
+ public ExecutionResult execute(Executor executor, CommandLinePatcher... patchers) throws ExecutionException {
+ CCUtils.createResources(myRunConfiguration.getProject(), myTask, myTaskDir);
+ ApplicationManager.getApplication().runWriteAction(() -> StudyCheckUtils.flushWindows(myTask, myTaskDir));
+
+ return super.execute(executor, patchers);
+ }
+
+ @Override
+ protected ProcessHandler doCreateProcess(GeneralCommandLine commandLine) throws ExecutionException {
+ ProcessHandler handler = super.doCreateProcess(commandLine);
+ handler.addProcessListener(new ProcessAdapter() {
+ @Override
+ public void processTerminated(ProcessEvent event) {
+ ApplicationManager.getApplication().invokeLater(() -> EduUtils.deleteWindowDescriptions(myTask, myTaskDir));
+ }
+ });
+ return handler;
+ }
+}
diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestConfiguration.java b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestConfiguration.java
new file mode 100644
index 000000000000..aca074e73274
--- /dev/null
+++ b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestConfiguration.java
@@ -0,0 +1,80 @@
+package com.jetbrains.edu.coursecreator.run;
+
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.Executor;
+import com.intellij.execution.configurations.ConfigurationFactory;
+import com.intellij.execution.configurations.RunProfileState;
+import com.intellij.execution.configurations.RuntimeConfigurationException;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.openapi.options.SettingsEditor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.JDOMExternalizerUtil;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.edu.learning.StudyUtils;
+import com.jetbrains.python.run.AbstractPythonRunConfiguration;
+import org.jdom.Element;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+class PyCCRunTestConfiguration extends AbstractPythonRunConfiguration {
+
+ public static final String PATH_ATTR = "studyTest";
+ private Project myProject;
+ private String myPathToTest;
+
+ public PyCCRunTestConfiguration(Project project, ConfigurationFactory factory) {
+ super(project, factory);
+ myProject = project;
+ }
+
+ @Nullable
+ @Override
+ public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment environment) throws ExecutionException {
+ return new PyCCCommandLineState(this, environment);
+ }
+
+ @Override
+ protected SettingsEditor createConfigurationEditor() {
+ return new PyCCSettingsEditor(myProject);
+ }
+
+ public String getPathToTest() {
+ return myPathToTest;
+ }
+
+ public void setPathToTest(String pathToTest) {
+ myPathToTest = pathToTest;
+ }
+
+ @Override
+ public void readExternal(Element element) throws InvalidDataException {
+ super.readExternal(element);
+ myPathToTest = JDOMExternalizerUtil.readField(element, PATH_ATTR);
+ }
+
+ @Override
+ public void writeExternal(Element element) throws WriteExternalException {
+ super.writeExternal(element);
+ JDOMExternalizerUtil.writeField(element, PATH_ATTR, myPathToTest);
+ }
+
+ @Override
+ public void checkConfiguration() throws RuntimeConfigurationException {
+ super.checkConfiguration();
+ String message = "Select valid path to the file with tests";
+ VirtualFile testsFile = LocalFileSystem.getInstance().findFileByPath(myPathToTest);
+ if (testsFile == null) {
+ throw new RuntimeConfigurationException(message);
+ }
+ VirtualFile taskDir = StudyUtils.getTaskDir(testsFile);
+ if (taskDir == null) {
+ throw new RuntimeConfigurationException(message);
+ }
+ if (StudyUtils.getTask(myProject, taskDir) == null) {
+ throw new RuntimeConfigurationException(message);
+ }
+ }
+}
diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationFactory.java b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationFactory.java
new file mode 100644
index 000000000000..1d2de895d0a2
--- /dev/null
+++ b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationFactory.java
@@ -0,0 +1,19 @@
+package com.jetbrains.edu.coursecreator.run;
+
+import com.intellij.execution.configurations.ConfigurationFactory;
+import com.intellij.execution.configurations.ConfigurationType;
+import com.intellij.execution.configurations.RunConfiguration;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.NotNull;
+
+public class PyCCRunTestsConfigurationFactory extends ConfigurationFactory {
+ protected PyCCRunTestsConfigurationFactory(@NotNull ConfigurationType type) {
+ super(type);
+ }
+
+ @NotNull
+ @Override
+ public RunConfiguration createTemplateConfiguration(@NotNull Project project) {
+ return new PyCCRunTestConfiguration(project, this);
+ }
+}
diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationProducer.java b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationProducer.java
new file mode 100644
index 000000000000..53ca0c996cc2
--- /dev/null
+++ b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationProducer.java
@@ -0,0 +1,94 @@
+package com.jetbrains.edu.coursecreator.run;
+
+import com.intellij.execution.Location;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.execution.actions.RunConfigurationProducer;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Ref;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiElement;
+import com.jetbrains.edu.coursecreator.CCUtils;
+import com.jetbrains.edu.learning.StudyUtils;
+import com.jetbrains.edu.learning.core.EduNames;
+import com.jetbrains.edu.learning.courseFormat.Task;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class PyCCRunTestsConfigurationProducer extends RunConfigurationProducer {
+ protected PyCCRunTestsConfigurationProducer() {
+ super(PyCCRunTestsConfigurationType.getInstance());
+ }
+
+ @Override
+ protected boolean setupConfigurationFromContext(PyCCRunTestConfiguration configuration,
+ ConfigurationContext context,
+ Ref sourceElement) {
+ Project project = context.getProject();
+ if (!CCUtils.isCourseCreator(project)) {
+ return false;
+ }
+
+ String testsPath = getTestPath(context);
+ if (testsPath == null) {
+ return false;
+ }
+ VirtualFile testsFile = LocalFileSystem.getInstance().findFileByPath(testsPath);
+ if (testsFile == null) {
+ return false;
+ }
+
+ String generatedName = generateName(testsFile, project);
+ if (generatedName == null) {
+ return false;
+ }
+
+ configuration.setPathToTest(testsPath);
+ configuration.setName(generatedName);
+ return true;
+ }
+
+ @Nullable
+ private static String generateName(@NotNull VirtualFile testsFile, @NotNull Project project) {
+ VirtualFile taskDir = StudyUtils.getTaskDir(testsFile);
+ if (taskDir == null) {
+ return null;
+ }
+ Task task = StudyUtils.getTask(project, taskDir);
+ if (task == null) {
+ return null;
+ }
+ return task.getLesson().getName() + "/" + task.getName();
+ }
+
+ @Nullable
+ private static String getTestPath(@NotNull ConfigurationContext context) {
+ Location location = context.getLocation();
+ if (location == null) {
+ return null;
+ }
+ VirtualFile file = location.getVirtualFile();
+ if (file == null) {
+ return null;
+ }
+ VirtualFile taskDir = StudyUtils.getTaskDir(file);
+ if (taskDir == null) {
+ return null;
+ }
+
+ String testsPath = taskDir.findChild(EduNames.SRC) != null ?
+ FileUtil.join(taskDir.getPath(), EduNames.SRC, EduNames.TESTS_FILE) :
+ FileUtil.join(taskDir.getPath(), EduNames.TESTS_FILE);
+ return file.getPath().equals(testsPath) ? testsPath : null;
+ }
+
+ @Override
+ public boolean isConfigurationFromContext(PyCCRunTestConfiguration configuration, ConfigurationContext context) {
+ String path = getTestPath(context);
+ if (path == null) {
+ return false;
+ }
+ return path.equals(configuration.getPathToTest());
+ }
+}
diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationType.java b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationType.java
new file mode 100644
index 000000000000..ac05cf1d8ca4
--- /dev/null
+++ b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationType.java
@@ -0,0 +1,41 @@
+package com.jetbrains.edu.coursecreator.run;
+
+import com.intellij.execution.configurations.ConfigurationFactory;
+import com.intellij.execution.configurations.ConfigurationType;
+import com.intellij.execution.configurations.ConfigurationTypeUtil;
+import com.intellij.icons.AllIcons;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+
+public class PyCCRunTestsConfigurationType implements ConfigurationType {
+ @Override
+ public String getDisplayName() {
+ return "Run Study Tests";
+ }
+
+ @Override
+ public String getConfigurationTypeDescription() {
+ return "Study Test Runner";
+ }
+
+ @Override
+ public Icon getIcon() {
+ return AllIcons.Actions.Lightning;
+ }
+
+ @NotNull
+ @Override
+ public String getId() {
+ return "ccruntests";
+ }
+
+ @Override
+ public ConfigurationFactory[] getConfigurationFactories() {
+ return new ConfigurationFactory[]{new PyCCRunTestsConfigurationFactory(this)};
+ }
+
+ public static PyCCRunTestsConfigurationType getInstance() {
+ return ConfigurationTypeUtil.findConfigurationType(PyCCRunTestsConfigurationType.class);
+ }
+}
diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCSettingEditor.form b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCSettingEditor.form
new file mode 100644
index 000000000000..c84b034ed12f
--- /dev/null
+++ b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCSettingEditor.form
@@ -0,0 +1,34 @@
+
+
diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCSettingsEditor.java b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCSettingsEditor.java
new file mode 100644
index 000000000000..806f6a02ad5e
--- /dev/null
+++ b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCSettingsEditor.java
@@ -0,0 +1,69 @@
+package com.jetbrains.edu.coursecreator.run;
+
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.openapi.options.SettingsEditor;
+import com.intellij.openapi.project.Project;
+import com.jetbrains.python.run.AbstractPyCommonOptionsForm;
+import com.jetbrains.python.run.AbstractPythonRunConfiguration;
+import com.jetbrains.python.run.PyCommonOptionsFormData;
+import com.jetbrains.python.run.PyCommonOptionsFormFactory;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.List;
+
+public class PyCCSettingsEditor extends SettingsEditor {
+ private AbstractPyCommonOptionsForm myForm;
+ private Project myProject;
+ private JTextField myPathToTestFileField;
+ private JPanel myPanel;
+
+ public PyCCSettingsEditor(Project project) {
+ myProject = project;
+ }
+
+ @Override
+ protected void resetEditorFrom(PyCCRunTestConfiguration s) {
+ AbstractPythonRunConfiguration.copyParams(s, myForm);
+ myPathToTestFileField.setText(s.getPathToTest());
+ }
+
+ @Override
+ protected void applyEditorTo(PyCCRunTestConfiguration s) throws ConfigurationException {
+ AbstractPythonRunConfiguration.copyParams(myForm, s);
+ s.setPathToTest(myPathToTestFileField.getText());
+ }
+
+ @NotNull
+ @Override
+ protected JComponent createEditor() {
+ final JPanel mainPanel = new JPanel(new BorderLayout());
+ mainPanel.add(myPanel, BorderLayout.NORTH);
+ myForm = createEnvPanel();
+ mainPanel.add(myForm.getMainPanel(), BorderLayout.SOUTH);
+ return mainPanel;
+ }
+
+
+ @NotNull
+ private AbstractPyCommonOptionsForm createEnvPanel() {
+ return PyCommonOptionsFormFactory.getInstance().createForm(new PyCommonOptionsFormData() {
+ @Override
+ public Project getProject() {
+ return myProject;
+ }
+
+ @Override
+ public List getValidModules() {
+ return AbstractPythonRunConfiguration.getValidModules(myProject);
+ }
+
+ @Override
+ public boolean showConfigureInterpretersLink() {
+ return false;
+ }
+ });
+ }
+}
diff --git a/python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyCheckAction.java b/python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyCheckAction.java
index 43f5fc5645f4..fdb110718b34 100644
--- a/python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyCheckAction.java
+++ b/python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyCheckAction.java
@@ -16,6 +16,7 @@ import com.jetbrains.edu.learning.checker.StudyCheckTask;
import com.jetbrains.edu.learning.checker.StudyCheckUtils;
import com.jetbrains.edu.learning.checker.StudyTestRunner;
import com.jetbrains.edu.learning.checker.StudyTestsOutputParser;
+import com.jetbrains.edu.learning.core.EduNames;
import com.jetbrains.edu.learning.courseFormat.StudyStatus;
import com.jetbrains.edu.learning.courseFormat.Task;
import com.jetbrains.edu.learning.courseFormat.TaskFile;
@@ -103,9 +104,11 @@ public class PyStudyCheckAction extends StudyCheckAction {
myTaskManger.setStatus(taskFile, StudyStatus.Failed);
continue;
}
- CommandProcessor.getInstance().runUndoTransparentAction(() -> ApplicationManager.getApplication().runWriteAction(() -> {
- StudyCheckUtils.runSmartTestProcess(myTaskDir, testRunner, name, taskFile, project);
- }));
+ if (EduNames.STUDY.equals(myTaskManger.getCourse().getCourseMode())) {
+ CommandProcessor.getInstance().runUndoTransparentAction(() -> ApplicationManager.getApplication().runWriteAction(() -> {
+ StudyCheckUtils.runSmartTestProcess(myTaskDir, testRunner, name, taskFile, project);
+ }));
+ }
}
StudyCheckUtils.showTestResultPopUp(testsOutput.getMessage(), MessageType.ERROR.getPopupBackground(), project);
StudyCheckUtils.navigateToFailedPlaceholder(myStudyState, myTask, myTaskDir, project);