summaryrefslogtreecommitdiff
path: root/python/edu/learn-python/src/com/jetbrains/python
diff options
context:
space:
mode:
Diffstat (limited to 'python/edu/learn-python/src/com/jetbrains/python')
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/StudyDirectoryProjectGenerator.java4
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/StudyDocumentListener.java3
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/StudyInstructionPainter.java5
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/StudyState.java52
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/StudyTaskManager.java24
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/StudyTestRunner.java76
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/StudyUtils.java44
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java378
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyEditInputAction.java4
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyNewProject.java34
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyNextStudyTaskAction.java5
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyNextWindowAction.java4
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyPreviousStudyTaskAction.java5
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyRefreshTaskFileAction.java (renamed from python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyRefreshTaskAction.java)15
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyShowHintAction.java103
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyTaskNavigationAction.java49
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/course/TaskFile.java48
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/course/TaskWindow.java67
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/editor/StudyEditor.java96
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/highlighting/StudyVisitorFilter.java18
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/projectView/StudyDirectoryNode.java11
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/ui/StudyNewProjectPanel.form10
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/ui/StudyNewProjectPanel.java7
23 files changed, 694 insertions, 368 deletions
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyDirectoryProjectGenerator.java b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyDirectoryProjectGenerator.java
index d4831d93e367..59bd8bc2ea7c 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyDirectoryProjectGenerator.java
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyDirectoryProjectGenerator.java
@@ -53,7 +53,7 @@ public class StudyDirectoryProjectGenerator extends PythonProjectGenerator imple
@NotNull
@Override
public String getName() {
- return "Study project";
+ return "Learn Python";
}
@@ -137,7 +137,7 @@ public class StudyDirectoryProjectGenerator extends PythonProjectGenerator imple
@Nullable
@Override
public Icon getLogo() {
- return StudyIcons.Playground;
+ return StudyIcons.EducationalProjectType;
}
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyDocumentListener.java b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyDocumentListener.java
index 9fdcf704a29b..6ce1d0991dff 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyDocumentListener.java
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyDocumentListener.java
@@ -52,6 +52,9 @@ public class StudyDocumentListener extends DocumentAdapter {
if (myTaskWindow != null) {
int newLength = myTaskWindow.getLength() + change;
myTaskWindow.setLength(newLength <= 0 ? 0 : newLength);
+ if (e.getNewFragment().equals("\n")) {
+ myTaskWindow.setLength(myTaskWindow.getLength() + 1);
+ }
}
int newEnd = offset + event.getNewLength();
int newLine = document.getLineNumber(newEnd);
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyInstructionPainter.java b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyInstructionPainter.java
index 4f34bfb92fab..96a44b2ee66a 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyInstructionPainter.java
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyInstructionPainter.java
@@ -8,7 +8,6 @@ import com.intellij.ui.JBColor;
import com.intellij.util.PairFunction;
import com.intellij.util.ui.GraphicsUtil;
import com.intellij.util.ui.UIUtil;
-import com.jetbrains.python.edu.ui.StudyCondition;
import java.awt.*;
@@ -19,10 +18,6 @@ import java.awt.*;
public class StudyInstructionPainter extends EditorEmptyTextPainter {
@Override
public void paintEmptyText(final EditorsSplitters splitters, Graphics g) {
- if (!StudyCondition.VALUE) {
- super.paintEmptyText(splitters, g);
- return;
- }
boolean isDarkBackground = UIUtil.isUnderDarcula();
UIUtil.applyRenderingHints(g);
GraphicsUtil.setupAntialiasing(g, true, false);
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyState.java b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyState.java
new file mode 100644
index 000000000000..96dc3d906472
--- /dev/null
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyState.java
@@ -0,0 +1,52 @@
+package com.jetbrains.python.edu;
+
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.python.edu.course.Task;
+import com.jetbrains.python.edu.course.TaskFile;
+import com.jetbrains.python.edu.editor.StudyEditor;
+
+public class StudyState {
+ private final StudyEditor myStudyEditor;
+ private final Editor myEditor;
+ private final TaskFile myTaskFile;
+ private final VirtualFile myVirtualFile;
+ private final Task myTask;
+ private final VirtualFile myTaskDir;
+
+ public StudyState(final StudyEditor studyEditor) {
+ myStudyEditor = studyEditor;
+ myEditor = studyEditor != null ? studyEditor.getEditor() : null;
+ myTaskFile = studyEditor != null ? studyEditor.getTaskFile() : null;
+ myVirtualFile = myEditor != null ? FileDocumentManager.getInstance().getFile(myEditor.getDocument()) : null;
+ myTaskDir = myVirtualFile != null ? myVirtualFile.getParent() : null;
+ myTask = myTaskFile != null ? myTaskFile.getTask() : null;
+ }
+
+ public Editor getEditor() {
+ return myEditor;
+ }
+
+ public TaskFile getTaskFile() {
+ return myTaskFile;
+ }
+
+ public VirtualFile getVirtualFile() {
+ return myVirtualFile;
+ }
+
+ public Task getTask() {
+ return myTask;
+ }
+
+ public VirtualFile getTaskDir() {
+ return myTaskDir;
+ }
+
+ public boolean isValid() {
+ return myStudyEditor != null && myEditor != null &&
+ myTaskFile != null && myVirtualFile != null &&
+ myTask != null && myTaskDir != null;
+ }
+}
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyTaskManager.java b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyTaskManager.java
index 213c1f7601f0..3013fbcb05d3 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyTaskManager.java
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyTaskManager.java
@@ -109,21 +109,29 @@ public class StudyTaskManager implements ProjectComponent, PersistentStateCompon
StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new Runnable() {
@Override
public void run() {
- ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.PROJECT_VIEW).show(null);
- FileEditor[] editors = FileEditorManager.getInstance(myProject).getSelectedEditors();
- if (editors.length > 0) {
- JComponent focusedComponent = editors[0].getPreferredFocusedComponent();
- if (focusedComponent != null) {
- IdeFocusManager.getInstance(myProject).requestFocus(focusedComponent, true);
+ ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.PROJECT_VIEW).show(new Runnable() {
+ @Override
+ public void run() {
+ FileEditor[] editors = FileEditorManager.getInstance(myProject).getSelectedEditors();
+ if (editors.length > 0) {
+ final JComponent focusedComponent = editors[0].getPreferredFocusedComponent();
+ if (focusedComponent != null) {
+ ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ IdeFocusManager.getInstance(myProject).requestFocus(focusedComponent, true);
+ }
+ });
+ }
+ }
}
- }
+ });
}
});
UISettings.getInstance().HIDE_TOOL_STRIPES = false;
UISettings.getInstance().fireUISettingsChanged();
ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(myProject);
String toolWindowId = StudyToolWindowFactory.STUDY_TOOL_WINDOW;
- //TODO:decide smth with tool window position
try {
Method method = toolWindowManager.getClass().getDeclaredMethod("registerToolWindow", String.class,
JComponent.class,
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyTestRunner.java b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyTestRunner.java
new file mode 100644
index 000000000000..b0cd5ba89fed
--- /dev/null
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyTestRunner.java
@@ -0,0 +1,76 @@
+package com.jetbrains.python.edu;
+
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.configurations.GeneralCommandLine;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.module.ModuleManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.python.edu.course.Course;
+import com.jetbrains.python.edu.course.Task;
+import com.jetbrains.python.sdk.PythonSdkType;
+
+import java.io.*;
+import java.util.Map;
+
+public class StudyTestRunner {
+ public static final String TEST_OK = "#study_plugin test OK";
+ private static final String TEST_FAILED = "#study_plugin FAILED + ";
+ private static final String PYTHONPATH = "PYTHONPATH";
+ private static final Logger LOG = Logger.getInstance(StudyTestRunner.class);
+ private final Task myTask;
+ private final VirtualFile myTaskDir;
+
+ public StudyTestRunner(Task task, VirtualFile taskDir) {
+ myTask = task;
+ myTaskDir = taskDir;
+ }
+
+ public Process launchTests(Project project, String executablePath) throws ExecutionException {
+ Sdk sdk = PythonSdkType.findPythonSdk(ModuleManager.getInstance(project).getModules()[0]);
+ File testRunner = new File(myTaskDir.getPath(), myTask.getTestFile());
+ GeneralCommandLine commandLine = new GeneralCommandLine();
+ commandLine.setWorkDirectory(myTaskDir.getPath());
+ final Map<String, String> env = commandLine.getEnvironment();
+ final VirtualFile courseDir = project.getBaseDir();
+ if (courseDir != null) {
+ env.put(PYTHONPATH, courseDir.getPath());
+ }
+ if (sdk != null) {
+ String pythonPath = sdk.getHomePath();
+ if (pythonPath != null) {
+ commandLine.setExePath(pythonPath);
+ commandLine.addParameter(testRunner.getPath());
+ final Course course = StudyTaskManager.getInstance(project).getCourse();
+ assert course != null;
+ commandLine.addParameter(new File(course.getResourcePath()).getParent());
+ commandLine.addParameter(FileUtil.toSystemDependentName(executablePath));
+ return commandLine.createProcess();
+ }
+ }
+ return null;
+ }
+
+
+ public String getPassedTests(Process p) {
+ InputStream testOutput = p.getInputStream();
+ BufferedReader testOutputReader = new BufferedReader(new InputStreamReader(testOutput));
+ String line;
+ try {
+ while ((line = testOutputReader.readLine()) != null) {
+ if (line.contains(TEST_FAILED)) {
+ return line.substring(TEST_FAILED.length(), line.length());
+ }
+ }
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ finally {
+ StudyUtils.closeSilently(testOutputReader);
+ }
+ return TEST_OK;
+ }
+}
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyUtils.java b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyUtils.java
index d3ac1dadf98e..5d9bb139db09 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyUtils.java
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyUtils.java
@@ -3,6 +3,7 @@ package com.jetbrains.python.edu;
import com.intellij.ide.SaveAndSyncHandlerImpl;
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;
@@ -10,12 +11,12 @@ import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorManager;
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.openapi.wm.ToolWindowManager;
import com.intellij.util.ui.UIUtil;
-import com.jetbrains.python.edu.course.TaskFile;
-import com.jetbrains.python.edu.course.TaskWindow;
+import com.jetbrains.python.edu.course.*;
import com.jetbrains.python.edu.editor.StudyEditor;
import com.jetbrains.python.edu.ui.StudyToolWindowFactory;
import org.jetbrains.annotations.NotNull;
@@ -70,7 +71,7 @@ public class StudyUtils {
return wrapHTML ? UIUtil.toHtml(taskText.toString()) : taskText.toString();
}
catch (IOException e) {
- LOG.error("Failed to get file text from file " + fileName, e);
+ LOG.info("Failed to get file text from file " + fileName, e);
}
finally {
closeSilently(reader);
@@ -119,14 +120,18 @@ public class StudyUtils {
}
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
- public static VirtualFile flushWindows(Document document, TaskFile taskFile, VirtualFile file) {
+ 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()) {
@@ -137,6 +142,12 @@ public class StudyUtils {
String windowDescription = document.getText(new TextRange(start, start + taskWindow.getLength()));
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);
@@ -148,4 +159,27 @@ public class StudyUtils {
}
return fileWindows;
}
+
+ public static void deleteFile(VirtualFile file) {
+ try {
+ file.delete(StudyUtils.class);
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ }
+
+ public static File copyResourceFile(String sourceName, String copyName, Project project, Task task)
+ throws IOException {
+ StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
+ Course course = taskManager.getCourse();
+ int taskNum = task.getIndex() + 1;
+ int lessonNum = task.getLesson().getIndex() + 1;
+ assert course != null;
+ String pathToResource =
+ FileUtil.join(new File(course.getResourcePath()).getParent(), Lesson.LESSON_DIR + lessonNum, Task.TASK_DIR + taskNum);
+ File resourceFile = new File(pathToResource, copyName);
+ FileUtil.copy(new File(pathToResource, sourceName), resourceFile);
+ return resourceFile;
+ }
}
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java
index f8e10c9c4521..5d02f7149aab 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java
@@ -1,7 +1,6 @@
package com.jetbrains.python.edu.actions;
import com.intellij.execution.ExecutionException;
-import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.ide.projectView.ProjectView;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnActionEvent;
@@ -13,93 +12,81 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorManager;
-import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.ui.popup.BalloonBuilder;
import com.intellij.openapi.ui.popup.JBPopupFactory;
-import com.intellij.openapi.util.TextRange;
-import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.ui.JBColor;
+import com.intellij.openapi.wm.IdeFocusManager;
import com.jetbrains.python.edu.StudyDocumentListener;
-import com.jetbrains.python.edu.StudyTaskManager;
+import com.jetbrains.python.edu.StudyState;
+import com.jetbrains.python.edu.StudyTestRunner;
import com.jetbrains.python.edu.StudyUtils;
-import com.jetbrains.python.edu.course.*;
+import com.jetbrains.python.edu.course.StudyStatus;
+import com.jetbrains.python.edu.course.Task;
+import com.jetbrains.python.edu.course.TaskFile;
+import com.jetbrains.python.edu.course.TaskWindow;
import com.jetbrains.python.edu.editor.StudyEditor;
-import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
-import java.io.*;
-import java.util.*;
-import java.util.List;
+import java.io.IOException;
+import java.util.Map;
public class StudyCheckAction extends DumbAwareAction {
private static final Logger LOG = Logger.getInstance(StudyCheckAction.class.getName());
- public static final String PYTHONPATH = "PYTHONPATH";
+ private static final String ANSWERS_POSTFIX = "_answers.py";
- static class StudyTestRunner {
- public static final String TEST_OK = "#study_plugin test OK";
- private static final String TEST_FAILED = "#study_plugin FAILED + ";
- private final Task myTask;
- private final VirtualFile myTaskDir;
- StudyTestRunner(Task task, VirtualFile taskDir) {
- myTask = task;
- myTaskDir = taskDir;
+ private static void flushWindows(@NotNull final Task task, @NotNull final VirtualFile taskDir) {
+ for (Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
+ String name = entry.getKey();
+ TaskFile taskFile = entry.getValue();
+ VirtualFile virtualFile = taskDir.findChild(name);
+ if (virtualFile == null) {
+ continue;
+ }
+ StudyUtils.flushWindows(taskFile, virtualFile);
}
+ }
- Process launchTests(Project project, String executablePath) throws ExecutionException {
- Sdk sdk = PythonSdkType.findPythonSdk(ModuleManager.getInstance(project).getModules()[0]);
- File testRunner = new File(myTaskDir.getPath(), myTask.getTestFile());
- GeneralCommandLine commandLine = new GeneralCommandLine();
- commandLine.setWorkDirectory(myTaskDir.getPath());
- final Map<String, String> env = commandLine.getEnvironment();
- final VirtualFile courseDir = project.getBaseDir();
- if (courseDir != null)
- env.put(PYTHONPATH, courseDir.getPath());
- if (sdk != null) {
- String pythonPath = sdk.getHomePath();
- if (pythonPath != null) {
- commandLine.setExePath(pythonPath);
- commandLine.addParameter(testRunner.getPath());
- final Course course = StudyTaskManager.getInstance(project).getCourse();
- assert course != null;
- commandLine.addParameter(new File(course.getResourcePath()).getParent());
- commandLine.addParameter(FileUtil.toSystemDependentName(executablePath));
- return commandLine.createProcess();
- }
+ private static void deleteWindowDescriptions(@NotNull final Task task, @NotNull final VirtualFile taskDir) {
+ for (Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
+ String name = entry.getKey();
+ VirtualFile virtualFile = taskDir.findChild(name);
+ if (virtualFile == null) {
+ continue;
+ }
+ String windowsFileName = virtualFile.getNameWithoutExtension() + "_windows";
+ VirtualFile windowsFile = taskDir.findChild(windowsFileName);
+ if (windowsFile != null) {
+ StudyUtils.deleteFile(windowsFile);
}
- return null;
}
+ }
-
- String getPassedTests(Process p) {
- InputStream testOutput = p.getInputStream();
- BufferedReader testOutputReader = new BufferedReader(new InputStreamReader(testOutput));
- String line;
- try {
- while ((line = testOutputReader.readLine()) != null) {
- if (line.contains(TEST_FAILED)) {
- return line.substring(TEST_FAILED.length(), line.length());
- }
- }
- }
- catch (IOException e) {
- LOG.error(e);
+ private static void drawAllTaskWindows(@NotNull final Project project, @NotNull final Task task, @NotNull final VirtualFile taskDir) {
+ for (Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
+ String name = entry.getKey();
+ TaskFile taskFile = entry.getValue();
+ VirtualFile virtualFile = taskDir.findChild(name);
+ if (virtualFile == null) {
+ continue;
}
- finally {
- StudyUtils.closeSilently(testOutputReader);
+ FileEditor fileEditor = FileEditorManager.getInstance(project).getSelectedEditor(virtualFile);
+ if (fileEditor instanceof StudyEditor) {
+ StudyEditor studyEditor = (StudyEditor)fileEditor;
+ taskFile.drawAllWindows(studyEditor.getEditor());
}
- return TEST_OK;
}
}
+
public void check(@NotNull final Project project) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
@@ -107,188 +94,138 @@ public class StudyCheckAction extends DumbAwareAction {
CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() {
@Override
public void run() {
- final Editor selectedEditor = StudyEditor.getSelectedEditor(project);
- if (selectedEditor != null) {
- final FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
- final VirtualFile openedFile = fileDocumentManager.getFile(selectedEditor.getDocument());
- if (openedFile != null) {
- StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
- final TaskFile selectedTaskFile = taskManager.getTaskFile(openedFile);
- List<VirtualFile> filesToDelete = new ArrayList<VirtualFile>();
- if (selectedTaskFile != null) {
- final VirtualFile taskDir = openedFile.getParent();
- Task currentTask = selectedTaskFile.getTask();
- StudyStatus oldStatus = currentTask.getStatus();
- Map<String, TaskFile> taskFiles = selectedTaskFile.getTask().getTaskFiles();
+ final StudyEditor selectedEditor = StudyEditor.getSelectedStudyEditor(project);
+ final StudyState studyState = new StudyState(selectedEditor);
+ if (!studyState.isValid()) {
+ LOG.error("StudyCheckAction was invokes outside study editor");
+ return;
+ }
+ Task task = studyState.getTask();
+ StudyStatus oldStatus = task.getStatus();
+ Map<String, TaskFile> taskFiles = task.getTaskFiles();
+ VirtualFile taskDir = studyState.getTaskDir();
+ flushWindows(task, taskDir);
+ StudyRunAction runAction = (StudyRunAction)ActionManager.getInstance().getAction(StudyRunAction.ACTION_ID);
+ if (runAction != null && taskFiles.size() == 1) {
+ runAction.run(project);
+ }
+ ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ IdeFocusManager.getInstance(project).requestFocus(studyState.getEditor().getComponent(), true);
+ }
+ });
+ final StudyTestRunner testRunner = new StudyTestRunner(task, taskDir);
+ Process testProcess = null;
+ try {
+ testProcess = testRunner.launchTests(project, studyState.getVirtualFile().getPath());
+ }
+ catch (ExecutionException e) {
+ LOG.error(e);
+ }
+ if (testProcess == null) {
+ return;
+ }
+ String failedMessage = testRunner.getPassedTests(testProcess);
+ if (failedMessage.equals(StudyTestRunner.TEST_OK)) {
+ task.setStatus(StudyStatus.Solved, oldStatus);
+ createTestResultPopUp("Congratulations!", MessageType.INFO.getPopupBackground(), project);
+ }
+ else {
+ task.setStatus(StudyStatus.Failed, oldStatus);
for (Map.Entry<String, TaskFile> entry : taskFiles.entrySet()) {
String name = entry.getKey();
TaskFile taskFile = entry.getValue();
- VirtualFile virtualFile = taskDir.findChild(name);
- if (virtualFile == null) {
+ if (taskFile.getTaskWindows().size() < 2) {
+ taskFile.setStatus(StudyStatus.Failed, StudyStatus.Unchecked);
continue;
}
- VirtualFile windowFile = StudyUtils.flushWindows(FileDocumentManager.getInstance().getDocument(virtualFile), taskFile, virtualFile);
- filesToDelete.add(windowFile);
- FileDocumentManager.getInstance().saveAllDocuments();
- }
-
- StudyRunAction runAction = (StudyRunAction)ActionManager.getInstance().getAction(StudyRunAction.ACTION_ID);
- if (runAction != null && currentTask.getTaskFiles().size() == 1) {
- runAction.run(project);
- }
- final StudyTestRunner testRunner = new StudyTestRunner(currentTask, taskDir);
- Process testProcess = null;
- try {
- testProcess = testRunner.launchTests(project, openedFile.getPath());
- }
- catch (ExecutionException e) {
- LOG.error(e);
- }
- if (testProcess != null) {
- String failedMessage = testRunner.getPassedTests(testProcess);
- if (failedMessage.equals(StudyTestRunner.TEST_OK)) {
- currentTask.setStatus(StudyStatus.Solved, oldStatus);
- StudyUtils.updateStudyToolWindow(project);
- selectedTaskFile.drawAllWindows(selectedEditor);
- ProjectView.getInstance(project).refresh();
- for (VirtualFile file:filesToDelete) {
- try {
- file.delete(this);
- }
- catch (IOException e) {
- LOG.error(e);
- }
- }
- createTestResultPopUp("Congratulations!", JBColor.GREEN, project);
- return;
- }
- for (Map.Entry<String, TaskFile> entry : taskFiles.entrySet()) {
- String name = entry.getKey();
- TaskFile taskFile = entry.getValue();
- TaskFile answerTaskFile = new TaskFile();
- VirtualFile virtualFile = taskDir.findChild(name);
- if (virtualFile == null) {
- continue;
- }
- VirtualFile answerFile = getCopyWithAnswers(taskDir, virtualFile, taskFile, answerTaskFile);
- for (TaskWindow taskWindow : answerTaskFile.getTaskWindows()) {
- Document document = FileDocumentManager.getInstance().getDocument(virtualFile);
- if (document == null) {
- continue;
- }
- if (!taskWindow.isValid(document)) {
- continue;
- }
- check(project, taskWindow, answerFile, answerTaskFile, taskFile, document, testRunner, virtualFile);
- }
- FileEditor fileEditor = FileEditorManager.getInstance(project).getSelectedEditor(virtualFile);
- Editor editor = null;
- if (fileEditor instanceof StudyEditor) {
- StudyEditor studyEditor = (StudyEditor) fileEditor;
- editor = studyEditor.getEditor();
- }
-
- if (editor != null) {
- taskFile.drawAllWindows(editor);
- StudyUtils.synchronize();
- }
- try {
- answerFile.delete(this);
- }
- catch (IOException e) {
- LOG.error(e);
- }
- }
- for (VirtualFile file:filesToDelete) {
- try {
- file.delete(this);
- }
- catch (IOException e) {
- LOG.error(e);
- }
- }
- currentTask.setStatus(StudyStatus.Failed, oldStatus);
- StudyUtils.updateStudyToolWindow(project);
- createTestResultPopUp(failedMessage, JBColor.RED, project);
+ runSmartTestProcess(taskDir, testRunner, name, taskFile, project);
}
+ createTestResultPopUp(failedMessage, MessageType.ERROR.getPopupBackground(), project);
+ navigateToFailedTaskWindow(studyState, task, taskDir, project);
}
+ StudyUtils.updateStudyToolWindow(project);
+ drawAllTaskWindows(project, task, taskDir);
+ ProjectView.getInstance(project).refresh();
+ deleteWindowDescriptions(task, taskDir);
}
- }
-
- }
- });
+ });
}
});
}
- private void check(Project project,
- TaskWindow taskWindow,
- VirtualFile answerFile,
- TaskFile answerTaskFile,
- TaskFile usersTaskFile,
- Document usersDocument,
- StudyTestRunner testRunner,
- VirtualFile openedFile) {
-
- try {
- VirtualFile windowCopy = answerFile.copy(this, answerFile.getParent(), answerFile.getNameWithoutExtension() + "_window" + taskWindow.getIndex() + ".py");
- final FileDocumentManager documentManager = FileDocumentManager.getInstance();
- final Document windowDocument = documentManager.getDocument(windowCopy);
- if (windowDocument != null) {
- StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
- Course course = taskManager.getCourse();
- Task task = usersTaskFile.getTask();
- int taskNum = task.getIndex() + 1;
- int lessonNum = task.getLesson().getIndex() + 1;
- assert course != null;
- String pathToResource = FileUtil.join(new File(course.getResourcePath()).getParent(), Lesson.LESSON_DIR + lessonNum, Task.TASK_DIR + taskNum);
- File resourceFile = new File(pathToResource, windowCopy.getName());
- FileUtil.copy(new File(pathToResource, openedFile.getName()), resourceFile);
- TaskFile windowTaskFile = new TaskFile();
- TaskFile.copy(answerTaskFile, windowTaskFile);
- StudyDocumentListener listener = new StudyDocumentListener(windowTaskFile);
- windowDocument.addDocumentListener(listener);
- int start = taskWindow.getRealStartOffset(windowDocument);
- int end = start + taskWindow.getLength();
- TaskWindow userTaskWindow = usersTaskFile.getTaskWindows().get(taskWindow.getIndex());
- int userStart = userTaskWindow.getRealStartOffset(usersDocument);
- int userEnd = userStart + userTaskWindow.getLength();
- String text = usersDocument.getText(new TextRange(userStart, userEnd));
- windowDocument.replaceString(start, end, text);
- ApplicationManager.getApplication().runWriteAction(new Runnable() {
- @Override
- public void run() {
- documentManager.saveDocument(windowDocument);
+ private static void navigateToFailedTaskWindow(@NotNull final StudyState studyState,
+ @NotNull final Task task,
+ @NotNull final VirtualFile taskDir,
+ @NotNull final Project project) {
+ TaskFile selectedTaskFile = studyState.getTaskFile();
+ Editor editor = studyState.getEditor();
+ TaskFile taskFileToNavigate = selectedTaskFile;
+ VirtualFile fileToNavigate = studyState.getVirtualFile();
+ if (!selectedTaskFile.hasFailedTaskWindows()) {
+ for (Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
+ String name = entry.getKey();
+ TaskFile taskFile = entry.getValue();
+ if (taskFile.hasFailedTaskWindows()) {
+ taskFileToNavigate = taskFile;
+ VirtualFile virtualFile = taskDir.findChild(name);
+ if (virtualFile == null) {
+ continue;
}
- });
- VirtualFile fileWindows = StudyUtils.flushWindows(windowDocument, windowTaskFile, windowCopy);
- Process smartTestProcess = testRunner.launchTests(project, windowCopy.getPath());
- boolean res = testRunner.getPassedTests(smartTestProcess).equals(StudyTestRunner.TEST_OK);
- userTaskWindow.setStatus(res ? StudyStatus.Solved : StudyStatus.Failed, StudyStatus.Unchecked);
- windowCopy.delete(this);
- fileWindows.delete(this);
- if (!resourceFile.delete()) {
- LOG.error("failed to delete", resourceFile.getPath());
+ FileEditor fileEditor = FileEditorManager.getInstance(project).getSelectedEditor(virtualFile);
+ if (fileEditor instanceof StudyEditor) {
+ StudyEditor studyEditor = (StudyEditor)fileEditor;
+ editor = studyEditor.getEditor();
+ }
+ fileToNavigate = virtualFile;
+ break;
}
}
}
- catch (IOException e) {
- LOG.error(e);
+ FileEditorManager.getInstance(project).openFile(fileToNavigate, true);
+ final Editor editorToNavigate = editor;
+ ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ IdeFocusManager.getInstance(project).requestFocus(editorToNavigate.getContentComponent(), true);
+ }
+ });
+ taskFileToNavigate.navigateToFirstFailedTaskWindow(editor);
+ }
+
+ private void runSmartTestProcess(@NotNull final VirtualFile taskDir,
+ @NotNull final StudyTestRunner testRunner,
+ final String taskFileName,
+ @NotNull final TaskFile taskFile,
+ @NotNull final Project project) {
+ TaskFile answerTaskFile = new TaskFile();
+ VirtualFile virtualFile = taskDir.findChild(taskFileName);
+ if (virtualFile == null) {
+ return;
}
- catch (ExecutionException e) {
- LOG.error(e);
+ VirtualFile answerFile = getCopyWithAnswers(taskDir, virtualFile, taskFile, answerTaskFile);
+ for (TaskWindow taskWindow : answerTaskFile.getTaskWindows()) {
+ Document document = FileDocumentManager.getInstance().getDocument(virtualFile);
+ if (document == null) {
+ continue;
+ }
+ if (!taskWindow.isValid(document)) {
+ continue;
+ }
+ taskWindow.smartCheck(project, answerFile, answerTaskFile, taskFile, testRunner, virtualFile, document);
}
+ StudyUtils.deleteFile(answerFile);
}
-
- private VirtualFile getCopyWithAnswers(final VirtualFile taskDir,
- final VirtualFile file,
- final TaskFile source,
- TaskFile target) {
+ private VirtualFile getCopyWithAnswers(@NotNull final VirtualFile taskDir,
+ @NotNull final VirtualFile file,
+ @NotNull final TaskFile source,
+ @NotNull final TaskFile target) {
VirtualFile copy = null;
try {
- copy = file.copy(this, taskDir, file.getNameWithoutExtension() +"_answers.py");
+ copy = file.copy(this, taskDir, file.getNameWithoutExtension() + ANSWERS_POSTFIX);
final FileDocumentManager documentManager = FileDocumentManager.getInstance();
final Document document = documentManager.getDocument(copy);
if (document != null) {
@@ -315,19 +252,18 @@ public class StudyCheckAction extends DumbAwareAction {
catch (IOException e) {
LOG.error(e);
}
-
-
return copy;
}
private static void createTestResultPopUp(final String text, Color color, @NotNull final Project project) {
BalloonBuilder balloonBuilder =
JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(text, null, color, null);
- Balloon balloon = balloonBuilder.createBalloon();
+ final Balloon balloon = balloonBuilder.createBalloon();
StudyEditor studyEditor = StudyEditor.getSelectedStudyEditor(project);
assert studyEditor != null;
JButton checkButton = studyEditor.getCheckButton();
balloon.showInCenterOf(checkButton);
+ Disposer.register(project, balloon);
}
@Override
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyEditInputAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyEditInputAction.java
index 5b9a6fef23ac..72660fc9c2c6 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyEditInputAction.java
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyEditInputAction.java
@@ -19,6 +19,7 @@ import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.ui.tabs.TabInfo;
import com.intellij.ui.tabs.TabsListener;
import com.intellij.ui.tabs.impl.JBEditorTabs;
+import com.intellij.util.PlatformIcons;
import com.jetbrains.python.edu.StudyTaskManager;
import com.jetbrains.python.edu.StudyUtils;
import com.jetbrains.python.edu.course.Task;
@@ -26,7 +27,6 @@ import com.jetbrains.python.edu.course.TaskFile;
import com.jetbrains.python.edu.course.UserTest;
import com.jetbrains.python.edu.editor.StudyEditor;
import com.jetbrains.python.edu.ui.StudyTestContentPanel;
-import icons.StudyIcons;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
@@ -92,7 +92,7 @@ public class StudyEditInputAction extends DumbAwareAction {
i++;
}
TabInfo plusTab = new TabInfo(new JPanel());
- plusTab.setIcon(StudyIcons.Add);
+ plusTab.setIcon(PlatformIcons.ADD_ICON);
tabbedPane.addTabSilently(plusTab, tabbedPane.getTabCount());
final JBPopup hint =
JBPopupFactory.getInstance().createComponentPopupBuilder(tabbedPane.getComponent(), tabbedPane.getComponent())
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyNewProject.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyNewProject.java
new file mode 100644
index 000000000000..0b75c4bc01c4
--- /dev/null
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyNewProject.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2000-2013 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.python.edu.actions;
+
+import com.jetbrains.python.edu.StudyDirectoryProjectGenerator;
+import com.jetbrains.python.newProject.actions.GenerateProjectCallback;
+import com.jetbrains.python.newProject.actions.ProjectSpecificAction;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class StudyNewProject extends ProjectSpecificAction {
+
+ public StudyNewProject(@NotNull final String name, @Nullable final Runnable runnable) {
+ super(new GenerateProjectCallback(runnable), new StudyDirectoryProjectGenerator(), name, true);
+ }
+
+ public StudyNewProject() {
+ this("Learn Python", null);
+ }
+
+}
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyNextStudyTaskAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyNextStudyTaskAction.java
index 81818a95c044..3c971c3fe15e 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyNextStudyTaskAction.java
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyNextStudyTaskAction.java
@@ -2,13 +2,14 @@ package com.jetbrains.python.edu.actions;
import com.jetbrains.python.edu.editor.StudyEditor;
import com.jetbrains.python.edu.course.Task;
+import org.jetbrains.annotations.NotNull;
import javax.swing.*;
public class StudyNextStudyTaskAction extends StudyTaskNavigationAction {
@Override
- protected JButton getButton(StudyEditor selectedStudyEditor) {
+ protected JButton getButton(@NotNull final StudyEditor selectedStudyEditor) {
return selectedStudyEditor.getNextTaskButton();
}
@@ -18,7 +19,7 @@ public class StudyNextStudyTaskAction extends StudyTaskNavigationAction {
}
@Override
- protected Task getTargetTask(Task sourceTask) {
+ protected Task getTargetTask(@NotNull final Task sourceTask) {
return sourceTask.next();
}
} \ No newline at end of file
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyNextWindowAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyNextWindowAction.java
index 595aeeff42e3..fcf9ef40c7d4 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyNextWindowAction.java
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyNextWindowAction.java
@@ -1,8 +1,8 @@
package com.jetbrains.python.edu.actions;
+import com.intellij.icons.AllIcons;
import com.jetbrains.python.edu.StudyUtils;
import com.jetbrains.python.edu.course.TaskWindow;
-import icons.StudyIcons;
import org.jetbrains.annotations.NotNull;
import java.util.List;
@@ -16,7 +16,7 @@ public class StudyNextWindowAction extends StudyWindowNavigationAction {
public static final String SHORTCUT2 = "ctrl pressed ENTER";
public StudyNextWindowAction() {
- super("NextWindowAction", "Select next window", StudyIcons.Next);
+ super("NextWindowAction", "Select next window", AllIcons.Actions.Forward);
}
@Override
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyPreviousStudyTaskAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyPreviousStudyTaskAction.java
index bc26c28cfabd..f6da6a067894 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyPreviousStudyTaskAction.java
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyPreviousStudyTaskAction.java
@@ -3,13 +3,14 @@ package com.jetbrains.python.edu.actions;
import com.jetbrains.python.edu.editor.StudyEditor;
import com.jetbrains.python.edu.course.Task;
+import org.jetbrains.annotations.NotNull;
import javax.swing.*;
public class StudyPreviousStudyTaskAction extends StudyTaskNavigationAction {
@Override
- protected JButton getButton(StudyEditor selectedStudyEditor) {
+ protected JButton getButton(@NotNull final StudyEditor selectedStudyEditor) {
return selectedStudyEditor.getPrevTaskButton();
}
@@ -19,7 +20,7 @@ public class StudyPreviousStudyTaskAction extends StudyTaskNavigationAction {
}
@Override
- protected Task getTargetTask(Task sourceTask) {
+ protected Task getTargetTask(@NotNull final Task sourceTask) {
return sourceTask.prev();
}
} \ No newline at end of file
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyRefreshTaskAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyRefreshTaskFileAction.java
index f8abb0b63365..a9448ddea0e3 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyRefreshTaskAction.java
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyRefreshTaskFileAction.java
@@ -14,6 +14,7 @@ import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.ui.popup.BalloonBuilder;
import com.intellij.openapi.ui.popup.JBPopupFactory;
+import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.IdeFocusManager;
import com.jetbrains.python.edu.StudyDocumentListener;
@@ -24,8 +25,8 @@ import com.jetbrains.python.edu.editor.StudyEditor;
import java.io.*;
-public class StudyRefreshTaskAction extends DumbAwareAction {
- private static final Logger LOG = Logger.getInstance(StudyRefreshTaskAction.class.getName());
+public class StudyRefreshTaskFileAction extends DumbAwareAction {
+ private static final Logger LOG = Logger.getInstance(StudyRefreshTaskFileAction.class.getName());
public void refresh(final Project project) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@@ -92,14 +93,20 @@ public class StudyRefreshTaskAction extends DumbAwareAction {
document.addDocumentListener(listener);
}
selectedTaskFile.drawAllWindows(editor);
- IdeFocusManager.getInstance(project).requestFocus(editor.getContentComponent(), true);
+ ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ IdeFocusManager.getInstance(project).requestFocus(editor.getContentComponent(), true);
+ }
+ });
selectedTaskFile.navigateToFirstTaskWindow(editor);
BalloonBuilder balloonBuilder =
JBPopupFactory.getInstance().createHtmlTextBalloonBuilder("You can now start again", MessageType.INFO, null);
- Balloon balloon = balloonBuilder.createBalloon();
+ final Balloon balloon = balloonBuilder.createBalloon();
StudyEditor selectedStudyEditor = StudyEditor.getSelectedStudyEditor(project);
assert selectedStudyEditor != null;
balloon.showInCenterOf(selectedStudyEditor.getRefreshButton());
+ Disposer.register(project, balloon);
}
catch (FileNotFoundException e1) {
LOG.error(e1);
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyShowHintAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyShowHintAction.java
index 1efa90889449..2952486274cf 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyShowHintAction.java
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyShowHintAction.java
@@ -5,19 +5,18 @@ import com.intellij.codeInsight.documentation.DocumentationManager;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.LogicalPosition;
-import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
-import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.util.Disposer;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
+import com.jetbrains.python.edu.StudyState;
import com.jetbrains.python.edu.StudyTaskManager;
import com.jetbrains.python.edu.StudyUtils;
import com.jetbrains.python.edu.course.Course;
-import com.jetbrains.python.edu.course.TaskFile;
import com.jetbrains.python.edu.course.TaskWindow;
import com.jetbrains.python.edu.editor.StudyEditor;
import icons.StudyIcons;
@@ -33,58 +32,56 @@ public class StudyShowHintAction extends DumbAwareAction {
}
public void actionPerformed(AnActionEvent e) {
- Project project = e.getProject();
- if (project != null) {
+ final Project project = e.getProject();
+ if (project == null) {
+ return;
+ }
+ Course course = StudyTaskManager.getInstance(project).getCourse();
+ if (course == null) {
+ return;
+ }
+ StudyState studyState = new StudyState(StudyEditor.getSelectedStudyEditor(project));
+ if (!studyState.isValid()) {
+ return;
+ }
+ PsiFile file = PsiManager.getInstance(project).findFile(studyState.getVirtualFile());
+ final Editor editor = studyState.getEditor();
+ LogicalPosition pos = editor.getCaretModel().getLogicalPosition();
+ TaskWindow taskWindow = studyState.getTaskFile().getTaskWindow(editor.getDocument(), pos);
+ if (file == null || taskWindow == null) {
+ return;
+ }
+ String hint = taskWindow.getHint();
+ if (hint == null) {
+ return;
+ }
+ File resourceFile = new File(course.getResourcePath());
+ File resourceRoot = resourceFile.getParentFile();
+ if (resourceRoot == null || !resourceRoot.exists()) {
+ return;
+ }
+ File hintsDir = new File(resourceRoot, Course.HINTS_DIR);
+ if (hintsDir.exists()) {
+ String hintText = StudyUtils.getFileText(hintsDir.getAbsolutePath(), hint, true);
+ int offset = editor.getDocument().getLineStartOffset(pos.line) + pos.column;
+ PsiElement element = file.findElementAt(offset);
+ if (hintText == null || element == null) {
+ return;
+ }
+
DocumentationManager documentationManager = DocumentationManager.getInstance(project);
DocumentationComponent component = new DocumentationComponent(documentationManager);
- Editor selectedEditor = StudyEditor.getSelectedEditor(project);
- FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
- assert selectedEditor != null;
- VirtualFile openedFile = fileDocumentManager.getFile(selectedEditor.getDocument());
- if (openedFile != null) {
- StudyTaskManager taskManager = StudyTaskManager.getInstance(e.getProject());
- TaskFile taskFile = taskManager.getTaskFile(openedFile);
- if (taskFile != null) {
- PsiFile file = PsiManager.getInstance(project).findFile(openedFile);
- if (file != null) {
- LogicalPosition pos = selectedEditor.getCaretModel().getLogicalPosition();
- TaskWindow taskWindow = taskFile.getTaskWindow(selectedEditor.getDocument(), pos);
- if (taskWindow != null) {
- String hint = taskWindow.getHint();
- if (hint == null) {
- return;
- }
- Course course = taskManager.getCourse();
- if (course != null) {
- File resourceFile = new File(course.getResourcePath());
- File resourceRoot = resourceFile.getParentFile();
- if (resourceRoot != null && resourceRoot.exists()) {
- File hintsDir = new File(resourceRoot, Course.HINTS_DIR);
- if (hintsDir.exists()) {
- String hintText = StudyUtils.getFileText(hintsDir.getAbsolutePath(), hint, true);
- if (hintText != null) {
- int offset = selectedEditor.getDocument().getLineStartOffset(pos.line) + pos.column;
- PsiElement element = file.findElementAt(offset);
- if (element != null) {
- component.setData(element, hintText, true, null);
- final JBPopup popup =
- JBPopupFactory.getInstance().createComponentPopupBuilder(component, component)
- .setDimensionServiceKey(project, DocumentationManager.JAVADOC_LOCATION_AND_SIZE, false)
- .setResizable(true)
- .setMovable(true)
- .setRequestFocus(true)
- .createPopup();
- component.setHint(popup);
- popup.showInBestPositionFor(selectedEditor);
- }
- }
- }
- }
- }
- }
- }
- }
- }
+ component.setData(element, hintText, true, null);
+ final JBPopup popup =
+ JBPopupFactory.getInstance().createComponentPopupBuilder(component, component)
+ .setDimensionServiceKey(project, DocumentationManager.JAVADOC_LOCATION_AND_SIZE, false)
+ .setResizable(true)
+ .setMovable(true)
+ .setRequestFocus(true)
+ .createPopup();
+ component.setHint(popup);
+ popup.showInBestPositionFor(editor);
+ Disposer.dispose(component);
}
}
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyTaskNavigationAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyTaskNavigationAction.java
index b781e7da8849..46c0981cb964 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyTaskNavigationAction.java
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyTaskNavigationAction.java
@@ -1,8 +1,6 @@
package com.jetbrains.python.edu.actions;
import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
@@ -11,37 +9,34 @@ import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.ui.popup.BalloonBuilder;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.vfs.VirtualFile;
-import com.jetbrains.python.edu.StudyTaskManager;
+import com.intellij.openapi.wm.ToolWindow;
+import com.intellij.openapi.wm.ToolWindowId;
+import com.intellij.openapi.wm.ToolWindowManager;
+import com.jetbrains.python.edu.StudyState;
import com.jetbrains.python.edu.course.Lesson;
import com.jetbrains.python.edu.course.Task;
import com.jetbrains.python.edu.course.TaskFile;
import com.jetbrains.python.edu.editor.StudyEditor;
+import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.util.Map;
-/**
- * author: liana
- * data: 7/21/14.
- */
+
abstract public class StudyTaskNavigationAction extends DumbAwareAction {
- public void navigateTask(Project project) {
- Editor selectedEditor = StudyEditor.getSelectedEditor(project);
- FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
- assert selectedEditor != null;
- VirtualFile openedFile = fileDocumentManager.getFile(selectedEditor.getDocument());
- StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
- assert openedFile != null;
- TaskFile selectedTaskFile = taskManager.getTaskFile(openedFile);
- assert selectedTaskFile != null;
- Task currentTask = selectedTaskFile.getTask();
- Task nextTask = getTargetTask(currentTask);
+ public void navigateTask(@NotNull final Project project) {
+ StudyEditor studyEditor = StudyEditor.getSelectedStudyEditor(project);
+ StudyState studyState = new StudyState(studyEditor);
+ if (!studyState.isValid()) {
+ return;
+ }
+ Task nextTask = getTargetTask(studyState.getTask());
if (nextTask == null) {
BalloonBuilder balloonBuilder =
JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(getNavigationFinishedMessage(), MessageType.INFO, null);
Balloon balloon = balloonBuilder.createBalloon();
- StudyEditor selectedStudyEditor = StudyEditor.getSelectedStudyEditor(project);
- balloon.showInCenterOf(getButton(selectedStudyEditor));
+ assert studyEditor != null;
+ balloon.showInCenterOf(getButton(studyEditor));
return;
}
for (VirtualFile file : FileEditorManager.getInstance(project).getOpenFiles()) {
@@ -82,16 +77,24 @@ abstract public class StudyTaskNavigationAction extends DumbAwareAction {
if (shouldBeActive != null) {
FileEditorManager.getInstance(project).openFile(shouldBeActive, true);
}
+ ToolWindow runToolWindow = ToolWindowManager.getInstance(project).getToolWindow(ToolWindowId.RUN);
+ if (runToolWindow != null) {
+ runToolWindow.hide(null);
+ }
}
- protected abstract JButton getButton(StudyEditor selectedStudyEditor);
+ protected abstract JButton getButton(@NotNull final StudyEditor selectedStudyEditor);
@Override
public void actionPerformed(AnActionEvent e) {
- navigateTask(e.getProject());
+ Project project = e.getProject();
+ if (project == null) {
+ return;
+ }
+ navigateTask(project);
}
protected abstract String getNavigationFinishedMessage();
- protected abstract Task getTargetTask(Task sourceTask);
+ protected abstract Task getTargetTask(@NotNull final Task sourceTask);
}
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/course/TaskFile.java b/python/edu/learn-python/src/com/jetbrains/python/edu/course/TaskFile.java
index 4f17fc0d27f3..c46c4f56f937 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/course/TaskFile.java
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/course/TaskFile.java
@@ -21,7 +21,7 @@ import java.util.List;
* which is visible to student in project view
*/
-public class TaskFile implements Stateful{
+public class TaskFile implements Stateful {
public List<TaskWindow> taskWindows = new ArrayList<TaskWindow>();
private Task myTask;
@Transient
@@ -173,7 +173,18 @@ public class TaskFile implements Stateful{
for (TaskWindow w : taskWindows) {
if ((w.getLine() == line) && (w.getStart() >= oldEndOffsetInLine)) {
int distance = w.getStart() - oldEndOffsetInLine;
- if (lineChange != 0 || newEndOffsetInLine <= w.getStart()) {
+ boolean coveredByPrevTW = false;
+ int prevIndex = w.getIndex() - 1;
+ if (StudyUtils.indexIsValid(prevIndex, taskWindows)) {
+ TaskWindow prevTW = taskWindows.get(prevIndex);
+ if (prevTW.getLine() == line) {
+ int endOffset = prevTW.getStart() + prevTW.getLength();
+ if (endOffset >= newEndOffsetInLine) {
+ coveredByPrevTW = true;
+ }
+ }
+ }
+ if (lineChange != 0 || newEndOffsetInLine <= w.getStart() || coveredByPrevTW) {
w.setStart(distance + newEndOffsetInLine);
w.setLine(line + lineChange);
}
@@ -217,12 +228,33 @@ public class TaskFile implements Stateful{
public void navigateToFirstTaskWindow(@NotNull final Editor editor) {
if (!taskWindows.isEmpty()) {
TaskWindow firstTaskWindow = StudyUtils.getFirst(taskWindows);
- mySelectedTaskWindow = firstTaskWindow;
- LogicalPosition taskWindowStart = new LogicalPosition(firstTaskWindow.getLine(), firstTaskWindow.getStart());
- editor.getCaretModel().moveToLogicalPosition(taskWindowStart);
- int startOffset = firstTaskWindow.getRealStartOffset(editor.getDocument());
- int endOffset = startOffset + firstTaskWindow.getLength();
- editor.getSelectionModel().setSelection(startOffset, endOffset);
+ navigateToTaskWindow(editor, firstTaskWindow);
+ }
+ }
+
+ private void navigateToTaskWindow(@NotNull final Editor editor, @NotNull final TaskWindow firstTaskWindow) {
+ if (!firstTaskWindow.isValid(editor.getDocument())) {
+ return;
}
+ mySelectedTaskWindow = firstTaskWindow;
+ LogicalPosition taskWindowStart = new LogicalPosition(firstTaskWindow.getLine(), firstTaskWindow.getStart());
+ editor.getCaretModel().moveToLogicalPosition(taskWindowStart);
+ int startOffset = firstTaskWindow.getRealStartOffset(editor.getDocument());
+ int endOffset = startOffset + firstTaskWindow.getLength();
+ editor.getSelectionModel().setSelection(startOffset, endOffset);
+ }
+
+ public void navigateToFirstFailedTaskWindow(@NotNull final Editor editor) {
+ for (TaskWindow taskWindow : taskWindows) {
+ if (taskWindow.getStatus() != StudyStatus.Failed) {
+ continue;
+ }
+ navigateToTaskWindow(editor, taskWindow);
+ break;
+ }
+ }
+
+ public boolean hasFailedTaskWindows() {
+ return taskWindows.size() > 0 && getStatus() == StudyStatus.Failed;
}
}
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/course/TaskWindow.java b/python/edu/learn-python/src/com/jetbrains/python/edu/course/TaskWindow.java
index 4fb112cc1f9b..dc4a75a800ce 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/course/TaskWindow.java
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/course/TaskWindow.java
@@ -1,5 +1,8 @@
package com.jetbrains.python.edu.course;
+import com.intellij.execution.ExecutionException;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.colors.EditorColors;
@@ -8,16 +11,27 @@ import com.intellij.openapi.editor.markup.HighlighterLayer;
import com.intellij.openapi.editor.markup.HighlighterTargetArea;
import com.intellij.openapi.editor.markup.RangeHighlighter;
import com.intellij.openapi.editor.markup.TextAttributes;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.JBColor;
+import com.jetbrains.python.edu.StudyDocumentListener;
+import com.jetbrains.python.edu.StudyTestRunner;
+import com.jetbrains.python.edu.StudyUtils;
import org.jetbrains.annotations.NotNull;
+import java.io.File;
+import java.io.IOException;
+
/**
* Implementation of windows which user should type in
*/
public class TaskWindow implements Comparable, Stateful {
-
+ private static final String WINDOW_POSTFIX = "_window.py";
+ private static final Logger LOG = Logger.getInstance(TaskWindow.class);
public int line = 0;
public int start = 0;
public String hint = "";
@@ -174,4 +188,55 @@ public class TaskWindow implements Comparable, Stateful {
public int getIndex() {
return myIndex;
}
+
+ public void smartCheck(@NotNull final Project project,
+ @NotNull final VirtualFile answerFile,
+ @NotNull final TaskFile answerTaskFile,
+ @NotNull final TaskFile usersTaskFile,
+ @NotNull final StudyTestRunner testRunner,
+ @NotNull final VirtualFile virtualFile,
+ @NotNull final Document usersDocument) {
+
+ try {
+ VirtualFile windowCopy =
+ answerFile.copy(this, answerFile.getParent(), answerFile.getNameWithoutExtension() + WINDOW_POSTFIX);
+ final FileDocumentManager documentManager = FileDocumentManager.getInstance();
+ final Document windowDocument = documentManager.getDocument(windowCopy);
+ if (windowDocument != null) {
+ File resourceFile = StudyUtils.copyResourceFile(virtualFile.getName(), windowCopy.getName(), project, usersTaskFile.getTask());
+ TaskFile windowTaskFile = new TaskFile();
+ TaskFile.copy(answerTaskFile, windowTaskFile);
+ StudyDocumentListener listener = new StudyDocumentListener(windowTaskFile);
+ windowDocument.addDocumentListener(listener);
+ int start = getRealStartOffset(windowDocument);
+ int end = start + getLength();
+ TaskWindow userTaskWindow = usersTaskFile.getTaskWindows().get(getIndex());
+ int userStart = userTaskWindow.getRealStartOffset(usersDocument);
+ int userEnd = userStart + userTaskWindow.getLength();
+ String text = usersDocument.getText(new TextRange(userStart, userEnd));
+ windowDocument.replaceString(start, end, text);
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ documentManager.saveDocument(windowDocument);
+ }
+ });
+ VirtualFile fileWindows = StudyUtils.flushWindows(windowTaskFile, windowCopy);
+ Process smartTestProcess = testRunner.launchTests(project, windowCopy.getPath());
+ boolean res = testRunner.getPassedTests(smartTestProcess).equals(StudyTestRunner.TEST_OK);
+ userTaskWindow.setStatus(res ? StudyStatus.Solved : StudyStatus.Failed, StudyStatus.Unchecked);
+ StudyUtils.deleteFile(windowCopy);
+ StudyUtils.deleteFile(fileWindows);
+ if (!resourceFile.delete()) {
+ LOG.error("failed to delete", resourceFile.getPath());
+ }
+ }
+ }
+ catch (ExecutionException e) {
+ LOG.error(e);
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ }
} \ No newline at end of file
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/editor/StudyEditor.java b/python/edu/learn-python/src/com/jetbrains/python/edu/editor/StudyEditor.java
index 69c5acc5f127..6b27c4a406db 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/editor/StudyEditor.java
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/editor/StudyEditor.java
@@ -1,8 +1,10 @@
package com.jetbrains.python.edu.editor;
import com.intellij.codeHighlighting.BackgroundEditorHighlighter;
+import com.intellij.icons.AllIcons;
import com.intellij.ide.structureView.StructureViewBuilder;
import com.intellij.openapi.actionSystem.ActionManager;
+import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
@@ -17,9 +19,15 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.wm.IdeFocusManager;
+import com.intellij.openapi.wm.ToolWindow;
+import com.intellij.openapi.wm.ToolWindowId;
+import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.pom.Navigatable;
+import com.intellij.ui.BrowserHyperlinkListener;
import com.intellij.ui.HideableTitledPanel;
import com.intellij.ui.JBColor;
+import com.intellij.util.ui.EmptyClipboardOwner;
import com.intellij.util.ui.UIUtil;
import com.jetbrains.python.edu.StudyDocumentListener;
import com.jetbrains.python.edu.StudyTaskManager;
@@ -36,8 +44,8 @@ import javax.swing.text.MutableAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import java.awt.*;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
+import java.awt.datatransfer.StringSelection;
+import java.awt.event.*;
import java.beans.PropertyChangeListener;
import java.util.HashMap;
import java.util.Map;
@@ -50,12 +58,13 @@ public class StudyEditor implements TextEditor {
private static final String TASK_TEXT_HEADER = "Task Text";
private final FileEditor myDefaultEditor;
private final JComponent myComponent;
+ private final TaskFile myTaskFile;
private JButton myCheckButton;
private JButton myNextTaskButton;
private JButton myPrevTaskButton;
private JButton myRefreshButton;
private static final Map<Document, StudyDocumentListener> myDocumentListeners = new HashMap<Document, StudyDocumentListener>();
- private Project myProject;
+ private final Project myProject;
public JButton getCheckButton() {
return myCheckButton;
@@ -65,6 +74,10 @@ public class StudyEditor implements TextEditor {
return myPrevTaskButton;
}
+ public TaskFile getTaskFile() {
+ return myTaskFile;
+ }
+
private static JButton addButton(@NotNull final JComponent parentComponent, String toolTipText, Icon icon) {
JButton newButton = new JButton();
newButton.setToolTipText(toolTipText);
@@ -89,26 +102,72 @@ public class StudyEditor implements TextEditor {
myComponent = myDefaultEditor.getComponent();
JPanel studyPanel = new JPanel();
studyPanel.setLayout(new BoxLayout(studyPanel, BoxLayout.Y_AXIS));
- TaskFile taskFile = StudyTaskManager.getInstance(myProject).getTaskFile(file);
- if (taskFile != null) {
- Task currentTask = taskFile.getTask();
+ myTaskFile = StudyTaskManager.getInstance(myProject).getTaskFile(file);
+ if (myTaskFile != null) {
+ Task currentTask = myTaskFile.getTask();
String taskText = currentTask.getResourceText(project, currentTask.getText(), false);
initializeTaskText(studyPanel, taskText);
JPanel studyButtonPanel = new JPanel(new GridLayout(1, 2));
JPanel taskActionsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
studyButtonPanel.add(taskActionsPanel);
studyButtonPanel.add(new JPanel());
- initializeButtons(taskActionsPanel, taskFile);
+ initializeButtons(taskActionsPanel, myTaskFile);
studyPanel.add(studyButtonPanel);
myComponent.add(studyPanel, BorderLayout.NORTH);
}
}
- private static void initializeTaskText(JPanel studyPanel, @Nullable String taskText) {
+ class CopyListener extends MouseAdapter {
+ final JTextPane myTextPane;
+
+ public CopyListener(JTextPane textPane) {
+ myTextPane = textPane;
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ ToolWindow projectView = ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.PROJECT_VIEW);
+ if (projectView == null) {
+ return;
+ }
+ final Component focusComponent = projectView.getComponent();
+ IdeFocusManager.getInstance(myProject).requestFocus(focusComponent, true);
+ final String text = myTextPane.getSelectedText();
+ if (text == null) {
+ return;
+ }
+ KeyAdapter keyAdapter = new KeyAdapter() {
+ @Override
+ public void keyPressed(KeyEvent ev) {
+ if (ev.getKeyCode() == KeyEvent.VK_C
+ && ev.getModifiers() == InputEvent.CTRL_MASK) {
+ StringSelection selection = new StringSelection(text);
+ Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, EmptyClipboardOwner.INSTANCE);
+ ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ IdeFocusManager.getInstance(myProject).requestFocus(myDefaultEditor.getComponent(), true);
+ }
+ });
+ }
+ }
+ };
+ focusComponent.addKeyListener(keyAdapter);
+ }
+ });
+ }
+ }
+
+ private void initializeTaskText(JPanel studyPanel, @Nullable String taskText) {
JTextPane taskTextPane = new JTextPane();
+ taskTextPane.addMouseListener(new CopyListener(taskTextPane));
taskTextPane.setContentType("text/html");
taskTextPane.setEditable(false);
taskTextPane.setText(taskText);
+ taskTextPane.addHyperlinkListener(new BrowserHyperlinkListener());
EditorColorsScheme editorColorsScheme = EditorColorsManager.getInstance().getGlobalScheme();
int fontSize = editorColorsScheme.getEditorFontSize();
String fontName = editorColorsScheme.getEditorFontName();
@@ -134,10 +193,10 @@ public class StudyEditor implements TextEditor {
private void initializeButtons(@NotNull final JPanel taskActionsPanel, @NotNull final TaskFile taskFile) {
myCheckButton = addButton(taskActionsPanel, "Check task", StudyIcons.Resolve);
myPrevTaskButton = addButton(taskActionsPanel, "Prev Task", StudyIcons.Prev);
- myNextTaskButton = addButton(taskActionsPanel, "Next Task", StudyIcons.Next);
- myRefreshButton = addButton(taskActionsPanel, "Start task again", StudyIcons.Refresh24);
+ myNextTaskButton = addButton(taskActionsPanel, "Next Task", AllIcons.Actions.Forward);
+ myRefreshButton = addButton(taskActionsPanel, "Start task again", AllIcons.Actions.Refresh);
if (!taskFile.getTask().getUserTests().isEmpty()) {
- JButton runButton = addButton(taskActionsPanel, "Run", StudyIcons.Run);
+ JButton runButton = addButton(taskActionsPanel, "Run", AllIcons.General.Run);
runButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
@@ -149,7 +208,8 @@ public class StudyEditor implements TextEditor {
watchInputButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
- StudyEditInputAction studyEditInputAction = (StudyEditInputAction)ActionManager.getInstance().getAction("WatchInputAction");
+ StudyEditInputAction studyEditInputAction =
+ (StudyEditInputAction)ActionManager.getInstance().getAction("WatchInputAction");
studyEditInputAction.showInput(myProject);
}
});
@@ -165,7 +225,8 @@ public class StudyEditor implements TextEditor {
myNextTaskButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
- StudyNextStudyTaskAction studyNextTaskAction = (StudyNextStudyTaskAction)ActionManager.getInstance().getAction("NextTaskAction");
+ StudyNextStudyTaskAction studyNextTaskAction =
+ (StudyNextStudyTaskAction)ActionManager.getInstance().getAction("NextTaskAction");
studyNextTaskAction.navigateTask(myProject);
}
});
@@ -180,7 +241,8 @@ public class StudyEditor implements TextEditor {
myRefreshButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
- StudyRefreshTaskAction studyRefreshTaskAction = (StudyRefreshTaskAction)ActionManager.getInstance().getAction("RefreshTaskAction");
+ StudyRefreshTaskFileAction studyRefreshTaskAction =
+ (StudyRefreshTaskFileAction)ActionManager.getInstance().getAction("RefreshTaskAction");
studyRefreshTaskAction.refresh(myProject);
}
});
@@ -300,7 +362,8 @@ public class StudyEditor implements TextEditor {
if (fileEditor instanceof StudyEditor) {
return (StudyEditor)fileEditor;
}
- } catch (Exception e) {
+ }
+ catch (Exception e) {
return null;
}
return null;
@@ -325,8 +388,9 @@ public class StudyEditor implements TextEditor {
@NotNull
@Override
public Editor getEditor() {
- if (myDefaultEditor instanceof TextEditor)
+ if (myDefaultEditor instanceof TextEditor) {
return ((TextEditor)myDefaultEditor).getEditor();
+ }
return EditorFactory.getInstance().createViewer(new DocumentImpl(""), myProject);
}
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/highlighting/StudyVisitorFilter.java b/python/edu/learn-python/src/com/jetbrains/python/edu/highlighting/StudyVisitorFilter.java
new file mode 100644
index 000000000000..dc7495adb16e
--- /dev/null
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/highlighting/StudyVisitorFilter.java
@@ -0,0 +1,18 @@
+package com.jetbrains.python.edu.highlighting;
+
+import com.intellij.psi.PsiFile;
+import com.jetbrains.python.edu.StudyTaskManager;
+import com.jetbrains.python.inspections.PythonVisitorFilter;
+import com.jetbrains.python.inspections.unresolvedReference.PyUnresolvedReferencesInspection;
+import org.jetbrains.annotations.NotNull;
+
+public class StudyVisitorFilter implements PythonVisitorFilter {
+ @Override
+ public boolean isSupported(@NotNull final Class visitorClass, @NotNull final PsiFile file) {
+ if (StudyTaskManager.getInstance(file.getProject()).getCourse() == null) return true;
+ if (visitorClass == PyUnresolvedReferencesInspection.class) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/projectView/StudyDirectoryNode.java b/python/edu/learn-python/src/com/jetbrains/python/edu/projectView/StudyDirectoryNode.java
index abf648c5c82a..2f80dba12695 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/projectView/StudyDirectoryNode.java
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/projectView/StudyDirectoryNode.java
@@ -32,7 +32,7 @@ public class StudyDirectoryNode extends PsiDirectoryNode {
@Override
protected void updateImpl(PresentationData data) {
- data.setIcon(StudyIcons.Unchecked);
+ data.setIcon(StudyIcons.Task);
String valueName = myValue.getName();
StudyTaskManager studyTaskManager = StudyTaskManager.getInstance(myProject);
Course course = studyTaskManager.getCourse();
@@ -41,7 +41,7 @@ public class StudyDirectoryNode extends PsiDirectoryNode {
}
if (valueName.equals(myProject.getName())) {
data.clearText();
- data.addText(course.getName(), new SimpleTextAttributes(SimpleTextAttributes.STYLE_BOLD, JBColor.BLUE));
+ data.addText(course.getName(), new SimpleTextAttributes(SimpleTextAttributes.STYLE_PLAIN, JBColor.BLACK));
data.addText(" (" + valueName + ")", SimpleTextAttributes.GRAYED_ATTRIBUTES);
return;
}
@@ -91,15 +91,16 @@ public class StudyDirectoryNode extends PsiDirectoryNode {
StudyStatus taskStatus = stateful.getStatus();
switch (taskStatus) {
case Unchecked: {
- updatePresentation(data, additionalName, JBColor.blue, StudyIcons.Unchecked);
+ updatePresentation(data, additionalName, JBColor.BLACK, stateful instanceof Lesson ? StudyIcons.Lesson : StudyIcons.Task);
break;
}
case Solved: {
- updatePresentation(data, additionalName, new JBColor(new Color(0, 134, 0), new Color(98, 150, 85)), StudyIcons.Checked);
+ updatePresentation(data, additionalName, new JBColor(new Color(0, 134, 0), new Color(98, 150, 85)),
+ stateful instanceof Lesson ? StudyIcons.LessonCompl : StudyIcons.TaskCompl);
break;
}
case Failed: {
- updatePresentation(data, additionalName, JBColor.RED, StudyIcons.Failed);
+ updatePresentation(data, additionalName, JBColor.RED, stateful instanceof Lesson ? StudyIcons.Lesson : StudyIcons.TaskProbl);
}
}
}
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/ui/StudyNewProjectPanel.form b/python/edu/learn-python/src/com/jetbrains/python/edu/ui/StudyNewProjectPanel.form
index 133c38d4e8f8..8dd6506d710c 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/ui/StudyNewProjectPanel.form
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/ui/StudyNewProjectPanel.form
@@ -39,11 +39,9 @@
</component>
</children>
</grid>
- <component id="6c40c" class="javax.swing.JLabel">
+ <component id="6c40c" class="javax.swing.JLabel" binding="myLabel">
<constraints>
- <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false">
- <preferred-size width="81" height="-1"/>
- </grid>
+ <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<font/>
@@ -67,9 +65,7 @@
</component>
<component id="f1e10" class="javax.swing.JButton" binding="myRefreshButton">
<constraints>
- <grid row="0" column="3" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false">
- <minimum-size width="30" height="23"/>
- </grid>
+ <grid row="0" column="3" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<hideActionText value="false"/>
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/ui/StudyNewProjectPanel.java b/python/edu/learn-python/src/com/jetbrains/python/edu/ui/StudyNewProjectPanel.java
index 0f1ec08a8856..6edad63586f0 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/ui/StudyNewProjectPanel.java
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/ui/StudyNewProjectPanel.java
@@ -2,6 +2,7 @@ package com.jetbrains.python.edu.ui;
import com.intellij.facet.ui.FacetValidatorsManager;
import com.intellij.facet.ui.ValidationResult;
+import com.intellij.icons.AllIcons;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.vfs.VirtualFile;
@@ -9,7 +10,6 @@ import com.intellij.util.Consumer;
import com.jetbrains.python.edu.StudyDirectoryProjectGenerator;
import com.jetbrains.python.edu.StudyUtils;
import com.jetbrains.python.edu.course.CourseInfo;
-import icons.StudyIcons;
import javax.swing.*;
import java.awt.event.ActionEvent;
@@ -32,6 +32,7 @@ public class StudyNewProjectPanel{
private JPanel myContentPanel;
private JLabel myAuthorLabel;
private JLabel myDescriptionLabel;
+ private JLabel myLabel;
private final StudyDirectoryProjectGenerator myGenerator;
private static final String CONNECTION_ERROR = "<html>Failed to download courses.<br>Check your Internet connection.</html>";
private static final String INVALID_COURSE = "Selected course is invalid";
@@ -56,7 +57,9 @@ public class StudyNewProjectPanel{
}
initListeners();
myRefreshButton.setVisible(true);
- myRefreshButton.setIcon(StudyIcons.Refresh);
+ myRefreshButton.setIcon(AllIcons.Actions.Refresh);
+
+ myLabel.setPreferredSize(new JLabel("Project name").getPreferredSize());
}
private void initListeners() {