Merge remote-tracking branch 'origin/master'

Conflicts:
	python/edu/learn-python/resources/courses/introduction_course.zip
This commit is contained in:
Ekaterina Tuzova
2014-08-19 20:08:36 +04:00
16 changed files with 545 additions and 258 deletions
@@ -54,7 +54,6 @@ public class SimpleAccessorReferenceSearcher extends QueryExecutorBase<PsiRefere
for (CustomPropertyScopeProvider provider : Extensions.getExtensions(CustomPropertyScopeProvider.EP_NAME)) {
additional = additional.union(provider.getScope(method.getProject()));
}
assert propertyName != null;
final SearchScope propScope = scope.intersectWith(method.getUseScope()).intersectWith(additional);
collector.searchWord(propertyName, propScope, UsageSearchContext.IN_FOREIGN_LANGUAGES, true, method);
}
@@ -246,6 +246,15 @@ public class UsageInfo {
return result;
}
@Override
public String toString() {
PsiReference reference = getReference();
if (reference == null) {
return super.toString();
}
return reference.getCanonicalText() + " (" + reference.getClass() + ")";
}
@Nullable
public PsiFile getFile() {
return mySmartPointer.getContainingFile();
@@ -54,6 +54,7 @@ public class RepositoryWithBranchPanel extends NonOpaquePanel implements TreeCel
super();
setLayout(new BorderLayout());
myRepositoryCheckbox = new JBCheckBox();
myRepositoryCheckbox.setFocusable(false);
myRepositoryCheckbox.setOpaque(false);
myRepositoryCheckbox.addActionListener(new ActionListener() {
@Override
@@ -77,15 +78,17 @@ public class RepositoryWithBranchPanel extends NonOpaquePanel implements TreeCel
protected void updateBorder(@NotNull final EditorEx editor) {
}
};
myDestBranchTextField.setBorder(UIUtil.getTableFocusCellHighlightBorder());//getTextFieldBorder());
myDestBranchTextField.setBorder(UIUtil.getTableFocusCellHighlightBorder());
myDestBranchTextField.setOneLineMode(true);
myDestBranchTextField.setOpaque(true);
myDestBranchTextField.addFocusListener(new FocusAdapter() {
FocusAdapter focusListener = new FocusAdapter() {
@Override
public void focusGained(FocusEvent e) {
myDestBranchTextField.selectAll();
}
});
};
myDestBranchTextField.addFocusListener(focusListener);
addFocusListener(focusListener);
myTextRenderer = new ColoredTreeCellRenderer() {
public void customizeCellRenderer(@NotNull JTree tree,
@@ -18,8 +18,10 @@ package com.intellij.xdebugger.impl.evaluate;
import com.intellij.openapi.editor.EditorLinePainter;
import com.intellij.openapi.editor.LineExtensionInfo;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.JBColor;
import com.intellij.ui.SimpleColoredText;
@@ -30,15 +32,13 @@ import com.intellij.xdebugger.impl.ui.tree.nodes.XValueTextRendererImpl;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.*;
/**
* @author Konstantin Bulenkov
*/
public class XDebuggerEditorLinePainter extends EditorLinePainter {
public static final Key<Map<Variable, VariableValue>> CACHE = Key.create("debug.frame");
@Override
public Collection<LineExtensionInfo> getLineExtensions(@NotNull Project project, @NotNull VirtualFile file, int lineNumber) {
if (!Registry.is("ide.debugger.inline")) {
@@ -46,6 +46,11 @@ public class XDebuggerEditorLinePainter extends EditorLinePainter {
}
Map<Pair<VirtualFile, Integer>, Set<XValueNodeImpl>> map = project.getUserData(XVariablesView.DEBUG_VARIABLES);
Map<Variable, VariableValue> oldValues = project.getUserData(CACHE);
if (oldValues == null) {
oldValues = new HashMap<Variable, VariableValue>();
project.putUserData(CACHE, oldValues);
}
if (map != null) {
Set<XValueNodeImpl> values = map.get(Pair.create(file, lineNumber));
if (values != null && !values.isEmpty()) {
@@ -61,9 +66,29 @@ public class XDebuggerEditorLinePainter extends EditorLinePainter {
presentation.renderValue(renderer);
}
final Color color = new JBColor(new Color(61, 128, 101), new Color(61, 128, 101));
result.add(new LineExtensionInfo(" " + value.getName() + ": ", color, null, null, Font.PLAIN));
for (String s : text.getTexts()) {
result.add(new LineExtensionInfo(s, color, null, null, Font.PLAIN));
final String name = value.getName();
result.add(new LineExtensionInfo(" " + name + ": ", color, null, null, Font.PLAIN));
Variable var = new Variable(name, value.hashCode(), lineNumber);
VariableValue variableValue = oldValues.get(var);
if (variableValue == null) {
variableValue = new VariableValue(text.toString(), null, value.hashCode());
oldValues.put(var, variableValue);
}
if (variableValue.valueNodeHashCode != value.hashCode()) {
variableValue.old = variableValue.actual;
variableValue.actual = text.toString();
variableValue.valueNodeHashCode = value.hashCode();
}
if (!variableValue.isChanged()) {
for (String s : text.getTexts()) {
result.add(new LineExtensionInfo(s, color, null, null, Font.PLAIN));
}
} else {
for (String s : text.getTexts()) {
result.add(new LineExtensionInfo(s, new JBColor(new Color(202, 128, 33), new Color(116, 114, 4)), null, null, Font.BOLD));
}
}
}
return result;
@@ -72,4 +97,50 @@ public class XDebuggerEditorLinePainter extends EditorLinePainter {
return null;
}
static class Variable {
private int lineNumber;
private String name;
public Variable(String name, int nodeHashCode, int lineNumber) {
this.lineNumber = lineNumber;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Variable variable = (Variable)o;
if (lineNumber != variable.lineNumber) return false;
if (!name.equals(variable.name)) return false;
return true;
}
@Override
public int hashCode() {
int result = lineNumber;
result = 31 * result + name.hashCode();
return result;
}
}
static class VariableValue {
private String actual;
private String old;
private int valueNodeHashCode;
public VariableValue(String actual, String old, int valueNodeHashCode) {
this.actual = actual;
this.old = old;
this.valueNodeHashCode = valueNodeHashCode;
}
public boolean isChanged() {
return old != null && !StringUtil.equals(actual, old);
}
}
}
@@ -68,6 +68,7 @@ public class HgChangeProvider implements ChangeProvider {
public void getChanges(VcsDirtyScope dirtyScope, ChangelistBuilder builder,
ProgressIndicator progress, ChangeListManagerGate addGate) throws VcsException {
if (myProject.isDisposed()) return;
final Collection<HgChange> changes = new HashSet<HgChange>();
changes.addAll(process(builder, dirtyScope.getRecursivelyDirtyDirectories()));
changes.addAll(process(builder, dirtyScope.getDirtyFiles()));
+2 -2
View File
@@ -366,7 +366,7 @@ private layoutWin(Map args, String target) {
winScripts(target, ch, "pycharm.bat", args)
winVMOptions(target, null, "pycharm.exe")
ant.copy(file: "$home/python/help/pycharm-eduhelp.jar ", todir: "$target/help", failonerror: false)
ant.copy(file: "$home/python/help/pycharm-eduhelp.jar", todir: "$target/help", failonerror: false)
}
private layoutUnix(Map args, String target) {
@@ -383,7 +383,7 @@ private layoutUnix(Map args, String target) {
unixScripts(target, ch, "pycharm.sh", args)
unixVMOptions(target, "pycharm")
ant.copy(file: "$home/python/help/pycharm-eduhelp.jar ", todir: "$target/help", failonerror: false)
ant.copy(file: "$home/python/help/pycharm-eduhelp.jar", todir: "$target/help", failonerror: false)
}
private layoutMac(Map _args, String target) {
@@ -0,0 +1,56 @@
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(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 StudyEditor getStudyEditor() {
return myStudyEditor;
}
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;
}
}
@@ -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;
}
}
@@ -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;
@@ -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;
}
}
@@ -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,94 +12,80 @@ 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.vfs.VirtualFile;
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.ArrayList;
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;
}
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 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;
}
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);
}
finally {
StudyUtils.closeSilently(testOutputReader);
}
return TEST_OK;
StudyUtils.flushWindows(taskFile, virtualFile);
}
}
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);
}
}
}
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;
}
FileEditor fileEditor = FileEditorManager.getInstance(project).getSelectedEditor(virtualFile);
if (fileEditor instanceof StudyEditor) {
StudyEditor studyEditor = (StudyEditor)fileEditor;
taskFile.drawAllWindows(studyEditor.getEditor());
}
}
}
public void check(@NotNull final Project project) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
@@ -108,188 +93,126 @@ 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);
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);
}
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!", MessageType.INFO.getPopupBackground(), project);
return;
}
currentTask.setStatus(StudyStatus.Failed, oldStatus);
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);
}
}
StudyUtils.updateStudyToolWindow(project);
createTestResultPopUp(failedMessage, MessageType.ERROR.getPopupBackground(), 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);
}
catch (ExecutionException e) {
LOG.error(e);
}
FileEditorManager.getInstance(project).openFile(fileToNavigate, true);
IdeFocusManager.getInstance(project).requestFocus(editor.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;
}
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) {
@@ -316,8 +239,6 @@ public class StudyCheckAction extends DumbAwareAction {
catch (IOException e) {
LOG.error(e);
}
return copy;
}
@@ -11,6 +11,8 @@ 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.intellij.openapi.wm.ToolWindowId;
import com.intellij.openapi.wm.ToolWindowManager;
import com.jetbrains.python.edu.StudyTaskManager;
import com.jetbrains.python.edu.course.Lesson;
import com.jetbrains.python.edu.course.Task;
@@ -82,6 +84,7 @@ abstract public class StudyTaskNavigationAction extends DumbAwareAction {
if (shouldBeActive != null) {
FileEditorManager.getInstance(project).openFile(shouldBeActive, true);
}
ToolWindowManager.getInstance(project).getToolWindow(ToolWindowId.RUN).hide(null);
}
protected abstract JButton getButton(StudyEditor selectedStudyEditor);
@@ -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
@@ -217,12 +217,30 @@ 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) {
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;
}
}
@@ -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);
}
}
}
@@ -52,6 +52,7 @@ 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;
@@ -67,6 +68,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);
@@ -91,16 +96,16 @@ 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);
}
@@ -35,14 +35,15 @@ import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.keymap.Keymap;
import com.intellij.openapi.keymap.ex.KeymapManagerEx;
import com.intellij.openapi.keymap.impl.KeymapImpl;
import com.intellij.openapi.project.DumbAwareRunnable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.project.ProjectManagerAdapter;
import com.intellij.openapi.project.ex.ProjectManagerEx;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.wm.ToolWindowEP;
import com.intellij.openapi.wm.ToolWindowId;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.openapi.wm.*;
import com.intellij.platform.DirectoryProjectConfigurator;
import com.intellij.platform.PlatformProjectViewOpener;
import com.intellij.psi.codeStyle.CodeStyleSettings;
@@ -93,6 +94,8 @@ public class PyCharmEduInitialConfigurator {
uiSettings.SHOW_MAIN_TOOLBAR = false;
codeInsightSettings.REFORMAT_ON_PASTE = CodeInsightSettings.NO_REFORMAT;
Registry.get("ide.file.settings.order.new").setValue(true);
GeneralSettings.getInstance().setShowTipsOnStartup(false);
EditorSettingsExternalizable.getInstance().setVirtualSpace(false);
@@ -147,6 +150,29 @@ public class PyCharmEduInitialConfigurator {
}
patchProjectAreaExtensions(project);
StartupManager.getInstance(project).runWhenProjectIsInitialized(new DumbAwareRunnable() {
@Override
public void run() {
if (project.isDisposed()) return;
ToolWindowManager.getInstance(project).invokeLater(new Runnable() {
int count = 0;
public void run() {
if (project.isDisposed()) return;
if (count++ < 3) { // we need to call this after ToolWindowManagerImpl.registerToolWindowsFromBeans
ToolWindowManager.getInstance(project).invokeLater(this);
return;
}
ToolWindow toolWindow = ToolWindowManager.getInstance(project).getToolWindow("Project");
if (toolWindow.getType() != ToolWindowType.SLIDING) {
toolWindow.activate(null);
}
}
});
}
});
}
});
}