mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/liana/course-creator-improvements'
# Conflicts: # python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCLessonMoveHandlerDelegate.java # python/educational-core/student/resources/META-INF/plugin.xml # python/educational-core/student/src/com/jetbrains/edu/learning/StudyPluginConfigurator.java # python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java # python/educational-core/student/src/com/jetbrains/edu/learning/StudyTaskManager.java # python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java # python/educational-core/student/src/com/jetbrains/edu/learning/editor/StudyEditorFactoryListener.java # python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudySwingToolWindow.java
This commit is contained in:
@@ -19,18 +19,17 @@
|
||||
<projectService serviceImplementation="com.jetbrains.edu.coursecreator.CCProjectService"/>
|
||||
<treeStructureProvider implementation="com.jetbrains.edu.coursecreator.projectView.CCTreeStructureProvider"/>
|
||||
<refactoring.elementListenerProvider implementation="com.jetbrains.edu.coursecreator.CCRefactoringElementListenerProvider"/>
|
||||
<refactoring.moveHandler implementation="com.jetbrains.edu.coursecreator.CCLessonMoveHandlerDelegate" order="first"/>
|
||||
<refactoring.moveHandler implementation="com.jetbrains.edu.coursecreator.CCTaskMoveHandlerDelegate" order="first"/>
|
||||
<renameHandler implementation="com.jetbrains.edu.coursecreator.CCTaskRenameHandler" order="first"/>
|
||||
<renameHandler implementation="com.jetbrains.edu.coursecreator.CCLessonRenameHandler" order="first"/>
|
||||
<refactoring.moveHandler implementation="com.jetbrains.edu.coursecreator.handlers.CCLessonMoveHandlerDelegate" order="first"/>
|
||||
<refactoring.moveHandler implementation="com.jetbrains.edu.coursecreator.handlers.CCTaskMoveHandlerDelegate" order="first"/>
|
||||
<renameHandler implementation="com.jetbrains.edu.coursecreator.handlers.CCTaskRenameHandler" order="first"/>
|
||||
<renameHandler implementation="com.jetbrains.edu.coursecreator.handlers.CCLessonRenameHandler" order="first"/>
|
||||
</extensions>
|
||||
<extensions defaultExtensionNs="Edu">
|
||||
<studyActionsProvider implementation="com.jetbrains.edu.coursecreator.CCStudyActionsProvider"/>
|
||||
<studyActionListener implementation="com.jetbrains.edu.coursecreator.CCStudyActionListener"/>
|
||||
</extensions>
|
||||
|
||||
<application-components>
|
||||
<!-- Add your application components here -->
|
||||
</application-components>
|
||||
|
||||
<project-components>
|
||||
<!-- Add your project components here -->
|
||||
<component>
|
||||
<implementation-class>com.jetbrains.edu.coursecreator.CCProjectComponent</implementation-class>
|
||||
</component>
|
||||
@@ -46,49 +45,40 @@
|
||||
<action id="CreateLesson" class="com.jetbrains.edu.coursecreator.actions.CCCreateLesson">
|
||||
<add-to-group group-id="NewGroup" anchor="before" relative-to-action="NewFile"/>
|
||||
</action>
|
||||
<action id="ChangeCourseInfo" class="com.jetbrains.edu.coursecreator.actions.CCChangeCourseInfo">
|
||||
<add-to-group group-id="ProjectViewPopupMenu" anchor="before" relative-to-action="PackCourse"/>
|
||||
</action>
|
||||
<action id="CreateTask" class="com.jetbrains.edu.coursecreator.actions.CCCreateTask">
|
||||
<add-to-group group-id="NewGroup" anchor="before" relative-to-action="NewFile"/>
|
||||
</action>
|
||||
<action id="CreateTaskFile" class="com.jetbrains.edu.coursecreator.actions.CCCreateTaskFile">
|
||||
<add-to-group group-id="NewGroup" anchor="before" relative-to-action="NewFile"/>
|
||||
</action>
|
||||
<action id="AddTaskFile" class="com.jetbrains.edu.coursecreator.actions.CCAddAsTaskFile" text="Add As Task File">
|
||||
<add-to-group group-id="ProjectViewPopupMenu" anchor="first"/>
|
||||
</action>
|
||||
<action id="AddTaskWindow" class="com.jetbrains.edu.coursecreator.actions.CCAddAnswerPlaceholder">
|
||||
<add-to-group group-id="EditorPopupMenu" anchor="before" relative-to-action="CopyReference"/>
|
||||
</action>
|
||||
<action id="ShowTaskWindowDetails" class="com.jetbrains.edu.coursecreator.actions.CCShowAnswerPlaceholderDetails">
|
||||
<add-to-group group-id="EditorPopupMenu" anchor="before" relative-to-action="CopyReference"/>
|
||||
</action>
|
||||
<action id="DeleteTaskWindow" class="com.jetbrains.edu.coursecreator.actions.CCDeleteAnswerPlaceholder">
|
||||
<add-to-group group-id="EditorPopupMenu" anchor="before" relative-to-action="CopyReference"/>
|
||||
</action>
|
||||
<action id="ShowPreview" class="com.jetbrains.edu.coursecreator.actions.CCShowPreview">
|
||||
<add-to-group group-id="ProjectViewPopupMenu" anchor="first"/>
|
||||
<add-to-group group-id="EditorTabPopupMenu"/>
|
||||
</action>
|
||||
<action id="PackCourse" class="com.jetbrains.edu.coursecreator.actions.CCCreateCourseArchive">
|
||||
<add-to-group group-id="ProjectViewPopupMenu" anchor="before" relative-to-action="CutCopyPasteGroup"/>
|
||||
<add-to-group group-id="FileMenu" relative-to-action="FileMainSettingsGroup" anchor="before"/>
|
||||
</action>
|
||||
<action id="UnpackCourse" class="com.jetbrains.edu.coursecreator.actions.CCFromCourseArchive"/>
|
||||
<action id="PushLesson" class="com.jetbrains.edu.coursecreator.actions.CCPushLesson">
|
||||
<add-to-group group-id="ProjectViewPopupMenu" anchor="before" relative-to-action="CutCopyPasteGroup"/>
|
||||
<add-to-group group-id="FileMenu" relative-to-action="FileMainSettingsGroup" anchor="before"/>
|
||||
</action>
|
||||
<action id="PushCourse" class="com.jetbrains.edu.coursecreator.actions.CCPushCourse">
|
||||
<add-to-group group-id="ProjectViewPopupMenu" anchor="before" relative-to-action="CutCopyPasteGroup"/>
|
||||
<add-to-group group-id="FileMenu" relative-to-action="FileMainSettingsGroup" anchor="before"/>
|
||||
</action>
|
||||
|
||||
<action id="DeleteAllPlaceholders" class="com.jetbrains.edu.coursecreator.actions.CCDeleteAllAnswerPlaceholdersAction">
|
||||
<group id="CCProjectViewGroup">
|
||||
<action id="AddTaskFile" class="com.jetbrains.edu.coursecreator.actions.CCAddAsTaskFile" text="Add as Task File"/>
|
||||
<action id="HideTaskFile" class="com.jetbrains.edu.coursecreator.actions.CCHideFromStudent" text="Hide from Student"/>
|
||||
<action id="ShowPreview" class="com.jetbrains.edu.coursecreator.actions.CCShowPreview">
|
||||
<add-to-group group-id="EditorTabPopupMenu"/>
|
||||
</action>
|
||||
<action id="DeleteAllPlaceholders" class="com.jetbrains.edu.coursecreator.actions.CCDeleteAllAnswerPlaceholdersAction"/>
|
||||
<action id="PackCourse" class="com.jetbrains.edu.coursecreator.actions.CCCreateCourseArchive">
|
||||
<add-to-group group-id="FileMenu" relative-to-action="FileMainSettingsGroup" anchor="before"/>
|
||||
</action>
|
||||
<action id="PushLesson" class="com.jetbrains.edu.coursecreator.actions.CCPushLesson">
|
||||
<add-to-group group-id="FileMenu" relative-to-action="FileMainSettingsGroup" anchor="before"/>
|
||||
</action>
|
||||
<action id="PushCourse" class="com.jetbrains.edu.coursecreator.actions.CCPushCourse">
|
||||
<add-to-group group-id="FileMenu" relative-to-action="FileMainSettingsGroup" anchor="before"/>
|
||||
</action>
|
||||
<action id="ChangeCourseInfo" class="com.jetbrains.edu.coursecreator.actions.CCChangeCourseInfo"/>
|
||||
<separator/>
|
||||
<add-to-group group-id="ProjectViewPopupMenu" anchor="before" relative-to-action="CutCopyPasteGroup"/>
|
||||
<add-to-group group-id="EditorPopupMenu" anchor="after" relative-to-action="DeleteTaskWindow"/>
|
||||
</action>
|
||||
</group>
|
||||
|
||||
<group id="AnswerPlaceholderGroup">
|
||||
<action id="EditAnswerPlaceholder" class="com.jetbrains.edu.coursecreator.actions.CCEditAnswerPlaceholder"/>
|
||||
<action id="AddTaskWindow" class="com.jetbrains.edu.coursecreator.actions.CCAddAnswerPlaceholder"/>
|
||||
<reference ref="DeleteAllPlaceholders"/>
|
||||
<separator/>
|
||||
<add-to-group group-id="EditorPopupMenu" anchor="first"/>
|
||||
</group>
|
||||
|
||||
<action id="UnpackCourse" class="com.jetbrains.edu.coursecreator.actions.CCFromCourseArchive"/>
|
||||
</actions>
|
||||
|
||||
</idea-plugin>
|
||||
-69
@@ -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();
|
||||
}
|
||||
}
|
||||
+5
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+26
-44
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-118
@@ -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<CCProjectService> {
|
||||
private Course myCourse;
|
||||
|
||||
private static final Map<Document, EduDocumentListener> myDocumentListeners = new HashMap<Document, EduDocumentListener>();
|
||||
|
||||
@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<AnswerPlaceholder> 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<Lesson> lessons = myCourse.getLessons();
|
||||
if (!EduUtils.indexIsValid(lessonIndex, lessons)) {
|
||||
return null;
|
||||
}
|
||||
Lesson lesson = lessons.get(lessonIndex);
|
||||
int taskIndex = EduUtils.getIndex(taskDirName, EduNames.TASK);
|
||||
List<Task> 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;
|
||||
}
|
||||
|
||||
|
||||
+24
-6
@@ -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<String, TaskFile> 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<String, TaskFile> taskFiles = task.getTaskFiles();
|
||||
TaskFile taskFile = task.getTaskFile(oldName);
|
||||
|
||||
taskFiles.remove(oldName);
|
||||
taskFiles.put(file.getName(), taskFile);
|
||||
CCUtils.createResourceFile(file.getVirtualFile(), course, taskDir.getVirtualFile());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+36
@@ -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);
|
||||
}
|
||||
}
|
||||
+12
@@ -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()};
|
||||
}
|
||||
}
|
||||
+83
-11
@@ -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<String, TaskFile> files = task.getTaskFiles();
|
||||
for (Map.Entry<String, TaskFile> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+58
-17
@@ -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<VirtualFile, StudyItem>() {
|
||||
@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;
|
||||
+103
-86
@@ -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<AnswerPlaceholder> 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<AnswerPlaceholder> 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;
|
||||
}
|
||||
}
|
||||
+9
-35
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+7
-18
@@ -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;
|
||||
}
|
||||
|
||||
+29
-60
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+7
-6
@@ -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);
|
||||
|
||||
+18
-21
@@ -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) {
|
||||
|
||||
+16
-18
@@ -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<PsiDirectory> 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
|
||||
|
||||
-143
@@ -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);
|
||||
}
|
||||
}
|
||||
+24
-25
@@ -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<AnswerPlaceholder> placeholders = new ArrayList<AnswerPlaceholder>(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<AnswerPlaceholder> myPlaceholders;
|
||||
private final Editor myEditor;
|
||||
private final VirtualFile myFile;
|
||||
private final Project myProject;
|
||||
TaskFile myTaskFile;
|
||||
|
||||
public ClearPlaceholders(TaskFile taskFile, List<AnswerPlaceholder> placeholders, Editor editor, VirtualFile file, Project project) {
|
||||
public ClearPlaceholders(TaskFile taskFile, List<AnswerPlaceholder> 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
|
||||
|
||||
-39
@@ -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<AnswerPlaceholder> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
-2
@@ -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);
|
||||
}
|
||||
}
|
||||
+81
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-7
@@ -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<String, TaskFile> 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);
|
||||
}
|
||||
});
|
||||
|
||||
+45
@@ -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<String, TaskFile> 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;
|
||||
}
|
||||
}
|
||||
+7
-3
@@ -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;
|
||||
}
|
||||
|
||||
+3
-3
@@ -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;
|
||||
}
|
||||
|
||||
-222
@@ -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<String, TaskFile> 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<String, TaskFile> 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;
|
||||
}
|
||||
}
|
||||
+11
-12
@@ -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));
|
||||
|
||||
+59
@@ -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);
|
||||
}
|
||||
+9
-3
@@ -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);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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;
|
||||
+8
-6
@@ -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();
|
||||
}
|
||||
+9
-7
@@ -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);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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;
|
||||
-83
@@ -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;
|
||||
}
|
||||
}
|
||||
+16
-34
@@ -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<AbstractTreeNode> modify(@NotNull AbstractTreeNode parent,
|
||||
@@ -26,18 +25,16 @@ public class CCTreeStructureProvider implements TreeStructureProvider, DumbAware
|
||||
if (!needModify(parent)) {
|
||||
return children;
|
||||
}
|
||||
Collection<AbstractTreeNode> nodes = new ArrayList<AbstractTreeNode>();
|
||||
Collection<AbstractTreeNode> 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<AbstractTreeNode> selected, String dataName) {
|
||||
return null;
|
||||
return CCUtils.isCourseCreator(project);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -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());
|
||||
|
||||
+1
-1
@@ -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) {
|
||||
|
||||
@@ -36,7 +36,9 @@
|
||||
<with attribute="implementationClass" implements="com.jetbrains.edu.learning.StudyLanguageManager"/>
|
||||
</extensionPoint>
|
||||
<extensionPoint qualifiedName="Edu.studyPluginConfigurator" interface="com.jetbrains.edu.learning.StudyPluginConfigurator"/>
|
||||
<extensionPoint qualifiedName="Edu.studyActionsProvider" interface="com.jetbrains.edu.learning.StudyActionsProvider"/>
|
||||
<extensionPoint qualifiedName="Edu.studyTwitterPluginConfigurator" interface="com.jetbrains.edu.learning.StudyTwitterPluginConfigurator"/>
|
||||
<extensionPoint qualifiedName="Edu.studyActionListener" interface="com.jetbrains.edu.learning.StudyActionListener"/>
|
||||
<extensionPoint qualifiedName="Edu.optionsProvider" beanClass="com.jetbrains.edu.learning.settings.StudyOptionsProviderEP">>
|
||||
<with attribute="instance" implements="com.jetbrains.edu.learning.settings.StudyOptionsProvider"/>
|
||||
</extensionPoint>
|
||||
|
||||
+10
@@ -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<StudyActionListener> EP_NAME = ExtensionPointName.create("Edu.studyActionListener");
|
||||
|
||||
void beforeCheck(AnActionEvent event);
|
||||
}
|
||||
+10
@@ -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<StudyActionsProvider> EP_NAME = ExtensionPointName.create("Edu.studyActionsProvider");
|
||||
|
||||
AnAction[] getActions();
|
||||
}
|
||||
+1
-1
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
+3
-6
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
+2
-1
@@ -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]);
|
||||
|
||||
+1
-1
@@ -40,6 +40,6 @@ public interface StudyPluginConfigurator {
|
||||
StudyAfterCheckAction[] getAfterCheckActions();
|
||||
|
||||
@NotNull String getLanguageScriptUrl();
|
||||
|
||||
|
||||
boolean accept(@NotNull final Project project);
|
||||
}
|
||||
|
||||
+20
-20
@@ -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<AnAction> 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<Lesson> lessons = course.getLessons();
|
||||
if (StudyUtils.indexIsValid(lessonIndex, lessons)) {
|
||||
final Lesson lesson = lessons.get(lessonIndex);
|
||||
final List<Task> 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<Lesson> lessons = course.getLessons();
|
||||
if (StudyUtils.indexIsValid(lessonIndex, lessons)) {
|
||||
final Lesson lesson = lessons.get(lessonIndex);
|
||||
final List<Task> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+20
-1
@@ -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<Element>, Dumb
|
||||
public Map<Task, List<UserTest>> myUserTests = new HashMap<>();
|
||||
public List<String> 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<Element>, Dumb
|
||||
@NotNull
|
||||
public List<UserTest> getUserTests(@NotNull final Task task) {
|
||||
final List<UserTest> userTests = myUserTests.get(task);
|
||||
return userTests != null ? userTests : Collections.emptyList();
|
||||
return userTests != null ? userTests : Collections.<UserTest>emptyList();
|
||||
}
|
||||
|
||||
public void removeUserTest(@NotNull final Task task, @NotNull final UserTest userTest) {
|
||||
@@ -260,4 +263,20 @@ public class StudyTaskManager implements PersistentStateComponent<Element>, 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-4
@@ -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();
|
||||
}
|
||||
+6
-1
@@ -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<Boolean> 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);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-1
@@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
+10
-5
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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";
|
||||
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
+3
-3
@@ -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);
|
||||
}
|
||||
|
||||
+2
-2
@@ -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(() -> {
|
||||
|
||||
+9
-11
@@ -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<RangeMarker> 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);
|
||||
|
||||
+2
-12
@@ -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<AnswerPlaceholderWrapper> myAnswerPlaceholders = new ArrayList<AnswerPlaceholderWrapper>();
|
||||
|
||||
|
||||
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) {
|
||||
|
||||
@@ -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() {
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
+30
@@ -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;
|
||||
|
||||
+15
-2
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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) {
|
||||
|
||||
+19
-6
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-9
@@ -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<AbstractTreeNode> modify(@NotNull AbstractTreeNode parent,
|
||||
@NotNull Collection<AbstractTreeNode> children,
|
||||
ViewSettings settings) {
|
||||
if (!isCourseBasedProject(parent)) {
|
||||
if (!needModify(parent)) {
|
||||
return children;
|
||||
}
|
||||
Collection<AbstractTreeNode> 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
|
||||
|
||||
+2
-3
@@ -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);
|
||||
}
|
||||
|
||||
+2
-3
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+100
-20
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,5 +23,6 @@
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module" module-name="xml" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -21,27 +21,16 @@
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<directoryProjectGenerator implementation="com.jetbrains.edu.coursecreator.PyCCProjectGenerator"/>
|
||||
<configurationType implementation="com.jetbrains.edu.coursecreator.run.PyCCRunTestsConfigurationType"/>
|
||||
<runConfigurationProducer implementation="com.jetbrains.edu.coursecreator.run.PyCCRunTestsConfigurationProducer"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="Edu">
|
||||
<CCLanguageManager implementationClass="com.jetbrains.edu.coursecreator.PyCCLanguageManager" language="Python"/>
|
||||
<executeFile implementation="com.jetbrains.edu.coursecreator.PyCCRunTests"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="Pythonid">
|
||||
<pyReferenceResolveProvider implementation="com.jetbrains.edu.coursecreator.PyCCReferenceResolveProvider"/>
|
||||
</extensions>
|
||||
|
||||
<application-components>
|
||||
<!-- Add your application components here -->
|
||||
</application-components>
|
||||
|
||||
<project-components>
|
||||
<!-- Add your project components here -->
|
||||
</project-components>
|
||||
|
||||
<actions>
|
||||
<action id="CCRunTests" class="com.jetbrains.edu.coursecreator.actions.PyCCRunTestsAction" text="Run Tests" description="Run tests"/>
|
||||
</actions>
|
||||
|
||||
</idea-plugin>
|
||||
+6
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
+39
-14
@@ -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) {
|
||||
|
||||
+3
-1
@@ -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<RatedResolveResult> 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);
|
||||
|
||||
-20
@@ -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;
|
||||
}
|
||||
}
|
||||
-62
@@ -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);
|
||||
}
|
||||
}
|
||||
+89
@@ -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;
|
||||
}
|
||||
}
|
||||
+80
@@ -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<PyCCRunTestConfiguration> {
|
||||
|
||||
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<PyCCRunTestConfiguration> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
@@ -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);
|
||||
}
|
||||
}
|
||||
+94
@@ -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<PyCCRunTestConfiguration> {
|
||||
protected PyCCRunTestsConfigurationProducer() {
|
||||
super(PyCCRunTestsConfigurationType.getInstance());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean setupConfigurationFromContext(PyCCRunTestConfiguration configuration,
|
||||
ConfigurationContext context,
|
||||
Ref<PsiElement> 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());
|
||||
}
|
||||
}
|
||||
+41
@@ -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);
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.edu.coursecreator.run.PyCCSettingsEditor">
|
||||
<grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<xy x="20" y="20" width="500" height="400"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="ae76e" class="javax.swing.JTextField" binding="myPathToTestFileField">
|
||||
<constraints>
|
||||
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
|
||||
<preferred-size width="150" height="-1"/>
|
||||
</grid>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<vspacer id="d7ebc">
|
||||
<constraints>
|
||||
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</vspacer>
|
||||
<component id="704f6" class="com.intellij.ui.components.JBLabel">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="Path to Test File"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
</form>
|
||||
+69
@@ -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<PyCCRunTestConfiguration> {
|
||||
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<Module> getValidModules() {
|
||||
return AbstractPythonRunConfiguration.getValidModules(myProject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean showConfigureInterpretersLink() {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+6
-3
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user