summaryrefslogtreecommitdiff
path: root/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator
diff options
context:
space:
mode:
Diffstat (limited to 'python/edu/course-creator/src/org/jetbrains/plugins/coursecreator')
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/AnswerFileType.java40
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/AnswerFileTypeFactory.java28
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCEditorFactoryListener.java13
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectComponent.java141
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectService.java52
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCRefactoringElementListenerProvider.java96
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCRunTests.java284
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/RunTestsLineMarker.java109
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/StudyDocumentListener.java5
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/AddTaskWindow.java5
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCRename.java97
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCRenameLesson.java48
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCRenameTask.java57
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCShowPreview.java104
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateCourseArchive.java188
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateTask.java14
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateTaskFile.java6
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Course.java14
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Lesson.java31
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Task.java20
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskFile.java27
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskWindow.java11
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/projectView/CCDirectoryNode.java2
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/projectView/CCTreeStructureProvider.java18
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateCourseArchivePanel.form2
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateTaskWindowDialog.java6
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateTaskWindowPanel.java5
27 files changed, 1290 insertions, 133 deletions
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/AnswerFileType.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/AnswerFileType.java
new file mode 100644
index 000000000000..3b8189aadffc
--- /dev/null
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/AnswerFileType.java
@@ -0,0 +1,40 @@
+/*
+ * 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 org.jetbrains.plugins.coursecreator;
+
+import com.jetbrains.python.PythonFileType;
+import org.jetbrains.annotations.NotNull;
+
+public class AnswerFileType extends PythonFileType {
+
+ @NotNull
+ @Override
+ public String getDefaultExtension() {
+ return "answer";
+ }
+
+ @NotNull
+ @Override
+ public String getDescription() {
+ return "Answer file";
+ }
+
+ @NotNull
+ @Override
+ public String getName() {
+ return "Answer";
+ }
+}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/AnswerFileTypeFactory.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/AnswerFileTypeFactory.java
new file mode 100644
index 000000000000..e4adcbc5b386
--- /dev/null
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/AnswerFileTypeFactory.java
@@ -0,0 +1,28 @@
+/*
+ * 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 org.jetbrains.plugins.coursecreator;
+
+
+import com.intellij.openapi.fileTypes.FileTypeConsumer;
+import com.intellij.openapi.fileTypes.FileTypeFactory;
+import org.jetbrains.annotations.NotNull;
+
+public class AnswerFileTypeFactory extends FileTypeFactory {
+ @Override
+ public void createFileTypes(@NotNull FileTypeConsumer fileTypeConsumer) {
+ fileTypeConsumer.consume(AnswerFileType.INSTANCE, "answer");
+ }
+}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCEditorFactoryListener.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCEditorFactoryListener.java
index 1eb8690aad22..acb0d43d0d12 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCEditorFactoryListener.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCEditorFactoryListener.java
@@ -35,6 +35,9 @@ public class CCEditorFactoryListener implements EditorFactoryListener {
final Lesson lesson = course.getLesson(lessonDir.getName());
final Task task = lesson.getTask(taskDir.getName());
final TaskFile taskFile = task.getTaskFile(virtualFile.getName());
+ if (taskFile == null) {
+ return;
+ }
TaskFileModificationListener listener = new TaskFileModificationListener(taskFile);
CCProjectService.addDocumentListener(editor.getDocument(), listener);
editor.getDocument().addDocumentListener(listener);
@@ -54,13 +57,10 @@ public class CCEditorFactoryListener implements EditorFactoryListener {
editor.getSelectionModel().removeSelection();
}
- private class TaskFileModificationListener extends StudyDocumentListener {
-
- private final TaskFile myTaskFile;
+ private static class TaskFileModificationListener extends StudyDocumentListener {
public TaskFileModificationListener(TaskFile taskFile) {
super(taskFile);
- myTaskFile = taskFile;
}
@Override
@@ -71,10 +71,5 @@ public class CCEditorFactoryListener implements EditorFactoryListener {
taskWindow.setReplacementLength(taskWindow.getLength() + 1);
}
}
-
- @Override
- protected boolean needModify() {
- return myTaskFile.isTrackChanges();
- }
}
}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectComponent.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectComponent.java
index 34de943d2ad0..8b524dbffd4b 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectComponent.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectComponent.java
@@ -1,22 +1,33 @@
package org.jetbrains.plugins.coursecreator;
+import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ProjectComponent;
+import com.intellij.openapi.diagnostic.Logger;
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.*;
import com.intellij.openapi.fileEditor.impl.text.PsiAwareTextEditorImpl;
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.VirtualFileAdapter;
+import com.intellij.openapi.vfs.VirtualFileEvent;
+import com.intellij.openapi.vfs.VirtualFileManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.coursecreator.format.Course;
+import org.jetbrains.plugins.coursecreator.format.Lesson;
+import org.jetbrains.plugins.coursecreator.format.Task;
+import org.jetbrains.plugins.coursecreator.format.TaskFile;
+
+import java.io.IOException;
public class CCProjectComponent implements ProjectComponent {
+ private static final Logger LOG = Logger.getInstance(CCProjectComponent.class.getName());
private final Project myProject;
+ private FileDeletedListener myListener;
public CCProjectComponent(Project project) {
myProject = project;
@@ -37,15 +48,46 @@ public class CCProjectComponent implements ProjectComponent {
StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new Runnable() {
@Override
public void run() {
- Course course = CCProjectService.getInstance(myProject).getCourse();
+ final Course course = CCProjectService.getInstance(myProject).getCourse();
if (course != null) {
- EditorFactory.getInstance().addEditorFactoryListener(new CCEditorFactoryListener(), myProject);
+ myProject.getMessageBus().connect(myProject).subscribe(
+ FileEditorManagerListener.FILE_EDITOR_MANAGER, new FileEditorManagerAdapter() {
+ @Override
+ public void selectionChanged(@NotNull FileEditorManagerEvent event) {
+ final VirtualFile oldFile = event.getOldFile();
+ if (oldFile == null) {
+ return;
+ }
+ if (CCProjectService.getInstance(myProject).isTaskFile(oldFile)) {
+ FileEditorManager.getInstance(myProject).closeFile(oldFile);
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ oldFile.delete(myProject);
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ }
+ });
+ }
+ }
+ });
+ myListener = new FileDeletedListener();
+ 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();
- new CCEditorFactoryListener().editorCreated(new EditorFactoryEvent(new EditorFactoryImpl(ProjectManager.getInstance()), editor ));
+ editorFactoryListener.editorCreated(new EditorFactoryEvent(new EditorFactoryImpl(ProjectManager.getInstance()), editor));
}
}
}
@@ -54,5 +96,94 @@ public class CCProjectComponent implements ProjectComponent {
}
public void projectClosed() {
+ if (myListener != null) {
+ VirtualFileManager.getInstance().removeVirtualFileListener(myListener);
+ }
+ }
+
+ private class FileDeletedListener extends VirtualFileAdapter {
+
+ @Override
+ public void fileDeleted(@NotNull VirtualFileEvent event) {
+ if (myProject.isDisposed() || !myProject.isOpen()) {
+ return;
+ }
+ Course course = CCProjectService.getInstance(myProject).getCourse();
+ if (course == null) {
+ return;
+ }
+ VirtualFile removedFile = event.getFile();
+ if (removedFile.getName().contains(".answer")) {
+ deleteTaskFile(course, removedFile);
+ }
+ if (removedFile.getName().contains("task")) {
+ deleteTask(course, removedFile);
+ }
+ if (removedFile.getName().contains("lesson")) {
+ deleteLesson(course, removedFile);
+ }
+ }
+
+ private void deleteLesson(Course course, VirtualFile file) {
+ VirtualFile courseDir = file.getParent();
+ if (!courseDir.getName().equals(myProject.getName())) {
+ return;
+ }
+ Lesson lesson = course.getLesson(file.getName());
+ if (lesson != null) {
+ course.getLessons().remove(lesson);
+ course.getLessonsMap().remove(file.getName());
+ }
+ }
+
+ private void deleteTask(Course course, VirtualFile removedFile) {
+ VirtualFile lessonDir = removedFile.getParent();
+ if (lessonDir == null || !lessonDir.getName().contains("lesson")) {
+ return;
+ }
+ VirtualFile courseDir = lessonDir.getParent();
+ if (!courseDir.getName().equals(myProject.getName())) {
+ return;
+ }
+ Lesson lesson = course.getLesson(lessonDir.getName());
+ if (lesson == null) {
+ return;
+ }
+ Task task = lesson.getTask(removedFile.getName());
+ if (task == null) {
+ return;
+ }
+ lesson.getTaskList().remove(task);
+ lesson.getTasksMap().remove(removedFile.getName());
+ }
+
+ private void deleteTaskFile(Course course, VirtualFile removedFile) {
+ VirtualFile taskDir = removedFile.getParent();
+ if (taskDir == null || !taskDir.getName().contains("task")) {
+ return;
+ }
+ VirtualFile lessonDir = taskDir.getParent();
+ if (lessonDir == null || !lessonDir.getName().contains("lesson")) {
+ return;
+ }
+ VirtualFile courseDir = lessonDir.getParent();
+ if (!courseDir.getName().equals(myProject.getName())) {
+ return;
+ }
+ Lesson lesson = course.getLesson(lessonDir.getName());
+ if (lesson == null) {
+ return;
+ }
+ Task task = lesson.getTask(taskDir.getName());
+ if (task == null) {
+ return;
+ }
+ TaskFile taskFile = task.getTaskFile(removedFile.getName());
+ if (taskFile == null) {
+ return;
+ }
+ String name = CCProjectService.getRealTaskFileName(removedFile.getName());
+ task.getTaskFiles().remove(name);
+ }
}
}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectService.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectService.java
index 1e38bab865cb..c06925e9a453 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectService.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectService.java
@@ -32,6 +32,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.coursecreator.format.*;
import java.io.File;
+import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -70,6 +71,9 @@ public class CCProjectService implements PersistentStateComponent<Element> {
@Override
public void loadState(Element el) {
myCourse = XmlSerializer.deserialize(el.getChild(COURSE_ELEMENT), Course.class);
+ if (myCourse != null) {
+ myCourse.init();
+ }
}
public static CCProjectService getInstance(@NotNull Project project) {
@@ -115,7 +119,7 @@ public class CCProjectService implements PersistentStateComponent<Element> {
}
List<TaskWindow> taskWindows = taskFile.getTaskWindows();
for (TaskWindow taskWindow : taskWindows) {
- taskWindow.drawHighlighter(editor);
+ taskWindow.drawHighlighter(editor, false);
}
}
@@ -131,8 +135,52 @@ public class CCProjectService implements PersistentStateComponent<Element> {
myDocumentListeners.remove(document);
}
- public static boolean indexIsValid(int index, List<TaskWindow> collection) {
+ public static boolean indexIsValid(int index, Collection collection) {
int size = collection.size();
return index >= 0 && index < size;
}
+
+ public boolean isTaskFile(VirtualFile file) {
+ if (myCourse == null || file == null) {
+ return false;
+ }
+ VirtualFile taskDir = file.getParent();
+ if (taskDir != null) {
+ String taskDirName = taskDir.getName();
+ if (taskDirName.contains("task")) {
+ VirtualFile lessonDir = taskDir.getParent();
+ if (lessonDir != null) {
+ String lessonDirName = lessonDir.getName();
+ int lessonIndex = getIndex(lessonDirName, "lesson");
+ List<Lesson> lessons = myCourse.getLessons();
+ if (!indexIsValid(lessonIndex, lessons)) {
+ return false;
+ }
+ Lesson lesson = lessons.get(lessonIndex);
+ int taskIndex = getIndex(taskDirName, "task");
+ List<Task> tasks = lesson.getTaskList();
+ if (!indexIsValid(taskIndex, tasks)) {
+ return false;
+ }
+ Task task = tasks.get(taskIndex);
+ return task.isTaskFile(file.getName());
+ }
+ }
+ }
+ return false;
+ }
+
+ public static int getIndex(@NotNull final String fullName, @NotNull final String logicalName) {
+ if (!fullName.contains(logicalName)) {
+ throw new IllegalArgumentException();
+ }
+ return Integer.parseInt(fullName.substring(logicalName.length())) - 1;
+ }
+ public static String getRealTaskFileName(String name) {
+ if (!name.contains(".answer")) {
+ return null;
+ }
+ int nameEnd = name.indexOf(".answer");
+ return name.substring(0, nameEnd) + ".py";
+ }
}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCRefactoringElementListenerProvider.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCRefactoringElementListenerProvider.java
new file mode 100644
index 000000000000..601e4fc7cb40
--- /dev/null
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCRefactoringElementListenerProvider.java
@@ -0,0 +1,96 @@
+/*
+ * 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 org.jetbrains.plugins.coursecreator;
+
+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 org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.plugins.coursecreator.format.Course;
+import org.jetbrains.plugins.coursecreator.format.Lesson;
+import org.jetbrains.plugins.coursecreator.format.Task;
+import org.jetbrains.plugins.coursecreator.format.TaskFile;
+
+import java.util.Map;
+
+public class CCRefactoringElementListenerProvider implements RefactoringElementListenerProvider {
+ @Nullable
+ @Override
+ public RefactoringElementListener getListener(PsiElement element) {
+ return new CCRenameListener(element);
+ }
+
+
+ static class CCRenameListener extends RefactoringElementAdapter {
+
+ private String myElementName;
+
+ public CCRenameListener(PsiElement element) {
+ if (element instanceof PsiFile) {
+ PsiFile psiFile = (PsiFile)element;
+ myElementName = psiFile.getName();
+ }
+ }
+
+ @Override
+ protected void elementRenamedOrMoved(@NotNull PsiElement newElement) {
+ if (newElement instanceof PsiFile && myElementName != null) {
+ PsiFile psiFile = (PsiFile)newElement;
+ if (myElementName.contains(".answer")) {
+ //this is task file
+ renameTaskFile(psiFile, myElementName);
+ }
+ }
+ }
+
+ private static void renameTaskFile(PsiFile file, String oldName) {
+ PsiDirectory taskDir = file.getContainingDirectory();
+ Course course = CCProjectService.getInstance(file.getProject()).getCourse();
+ if (course == null) {
+ return;
+ }
+ if (taskDir == null || !taskDir.getName().contains("task")) {
+ return;
+ }
+ PsiDirectory lessonDir = taskDir.getParent();
+ if (lessonDir == null || !lessonDir.getName().contains("lesson")) {
+ return;
+ }
+ Lesson lesson = course.getLesson(lessonDir.getName());
+ if (lesson == null) {
+ return;
+ }
+ Task task = lesson.getTask(taskDir.getName());
+ if (task == null) {
+ return;
+ }
+ Map<String, TaskFile> taskFiles = task.getTaskFiles();
+ TaskFile taskFile = task.getTaskFile(oldName);
+ String realTaskFileName = CCProjectService.getRealTaskFileName(oldName);
+ taskFiles.remove(realTaskFileName);
+ taskFiles.put(CCProjectService.getRealTaskFileName(file.getName()), taskFile);
+ }
+
+ @Override
+ public void undoElementMovedOrRenamed(@NotNull PsiElement newElement, @NotNull String oldQualifiedName) {
+
+ }
+ }
+}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCRunTests.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCRunTests.java
new file mode 100644
index 000000000000..d078972e3f56
--- /dev/null
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCRunTests.java
@@ -0,0 +1,284 @@
+/*
+ * 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 org.jetbrains.plugins.coursecreator;
+
+import com.intellij.execution.*;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.execution.configurations.ConfigurationFactory;
+import com.intellij.execution.executors.DefaultRunExecutor;
+import com.intellij.icons.AllIcons;
+import com.intellij.ide.projectView.ProjectView;
+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.editor.Document;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.VirtualFileManager;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.util.containers.HashMap;
+import com.jetbrains.python.run.PythonConfigurationType;
+import com.jetbrains.python.run.PythonRunConfiguration;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.plugins.coursecreator.actions.CreateCourseArchive;
+import org.jetbrains.plugins.coursecreator.format.*;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Map;
+
+public class CCRunTests extends AnAction {
+ private static final Logger LOG = Logger.getInstance(CCRunTests.class.getName());
+
+ public CCRunTests() {
+ getTemplatePresentation().setIcon(AllIcons.Actions.Lightning);
+ }
+
+ @Override
+ public void update(@NotNull AnActionEvent e) {
+ Presentation presentation = e.getPresentation();
+ final ConfigurationContext context = ConfigurationContext.getFromContext(e.getDataContext());
+ Location location = context.getLocation();
+ if (location == null) {
+ return;
+ }
+ PsiElement psiElement = location.getPsiElement();
+ PsiFile psiFile = psiElement.getContainingFile();
+ if (psiFile != null && psiFile.getName().contains(".answer")) {
+ presentation.setEnabled(true);
+ presentation.setText("Run tests from '" + psiFile.getName() + "'");
+ }
+ else {
+ presentation.setEnabled(false);
+ }
+ }
+
+ public void actionPerformed(@NotNull AnActionEvent e) {
+ final ConfigurationContext context = ConfigurationContext.getFromContext(e.getDataContext());
+ run(context);
+ }
+
+ public static 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;
+ }
+ final Task task = getTask(course, taskDir);
+ if (task == null) {
+ return;
+ }
+ for (final Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
+ final String name = entry.getKey();
+ createTestEnvironment(taskDir, name, entry.getValue(), project);
+ VirtualFile testFile = taskDir.findChild("tests.py");
+ if (testFile == null) {
+ return;
+ }
+ executeTests(project, virtualFile, taskDir, testFile);
+ clearTestEnvironment(taskDir, project);
+ }
+ }
+ });
+ }
+
+ private static void createTestEnvironment(@NotNull final VirtualFile taskDir, final String fileName, @NotNull final TaskFile taskFile,
+ @NotNull final Project project) {
+ try {
+ String answerFileName = FileUtil.getNameWithoutExtension(fileName) + ".answer";
+ final VirtualFile answerFile = taskDir.findChild(answerFileName);
+ if (answerFile == null) {
+ LOG.debug("could not find answer file " + answerFileName);
+ return;
+ }
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ final FileDocumentManager documentManager = FileDocumentManager.getInstance();
+ documentManager.saveAllDocuments();
+ }
+ });
+ answerFile.copy(project, taskDir, fileName);
+ flushWindows(taskFile, answerFile);
+ createResourceFiles(answerFile, project);
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ }
+
+ private 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("course");
+ if (courseResourceDir == null) {
+ return;
+ }
+ courseResourceDir.delete(project);
+ VirtualFile[] taskDirChildren = taskDir.getChildren();
+ for (VirtualFile file : taskDirChildren) {
+ if (file.getName().contains("_windows")) {
+ file.delete(project);
+ }
+ if (CCProjectService.getInstance(project).isTaskFile(file)) {
+ file.delete(project);
+ }
+ }
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ }
+
+ private static 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());
+ VirtualFile userFile = taskDir.findChild(virtualFile.getNameWithoutExtension() + ".py");
+ if (userFile == null) {
+ return;
+ }
+ VirtualFile ideaDir = project.getBaseDir().findChild(".idea");
+ if (ideaDir == null) {
+ return;
+ }
+ VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
+ ProjectView.getInstance(project).refresh();
+ VirtualFile courseDir = ideaDir.findChild("course");
+ if (courseDir == null) {
+ return;
+ }
+ configuration.setScriptParameters(courseDir.getPath() + " " + userFile.getPath());
+ Executor executor = DefaultRunExecutor.getRunExecutorInstance();
+ ProgramRunnerUtil.executeConfiguration(project, settings, executor);
+ }
+
+ @Nullable
+ private static Task getTask(@NotNull final Course course, @NotNull final VirtualFile taskDir) {
+ if (!taskDir.getName().contains("task")) {
+ return null;
+ }
+ VirtualFile lessonDir = taskDir.getParent();
+ if (lessonDir == null || !lessonDir.getName().contains("lesson")) {
+ return null;
+ }
+ Lesson lesson = course.getLesson(lessonDir.getName());
+ if (lesson == null) {
+ return null;
+ }
+ return lesson.getTask(taskDir.getName());
+ }
+
+
+ //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 = CCProjectService.getIndex(taskDir.getName(), "task");
+ VirtualFile lessonDir = taskDir.getParent();
+ int lessonIndex = CCProjectService.getIndex(lessonDir.getName(), "lesson");
+ Course course = CCProjectService.getInstance(project).getCourse();
+ if (course == null) {
+ return;
+ }
+ VirtualFile ideaDir = project.getBaseDir().findChild(".idea");
+ assert ideaDir != null;
+ try {
+ VirtualFile taskResourceDir = ideaDir.createChildDirectory(project, "course").createChildDirectory(project, lessonDir.getName())
+ .createChildDirectory(project, taskDir.getName());
+ if (CCProjectService.indexIsValid(lessonIndex, course.getLessons())) {
+ Lesson lesson = course.getLessons().get(lessonIndex);
+ if (CCProjectService.indexIsValid(index, lesson.getTaskList())) {
+ Task task = lesson.getTaskList().get(index);
+ HashMap<TaskFile, TaskFile> taskFilesCopy = new HashMap<TaskFile, TaskFile>();
+ for (Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
+ CreateCourseArchive.createUserFile(project, taskFilesCopy, taskResourceDir, taskDir, entry);
+ CreateCourseArchive.resetTaskFiles(taskFilesCopy);
+ }
+ }
+ }
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ }
+
+ @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
+ public static VirtualFile flushWindows(TaskFile taskFile, VirtualFile file) {
+ VirtualFile taskDir = file.getParent();
+ VirtualFile fileWindows = null;
+ final Document document = FileDocumentManager.getInstance().getDocument(file);
+ if (document == null) {
+ LOG.debug("Couldn't flush windows");
+ return null;
+ }
+ if (taskDir != null) {
+ String name = file.getNameWithoutExtension() + "_windows";
+ PrintWriter printWriter = null;
+ try {
+ fileWindows = taskDir.createChildData(taskFile, name);
+ printWriter = new PrintWriter(new FileOutputStream(fileWindows.getPath()));
+ for (TaskWindow taskWindow : taskFile.getTaskWindows()) {
+ int start = taskWindow.getRealStartOffset(document);
+ String windowDescription = document.getText(new TextRange(start, start + taskWindow.getReplacementLength()));
+ printWriter.println("#study_plugin_window = " + windowDescription);
+ }
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ FileDocumentManager.getInstance().saveDocument(document);
+ }
+ });
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ finally {
+ if (printWriter != null) {
+ printWriter.close();
+ }
+ }
+ }
+ return fileWindows;
+ }
+}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/RunTestsLineMarker.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/RunTestsLineMarker.java
new file mode 100644
index 000000000000..93e0a706f367
--- /dev/null
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/RunTestsLineMarker.java
@@ -0,0 +1,109 @@
+/*
+ * 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 org.jetbrains.plugins.coursecreator;
+
+import com.intellij.codeHighlighting.Pass;
+import com.intellij.codeInsight.daemon.GutterIconNavigationHandler;
+import com.intellij.codeInsight.daemon.LineMarkerInfo;
+import com.intellij.codeInsight.daemon.LineMarkerProvider;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.icons.AllIcons;
+import com.intellij.ide.DataManager;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.markup.GutterIconRenderer;
+import com.intellij.psi.PsiComment;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiWhiteSpace;
+import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.util.Function;
+import com.jetbrains.python.psi.PyFile;
+import com.jetbrains.python.psi.PyImportStatement;
+import com.jetbrains.python.psi.PyStatement;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.awt.event.MouseEvent;
+import java.util.Collection;
+import java.util.List;
+
+public class RunTestsLineMarker implements LineMarkerProvider {
+ @Nullable
+ @Override
+ public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement element) {
+ return null;
+ }
+
+ @Override
+ public void collectSlowLineMarkers(@NotNull List<PsiElement> elements, @NotNull Collection<LineMarkerInfo> result) {
+ for (PsiElement element : elements) {
+ if (isFirstCodeLine(element)) {
+ PsiFile psiFile = element.getContainingFile();
+ if (psiFile == null || !psiFile.getName().contains(".answer")) {
+ continue;
+ }
+ result.add(new LineMarkerInfo<PsiElement>(
+ element, element.getTextRange(), AllIcons.Actions.Lightning, Pass.UPDATE_OVERRIDEN_MARKERS,
+ new Function<PsiElement, String>() {
+ @Override
+ public String fun(PsiElement e) {
+ return "Run tests from file '" + e.getContainingFile().getName() + "'";
+ }
+ },
+ new GutterIconNavigationHandler<PsiElement>() {
+ @Override
+ public void navigate(MouseEvent e, PsiElement elt) {
+ executeCurrentScript(elt);
+ }
+ },
+ GutterIconRenderer.Alignment.RIGHT));
+ }
+ }
+ }
+
+ private static void executeCurrentScript(PsiElement elt) {
+ Editor editor = PsiUtilBase.findEditor(elt);
+ assert editor != null;
+
+ final ConfigurationContext context =
+ ConfigurationContext.getFromContext(DataManager.getInstance().getDataContext(editor.getComponent()));
+ CCRunTests.run(context);
+ }
+
+ private static boolean isFirstCodeLine(PsiElement element) {
+ return element instanceof PyStatement &&
+ element.getParent() instanceof PyFile &&
+ !isNothing(element) &&
+ nothingBefore(element);
+ }
+
+ private static boolean nothingBefore(PsiElement element) {
+ element = element.getPrevSibling();
+ while (element != null) {
+ if (!isNothing(element)) {
+ return false;
+ }
+ element = element.getPrevSibling();
+ }
+
+ return true;
+ }
+
+ private static boolean isNothing(PsiElement element) {
+ return (element instanceof PsiComment) || (element instanceof PyImportStatement) || (element instanceof PsiWhiteSpace);
+ }
+}
+
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/StudyDocumentListener.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/StudyDocumentListener.java
index d803e0e8fd97..965bd31771a0 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/StudyDocumentListener.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/StudyDocumentListener.java
@@ -44,9 +44,6 @@ public abstract class StudyDocumentListener extends DocumentAdapter {
@Override
public void documentChanged(DocumentEvent e) {
if (e instanceof DocumentEventImpl) {
- if (!needModify()) {
- return;
- }
DocumentEventImpl event = (DocumentEventImpl)e;
Document document = e.getDocument();
int offset = e.getOffset();
@@ -65,7 +62,5 @@ public abstract class StudyDocumentListener extends DocumentAdapter {
}
protected abstract void updateTaskWindowLength(CharSequence fragment, TaskWindow taskWindow, int change);
-
- protected abstract boolean needModify();
}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/AddTaskWindow.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/AddTaskWindow.java
index ff88cea5fd42..0bc631dbd784 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/AddTaskWindow.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/AddTaskWindow.java
@@ -13,6 +13,7 @@ import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.coursecreator.CCProjectService;
import org.jetbrains.plugins.coursecreator.format.*;
import org.jetbrains.plugins.coursecreator.ui.CreateTaskWindowDialog;
@@ -59,12 +60,12 @@ public class AddTaskWindow extends DumbAwareAction {
}
int index = taskFile.getTaskWindows().size() + 1;
taskFile.addTaskWindow(taskWindow, index);
- taskWindow.drawHighlighter(editor);
+ taskWindow.drawHighlighter(editor, false);
DaemonCodeAnalyzerImpl.getInstance(project).restart(file);
}
@Override
- public void update(AnActionEvent event) {
+ public void update(@NotNull AnActionEvent event) {
final Presentation presentation = event.getPresentation();
final Project project = event.getData(CommonDataKeys.PROJECT);
if (project == null) {
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCRename.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCRename.java
new file mode 100644
index 000000000000..321a86a5ba35
--- /dev/null
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCRename.java
@@ -0,0 +1,97 @@
+/*
+ * 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 org.jetbrains.plugins.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.psi.PsiDirectory;
+import com.intellij.psi.PsiFile;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.coursecreator.CCProjectService;
+import org.jetbrains.plugins.coursecreator.format.Course;
+
+import javax.swing.*;
+
+public abstract class CCRename extends DumbAwareAction {
+ public CCRename(String text, String description, Icon icon) {
+ super(text, description, icon);
+ }
+
+ @Override
+ public void update(@NotNull AnActionEvent event) {
+ 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 PsiFile file = CommonDataKeys.PSI_FILE.getData(event.getDataContext());
+ final PsiDirectory directory = DirectoryChooserUtil.getOrChooseDirectory(view);
+ if (file != null ||directory == null || !directory.getName().contains(getFolderName())) {
+ presentation.setEnabled(false);
+ presentation.setVisible(false);
+ return;
+ }
+ presentation.setVisible(true);
+ presentation.setEnabled(true);
+ }
+
+ public abstract String getFolderName();
+
+ @Override
+ public void actionPerformed(@NotNull 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 directory = DirectoryChooserUtil.getOrChooseDirectory(view);
+ if (directory == null || !directory.getName().contains(getFolderName())) {
+ return;
+ }
+ Course course = CCProjectService.getInstance(project).getCourse();
+ if (course == null) {
+ return;
+ }
+ if (!processRename(project, directory, course)) return;
+ ProjectView.getInstance(project).refresh();
+ }
+
+ public abstract boolean processRename(Project project, PsiDirectory directory, Course course);
+}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCRenameLesson.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCRenameLesson.java
new file mode 100644
index 000000000000..3f580454ed6e
--- /dev/null
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCRenameLesson.java
@@ -0,0 +1,48 @@
+/*
+ * 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 org.jetbrains.plugins.coursecreator.actions;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.psi.PsiDirectory;
+import org.jetbrains.plugins.coursecreator.format.Course;
+import org.jetbrains.plugins.coursecreator.format.Lesson;
+
+public class CCRenameLesson extends CCRename {
+
+ public CCRenameLesson() {
+ super("Rename Lesson", "Rename Lesson", null);
+ }
+
+ @Override
+ public String getFolderName() {
+ return "lesson";
+ }
+
+ @Override
+ public boolean processRename(Project project, PsiDirectory directory, Course course) {
+ Lesson lesson = course.getLesson(directory.getName());
+ if (lesson == null) {
+ return false;
+ }
+ String newName = Messages.showInputDialog(project, "Enter new name", "Rename " + getFolderName(), null);
+ if (newName == null) {
+ return false;
+ }
+ lesson.setName(newName);
+ return true;
+ }
+}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCRenameTask.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCRenameTask.java
new file mode 100644
index 000000000000..342621bf0d47
--- /dev/null
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCRenameTask.java
@@ -0,0 +1,57 @@
+/*
+ * 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 org.jetbrains.plugins.coursecreator.actions;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.psi.PsiDirectory;
+import org.jetbrains.plugins.coursecreator.format.Course;
+import org.jetbrains.plugins.coursecreator.format.Lesson;
+import org.jetbrains.plugins.coursecreator.format.Task;
+
+public class CCRenameTask extends CCRename {
+ public CCRenameTask() {
+ super("Rename Task", "Rename Task", null);
+ }
+
+ @Override
+ public String getFolderName() {
+ return "task";
+ }
+
+ @Override
+ public boolean processRename(Project project, PsiDirectory directory, Course course) {
+ PsiDirectory lessonDir = directory.getParent();
+ if (lessonDir == null || !lessonDir.getName().contains("lesson")) {
+ return false;
+ }
+ Lesson lesson = course.getLesson(lessonDir.getName());
+ if (lesson == null) {
+ return false;
+ }
+ Task task = lesson.getTask(directory.getName());
+ if (task == null) {
+ return false;
+ }
+ String newName = Messages.showInputDialog(project, "Enter new name", "Rename " + getFolderName(), null);
+ if (newName == null) {
+ return false;
+ }
+ task.setName(newName);
+ return true;
+
+ }
+}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCShowPreview.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCShowPreview.java
new file mode 100644
index 000000000000..bccaacaf1957
--- /dev/null
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCShowPreview.java
@@ -0,0 +1,104 @@
+/*
+ * 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 org.jetbrains.plugins.coursecreator.actions;
+
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.project.DumbAwareAction;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiFile;
+import com.intellij.util.containers.hash.HashMap;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.coursecreator.CCProjectService;
+import org.jetbrains.plugins.coursecreator.format.*;
+
+import java.util.Map;
+
+public class CCShowPreview extends DumbAwareAction {
+ public CCShowPreview() {
+ super("Show preview","Show preview", null);
+ }
+
+ @Override
+ public void update(@NotNull AnActionEvent e) {
+ Presentation presentation = e.getPresentation();
+ presentation.setEnabled(false);
+ presentation.setVisible(false);
+ final PsiFile file = CommonDataKeys.PSI_FILE.getData(e.getDataContext());
+ if (file != null && file.getName().contains(".answer")) {
+ presentation.setEnabled(true);
+ presentation.setVisible(true);
+ }
+ }
+
+ @Override
+ public void actionPerformed(@NotNull AnActionEvent e) {
+ final Project project = e.getProject();
+ if (project == null) {
+ return;
+ }
+ final PsiFile file = CommonDataKeys.PSI_FILE.getData(e.getDataContext());
+ if (file == null || !file.getName().contains(".answer")) {
+ return;
+ }
+ final PsiDirectory taskDir = file.getContainingDirectory();
+ if (taskDir == null) {
+ return;
+ }
+ PsiDirectory lessonDir = taskDir.getParentDirectory();
+ if (lessonDir == null) {
+ return;
+ }
+ Course course = CCProjectService.getInstance(project).getCourse();
+ if (course == null) {
+ return;
+ }
+ Lesson lesson = course.getLesson(lessonDir.getName());
+ Task task = lesson.getTask(taskDir.getName());
+ TaskFile taskFile = task.getTaskFile(file.getName());
+ final Map<TaskFile, TaskFile> taskFilesCopy = new HashMap<TaskFile, TaskFile>();
+ for (final Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
+ if (entry.getValue() == taskFile) {
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ CreateCourseArchive.createUserFile(project, taskFilesCopy, taskDir.getVirtualFile(), taskDir.getVirtualFile(), entry);
+ }
+ });
+ }
+ }
+ String userFileName = FileUtil.getNameWithoutExtension(file.getName()) + ".py";
+ VirtualFile userFile = taskDir.getVirtualFile().findChild(userFileName);
+ if (userFile != null) {
+ FileEditorManager.getInstance(project).openFile(userFile, true);
+ Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor();
+ if (editor == null) {
+ return;
+ }
+ for (TaskWindow taskWindow : taskFile.getTaskWindows()) {
+ taskWindow.drawHighlighter(editor, true);
+ }
+ CreateCourseArchive.resetTaskFiles(taskFilesCopy);
+ }
+ }
+} \ No newline at end of file
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateCourseArchive.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateCourseArchive.java
index 05428f4e82d1..8db49156c987 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateCourseArchive.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateCourseArchive.java
@@ -18,6 +18,7 @@ import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.util.io.ZipUtil;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.coursecreator.CCProjectService;
import org.jetbrains.plugins.coursecreator.StudyDocumentListener;
import org.jetbrains.plugins.coursecreator.format.*;
@@ -29,8 +30,8 @@ import java.util.zip.ZipOutputStream;
public class CreateCourseArchive extends DumbAwareAction {
private static final Logger LOG = Logger.getInstance(CreateCourseArchive.class.getName());
- String myZipName;
- String myLocationDir;
+ private String myZipName;
+ private String myLocationDir;
public void setZipName(String zipName) {
myZipName = zipName;
@@ -60,46 +61,124 @@ public class CreateCourseArchive extends DumbAwareAction {
}
final VirtualFile baseDir = project.getBaseDir();
final Map<String, Lesson> lessons = course.getLessonsMap();
- //List<FileEditor> editorList = new ArrayList<FileEditor>();
- Map<VirtualFile, TaskFile> taskFiles = new HashMap<VirtualFile, TaskFile>();
+ //map to store initial task file
+ final Map<TaskFile, TaskFile> taskFiles = new HashMap<TaskFile, TaskFile>();
for (Map.Entry<String, Lesson> lesson : lessons.entrySet()) {
final VirtualFile lessonDir = baseDir.findChild(lesson.getKey());
if (lessonDir == null) continue;
for (Map.Entry<String, Task> task : lesson.getValue().myTasksMap.entrySet()) {
final VirtualFile taskDir = lessonDir.findChild(task.getKey());
if (taskDir == null) continue;
- for (Map.Entry<String, TaskFile> entry : task.getValue().task_files.entrySet()) {
- final VirtualFile file = taskDir.findChild(entry.getKey());
- if (file == null) continue;
- final Document document = FileDocumentManager.getInstance().getDocument(file);
- if (document == null) continue;
- final TaskFile taskFile = entry.getValue();
- document.addDocumentListener(new InsertionListener(taskFile));
- taskFiles.put(file, taskFile);
- taskFile.setTrackChanges(false);
- Collections.sort(taskFile.getTaskWindows());
- for (int i = taskFile.getTaskWindows().size() - 1; i >=0 ; i--) {
- final TaskWindow taskWindow = taskFile.getTaskWindows().get(i);
- final String taskText = taskWindow.getTaskText();
- final int lineStartOffset = document.getLineStartOffset(taskWindow.line);
- final int offset = lineStartOffset + taskWindow.start;
- CommandProcessor.getInstance().executeCommand(project, new Runnable() {
- @Override
- public void run() {
- ApplicationManager.getApplication().runWriteAction(new Runnable() {
- @Override
- public void run() {
- document.replaceString(offset, offset + taskWindow.getReplacementLength(), taskText);
- FileDocumentManager.getInstance().saveDocument(document);
- }
- });
- }
- }, "x", "qwe");
- }
+ for (final Map.Entry<String, TaskFile> entry : task.getValue().task_files.entrySet()) {
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ createUserFile(project, taskFiles, taskDir, taskDir, entry);
+ }
+ });
}
}
}
generateJson(project);
+ packCourse(baseDir, lessons);
+ resetTaskFiles(taskFiles);
+ synchronize(project);
+ }
+
+ public static void createUserFile(@NotNull final Project project,
+ @NotNull final Map<TaskFile, TaskFile> taskFilesCopy,
+ @NotNull final VirtualFile userFileDir,
+ @NotNull final VirtualFile answerFileDir,
+ @NotNull final Map.Entry<String, TaskFile> taskFiles) {
+ final String name = taskFiles.getKey();
+ VirtualFile file = userFileDir.findChild(name);
+ if (file != null) {
+ try {
+ file.delete(project);
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ }
+ try {
+ userFileDir.createChildData(project, name);
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+
+ file = userFileDir.findChild(name);
+ assert file != null;
+ String answerFileName = file.getNameWithoutExtension() + ".answer";
+ VirtualFile answerFile = answerFileDir.findChild(answerFileName);
+ if (answerFile == null) {
+ return;
+ }
+ final Document answerDocument = FileDocumentManager.getInstance().getDocument(answerFile);
+ if (answerDocument == null) {
+ return;
+ }
+ final Document document = FileDocumentManager.getInstance().getDocument(file);
+ if (document == null) return;
+ final TaskFile taskFile = taskFiles.getValue();
+ TaskFile taskFileSaved = new TaskFile();
+ taskFile.copy(taskFileSaved);
+ CommandProcessor.getInstance().executeCommand(project, new Runnable() {
+ @Override
+ public void run() {
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ document.replaceString(0, document.getTextLength(), answerDocument.getText());
+ }
+ });
+ }
+ }, "x", "qwe");
+ InsertionListener listener = new InsertionListener(taskFile);
+ document.addDocumentListener(listener);
+ taskFilesCopy.put(taskFile, taskFileSaved);
+ Collections.sort(taskFile.getTaskWindows());
+ for (int i = taskFile.getTaskWindows().size() - 1; i >= 0; i--) {
+ final TaskWindow taskWindow = taskFile.getTaskWindows().get(i);
+ replaceTaskWindow(project, document, taskWindow);
+ }
+ document.removeDocumentListener(listener);
+ }
+
+ private static void replaceTaskWindow(@NotNull final Project project,
+ @NotNull final Document document,
+ @NotNull final TaskWindow taskWindow) {
+ final String taskText = taskWindow.getTaskText();
+ final int lineStartOffset = document.getLineStartOffset(taskWindow.line);
+ final int offset = lineStartOffset + taskWindow.start;
+ CommandProcessor.getInstance().executeCommand(project, new Runnable() {
+ @Override
+ public void run() {
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ document.replaceString(offset, offset + taskWindow.getReplacementLength(), taskText);
+ FileDocumentManager.getInstance().saveDocument(document);
+ }
+ });
+ }
+ }, "x", "qwe");
+ }
+
+ private static void synchronize(@NotNull final Project project) {
+ VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
+ ProjectView.getInstance(project).refresh();
+ }
+
+ public static void resetTaskFiles(@NotNull final Map<TaskFile, TaskFile> taskFiles) {
+ for (Map.Entry<TaskFile, TaskFile> entry : taskFiles.entrySet()) {
+ TaskFile realTaskFile = entry.getKey();
+ TaskFile savedTaskFile = entry.getValue();
+ realTaskFile.update(savedTaskFile);
+ }
+ }
+
+ private void packCourse(@NotNull final VirtualFile baseDir, @NotNull final Map<String, Lesson> lessons) {
try {
File zipFile = new File(myLocationDir, myZipName + ".zip");
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)));
@@ -108,7 +187,12 @@ public class CreateCourseArchive extends DumbAwareAction {
final VirtualFile lessonDir = baseDir.findChild(entry.getKey());
if (lessonDir == null) continue;
- ZipUtil.addFileOrDirRecursively(zos, null, new File(lessonDir.getPath()), lessonDir.getName(), null, null);
+ ZipUtil.addFileOrDirRecursively(zos, null, new File(lessonDir.getPath()), lessonDir.getName(), new FileFilter() {
+ @Override
+ public boolean accept(File pathname) {
+ return !pathname.getName().contains(".answer");
+ }
+ }, null);
}
ZipUtil.addFileOrDirRecursively(zos, null, new File(baseDir.getPath(), "hints"), "hints", null, null);
ZipUtil.addFileOrDirRecursively(zos, null, new File(baseDir.getPath(), "course.json"), "course.json", null, null);
@@ -119,36 +203,9 @@ public class CreateCourseArchive extends DumbAwareAction {
catch (IOException e1) {
LOG.error(e1);
}
-
- for (Map.Entry<VirtualFile, TaskFile> entry: taskFiles.entrySet()) {
- TaskFile value = entry.getValue();
- final Document document = FileDocumentManager.getInstance().getDocument(entry.getKey());
- if (document == null) {
- continue;
- }
- for (final TaskWindow taskWindow : value.getTaskWindows()){
- final int lineStartOffset = document.getLineStartOffset(taskWindow.line);
- final int offset = lineStartOffset + taskWindow.start;
- CommandProcessor.getInstance().executeCommand(project, new Runnable() {
- @Override
- public void run() {
- ApplicationManager.getApplication().runWriteAction(new Runnable() {
- @Override
- public void run() {
- document.replaceString(offset, offset + taskWindow.length, taskWindow.getPossibleAnswer());
- FileDocumentManager.getInstance().saveDocument(document);
- }
- });
- }
- }, "x", "qwe");
- }
- value.setTrackChanges(true);
- }
- VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
- ProjectView.getInstance(project).refresh();
}
- private void generateJson(Project project) {
+ private static void generateJson(@NotNull final Project project) {
final CCProjectService service = CCProjectService.getInstance(project);
final Course course = service.getCourse();
final Gson gson = new GsonBuilder().setPrettyPrinting().excludeFieldsWithoutExposeAnnotation().create();
@@ -179,7 +236,7 @@ public class CreateCourseArchive extends DumbAwareAction {
}
}
- private class InsertionListener extends StudyDocumentListener {
+ private static class InsertionListener extends StudyDocumentListener {
public InsertionListener(TaskFile taskFile) {
super(taskFile);
@@ -187,12 +244,7 @@ public class CreateCourseArchive extends DumbAwareAction {
@Override
protected void updateTaskWindowLength(CharSequence fragment, TaskWindow taskWindow, int change) {
- //we don't need to update task window length
- }
-
- @Override
- protected boolean needModify() {
- return true;
+ //we don't need to update task window length
}
}
} \ No newline at end of file
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateTask.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateTask.java
index 0940135b97be..57a37b3f4194 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateTask.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateTask.java
@@ -18,6 +18,7 @@ import com.intellij.openapi.ui.Messages;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
import com.intellij.util.PlatformIcons;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.coursecreator.CCProjectService;
import org.jetbrains.plugins.coursecreator.format.Course;
import org.jetbrains.plugins.coursecreator.format.Lesson;
@@ -29,7 +30,7 @@ public class CreateTask extends DumbAwareAction {
}
@Override
- public void actionPerformed(AnActionEvent e) {
+ public void actionPerformed(final AnActionEvent e) {
final IdeView view = e.getData(LangDataKeys.IDE_VIEW);
final Project project = e.getData(CommonDataKeys.PROJECT);
@@ -42,7 +43,7 @@ public class CreateTask extends DumbAwareAction {
final CCProjectService service = CCProjectService.getInstance(project);
final Course course = service.getCourse();
final Lesson lesson = course.getLesson(directory.getName());
- final int size = lesson.getTasklist().size();
+ final int size = lesson.getTaskList().size();
final String taskName = Messages.showInputDialog("Name:", "Task Name", null, "task" + (size + 1), null);
if (taskName == null) return;
@@ -54,17 +55,16 @@ public class CreateTask extends DumbAwareAction {
if (taskDirectory != null) {
final FileTemplate template = FileTemplateManager.getInstance().getInternalTemplate("task.html");
final FileTemplate testsTemplate = FileTemplateManager.getInstance().getInternalTemplate("tests");
- final FileTemplate taskTemplate = FileTemplateManager.getInstance().getInternalTemplate("task.py");
+ final FileTemplate taskTemplate = FileTemplateManager.getInstance().getInternalTemplate("task.answer");
try {
final PsiElement taskFile = FileTemplateUtil.createFromTemplate(template, "task.html", null, taskDirectory);
final PsiElement testsFile = FileTemplateUtil.createFromTemplate(testsTemplate, "tests.py", null, taskDirectory);
- final PsiElement taskPyFile = FileTemplateUtil.createFromTemplate(taskTemplate, "file1" + ".py", null, taskDirectory);
+ final PsiElement taskPyFile = FileTemplateUtil.createFromTemplate(taskTemplate, "file1", null, taskDirectory);
final Task task = new Task(taskName);
- task.addTaskFile(taskPyFile.getContainingFile().getName(), size + 1);
+ task.addTaskFile("file1.py", size + 1);
task.setIndex(size + 1);
lesson.addTask(task, taskDirectory);
-
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
@@ -84,7 +84,7 @@ public class CreateTask extends DumbAwareAction {
}
@Override
- public void update(AnActionEvent event) {
+ public void update(@NotNull AnActionEvent event) {
final Presentation presentation = event.getPresentation();
final Project project = event.getData(CommonDataKeys.PROJECT);
if (project == null) {
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateTaskFile.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateTaskFile.java
index 5aafcebefd6e..368be275a5a4 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateTaskFile.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateTaskFile.java
@@ -55,10 +55,10 @@ public class CreateTaskFile extends DumbAwareAction {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
- final FileTemplate taskTemplate = FileTemplateManager.getInstance().getInternalTemplate("task.py");
+ final FileTemplate taskTemplate = FileTemplateManager.getInstance().getInternalTemplate("task.answer");
try {
- final PsiElement taskPyFile = FileTemplateUtil.createFromTemplate(taskTemplate, taskFileName + ".py", null, taskDir);
- task.addTaskFile(taskPyFile.getContainingFile().getName(), index);
+ final PsiElement taskPyFile = FileTemplateUtil.createFromTemplate(taskTemplate, taskFileName, null, taskDir);
+ task.addTaskFile(taskFileName + ".py", index);
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Course.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Course.java
index eb62d59cd9b1..e124a6eb305d 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Course.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Course.java
@@ -4,10 +4,7 @@ import com.google.gson.annotations.Expose;
import com.intellij.psi.PsiDirectory;
import org.jetbrains.annotations.NotNull;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
public class Course {
@Expose public List<Lesson> lessons = new ArrayList<Lesson>();
@@ -52,4 +49,13 @@ public class Course {
public String getDescription() {
return description;
}
+
+ public void init() {
+ lessons.clear();
+ for (Lesson lesson: myLessonsMap.values()) {
+ lessons.add(lesson);
+ lesson.init();
+ }
+ Collections.sort(lessons);
+ }
}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Lesson.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Lesson.java
index 38720140caf1..bd91e8ec30af 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Lesson.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Lesson.java
@@ -4,12 +4,9 @@ import com.google.gson.annotations.Expose;
import com.intellij.psi.PsiDirectory;
import org.jetbrains.annotations.NotNull;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
-public class Lesson {
+public class Lesson implements Comparable{
@Expose public String name;
@Expose public List<Task> task_list = new ArrayList<Task>();
@@ -27,11 +24,15 @@ public class Lesson {
task_list.add(task);
}
+ public void setName(String name) {
+ this.name = name;
+ }
+
public Task getTask(@NotNull final String name) {
return myTasksMap.get(name);
}
- public List<Task> getTasklist() {
+ public List<Task> getTaskList() {
return task_list;
}
@@ -42,4 +43,22 @@ public class Lesson {
public int getIndex() {
return myIndex;
}
+
+ public Map<String, Task> getTasksMap() {
+ return myTasksMap;
+ }
+
+ public void init() {
+ task_list.clear();
+ for (Task task : myTasksMap.values()) {
+ task_list.add(task);
+ }
+ Collections.sort(task_list);
+ }
+
+ @Override
+ public int compareTo(@NotNull Object o) {
+ Lesson lesson = (Lesson) o;
+ return myIndex - lesson.getIndex();
+ }
}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Task.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Task.java
index e6c085b5d6a1..886add86ceb4 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Task.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Task.java
@@ -2,11 +2,12 @@ package org.jetbrains.plugins.coursecreator.format;
import com.google.gson.annotations.Expose;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.coursecreator.CCProjectService;
import java.util.HashMap;
import java.util.Map;
-public class Task {
+public class Task implements Comparable{
@Expose public String name;
@Expose public Map<String, TaskFile> task_files = new HashMap<String, TaskFile>();
public int myIndex;
@@ -28,7 +29,8 @@ public class Task {
}
public TaskFile getTaskFile(@NotNull final String name) {
- return task_files.get(name);
+ String fileName = CCProjectService.getRealTaskFileName(name);
+ return fileName != null ? task_files.get(fileName) : null;
}
public void setIndex(int index) {
@@ -38,4 +40,18 @@ public class Task {
public Map<String, TaskFile> getTaskFiles() {
return task_files;
}
+
+ public boolean isTaskFile(String name) {
+ return task_files.get(name) != null;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public int compareTo(@NotNull Object o) {
+ Task task = (Task) o;
+ return myIndex - task.getIndex();
+ }
}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskFile.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskFile.java
index 85f0d91983f2..b88e375bc265 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskFile.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskFile.java
@@ -13,15 +13,6 @@ import java.util.List;
public class TaskFile {
@Expose public List<TaskWindow> task_windows = new ArrayList<TaskWindow>();
public int myIndex;
- public boolean myTrackChanges = true;
-
- public boolean isTrackChanges() {
- return myTrackChanges;
- }
-
- public void setTrackChanges(boolean trackChanges) {
- myTrackChanges = trackChanges;
- }
public TaskFile() {}
@@ -108,4 +99,22 @@ public class TaskFile {
}
}
}
+
+ public void copy(@NotNull final TaskFile target) {
+ target.setIndex(myIndex);
+ for (TaskWindow taskWindow : task_windows) {
+ TaskWindow savedWindow = new TaskWindow(taskWindow.getLine(), taskWindow.getStart(),
+ taskWindow.getLength(), "");
+ target.getTaskWindows().add(savedWindow);
+ savedWindow.setIndex(taskWindow.getIndex());
+ }
+ }
+
+ public void update(@NotNull final TaskFile source) {
+ for (TaskWindow taskWindow : source.getTaskWindows()) {
+ TaskWindow taskWindowUpdated = task_windows.get(taskWindow.getIndex() - 1);
+ taskWindowUpdated.setLine(taskWindow.getLine());
+ taskWindowUpdated.setStart(taskWindow.getStart());
+ }
+ }
}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskWindow.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskWindow.java
index cb6418ec75d7..6b1be7ef3e7d 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskWindow.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskWindow.java
@@ -68,16 +68,17 @@ public class TaskWindow implements Comparable{
}
}
- public void drawHighlighter(@NotNull final Editor editor) {
+ public void drawHighlighter(@NotNull final Editor editor, boolean useLength) {
int startOffset = editor.getDocument().getLineStartOffset(line) + start;
- int endOffset = startOffset + myReplacementLength;
+ int highlighterLength = useLength ? length : myReplacementLength;
+ int endOffset = startOffset + highlighterLength;
TextAttributes defaultTestAttributes =
EditorColorsManager.getInstance().getGlobalScheme().getAttributes(EditorColors.LIVE_TEMPLATE_ATTRIBUTES);
RangeHighlighter highlighter =
editor.getMarkupModel().addRangeHighlighter(startOffset, endOffset, HighlighterLayer.LAST + 1, defaultTestAttributes,
HighlighterTargetArea.EXACT_RANGE);
highlighter.setGreedyToLeft(true);
- highlighter.setGreedyToRight(true);
+ highlighter.setGreedyToRight(false);
}
public int getIndex() {
@@ -123,10 +124,6 @@ public class TaskWindow implements Comparable{
return lineDiff;
}
- public String getPossibleAnswer() {
- return possible_answer;
- }
-
public int getLength() {
return length;
}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/projectView/CCDirectoryNode.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/projectView/CCDirectoryNode.java
index 1a7304123f0a..0969c54563c2 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/projectView/CCDirectoryNode.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/projectView/CCDirectoryNode.java
@@ -26,6 +26,8 @@ public class CCDirectoryNode extends PsiDirectoryNode {
@Override
protected void updateImpl(PresentationData data) {
+ //TODO:change presentable name for files with suffix _answer
+
String valueName = myValue.getName();
final Course course = CCProjectService.getInstance(myProject).getCourse();
if (course == null) return;
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/projectView/CCTreeStructureProvider.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/projectView/CCTreeStructureProvider.java
index 69b78ec9a92b..b4fb50a96dc4 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/projectView/CCTreeStructureProvider.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/projectView/CCTreeStructureProvider.java
@@ -2,9 +2,11 @@ package org.jetbrains.plugins.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.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -27,11 +29,21 @@ public class CCTreeStructureProvider implements TreeStructureProvider, DumbAware
Project project = node.getProject();
if (project != null) {
if (node.getValue() instanceof PsiDirectory) {
- PsiDirectory directory = (PsiDirectory) node.getValue();
+ PsiDirectory directory = (PsiDirectory)node.getValue();
nodes.add(new CCDirectoryNode(project, directory, settings));
- } else {
- nodes.add(node);
+ continue;
}
+ if (node instanceof PsiFileNode) {
+ PsiFileNode fileNode = (PsiFileNode)node;
+ VirtualFile virtualFile = fileNode.getVirtualFile();
+ if (virtualFile == null) {
+ continue;
+ }
+ if (CCProjectService.getInstance(project).isTaskFile(virtualFile)) {
+ continue;
+ }
+ }
+ nodes.add(node);
}
}
return nodes;
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateCourseArchivePanel.form b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateCourseArchivePanel.form
index 920dcb9494a7..096a85f8da59 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateCourseArchivePanel.form
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateCourseArchivePanel.form
@@ -27,7 +27,7 @@
<component id="160bb" class="javax.swing.JTextField" binding="myNameField" default-binding="true">
<constraints>
<grid row="0" column="1" row-span="2" 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"/>
+ <preferred-size width="300" height="-1"/>
</grid>
</constraints>
<properties/>
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateTaskWindowDialog.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateTaskWindowDialog.java
index c7e8f715672c..53a4a77b97f7 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateTaskWindowDialog.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateTaskWindowDialog.java
@@ -150,4 +150,10 @@ public class CreateTaskWindowDialog extends DialogWrapper {
public void validateInput() {
super.initValidation();
}
+
+ @Nullable
+ @Override
+ public JComponent getPreferredFocusedComponent() {
+ return myPanel.getPreferredFocusedComponent();
+ }
}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateTaskWindowPanel.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateTaskWindowPanel.java
index 21a7eb063c63..a50840deaf2f 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateTaskWindowPanel.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateTaskWindowPanel.java
@@ -37,6 +37,7 @@ public class CreateTaskWindowPanel extends JPanel {
}
});
+ myTaskWindowText.grabFocus();
myHintName.getDocument().addDocumentListener(new DocumentAdapter() {
@Override
protected void textChanged(DocumentEvent e) {
@@ -93,4 +94,8 @@ public class CreateTaskWindowPanel extends JPanel {
public void setGeneratedHintName(String generatedHintName) {
myGeneratedHintName = generatedHintName;
}
+
+ public JComponent getPreferredFocusedComponent() {
+ return myTaskWindowText;
+ }
}