308a423d68f6833a4b309cf56afee0d9eeff2e08
[idea/community.git] / python / educational-core / student / src / com / jetbrains / edu / learning / actions / StudyTaskNavigationAction.java
1 package com.jetbrains.edu.learning.actions;
2
3 import com.intellij.ide.projectView.ProjectView;
4 import com.intellij.openapi.actionSystem.AnActionEvent;
5 import com.intellij.openapi.fileEditor.FileEditorManager;
6 import com.intellij.openapi.project.Project;
7 import com.intellij.openapi.ui.MessageType;
8 import com.intellij.openapi.ui.popup.Balloon;
9 import com.intellij.openapi.ui.popup.BalloonBuilder;
10 import com.intellij.openapi.ui.popup.JBPopupFactory;
11 import com.intellij.openapi.vfs.VirtualFile;
12 import com.intellij.openapi.wm.ToolWindow;
13 import com.intellij.openapi.wm.ToolWindowId;
14 import com.intellij.openapi.wm.ToolWindowManager;
15 import com.intellij.util.ui.tree.TreeUtil;
16 import com.jetbrains.edu.learning.core.EduNames;
17 import com.jetbrains.edu.learning.courseFormat.Task;
18 import com.jetbrains.edu.learning.courseFormat.TaskFile;
19 import com.jetbrains.edu.learning.StudyState;
20 import com.jetbrains.edu.learning.StudyUtils;
21 import com.jetbrains.edu.learning.editor.StudyEditor;
22 import org.jetbrains.annotations.NotNull;
23 import org.jetbrains.annotations.Nullable;
24
25 import javax.swing.*;
26 import javax.swing.tree.TreePath;
27 import java.util.Map;
28
29
30 abstract public class StudyTaskNavigationAction extends StudyActionWithShortcut {
31   public StudyTaskNavigationAction(@Nullable String text, @Nullable String description, @Nullable Icon icon) {
32     super(text, description, icon);
33   }
34
35   public void navigateTask(@NotNull final Project project) {
36     StudyEditor studyEditor = StudyUtils.getSelectedStudyEditor(project);
37     StudyState studyState = new StudyState(studyEditor);
38     if (!studyState.isValid()) {
39       return;
40     }
41     Task nextTask = getTargetTask(studyState.getTask());
42     if (nextTask == null) {
43       BalloonBuilder balloonBuilder =
44         JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(getNavigationFinishedMessage(), MessageType.INFO, null);
45       Balloon balloon = balloonBuilder.createBalloon();
46       assert studyEditor != null;
47       balloon.show(StudyUtils.computeLocation(studyEditor.getEditor()), Balloon.Position.above);
48       return;
49     }
50     for (VirtualFile file : FileEditorManager.getInstance(project).getOpenFiles()) {
51       FileEditorManager.getInstance(project).closeFile(file);
52     }
53     int nextTaskIndex = nextTask.getIndex();
54     int lessonIndex = nextTask.getLesson().getIndex();
55     Map<String, TaskFile> nextTaskFiles = nextTask.getTaskFiles();
56     if (nextTaskFiles.isEmpty()) {
57       return;
58     }
59     VirtualFile projectDir = project.getBaseDir();
60     String lessonDirName = EduNames.LESSON + String.valueOf(lessonIndex);
61     if (projectDir == null) {
62       return;
63     }
64     VirtualFile lessonDir = projectDir.findChild(lessonDirName);
65     if (lessonDir == null) {
66       return;
67     }
68     String taskDirName = EduNames.TASK + String.valueOf(nextTaskIndex);
69     VirtualFile taskDir = lessonDir.findChild(taskDirName);
70     if (taskDir == null) {
71       return;
72     }
73
74     VirtualFile shouldBeActive = getFileToActivate(project, nextTaskFiles, taskDir);
75     JTree tree = ProjectView.getInstance(project).getCurrentProjectViewPane().getTree();
76     TreePath path = TreeUtil.getFirstNodePath(tree);
77     tree.collapsePath(path);
78     if (shouldBeActive != null) {
79       ProjectView.getInstance(project).select(shouldBeActive, shouldBeActive, false);
80       FileEditorManager.getInstance(project).openFile(shouldBeActive, true);
81     }
82     ToolWindow runToolWindow = ToolWindowManager.getInstance(project).getToolWindow(ToolWindowId.RUN);
83     if (runToolWindow != null) {
84       runToolWindow.hide(null);
85     }
86   }
87
88   @Nullable
89   protected VirtualFile getFileToActivate(@NotNull Project project, Map<String, TaskFile> nextTaskFiles, VirtualFile taskDir) {
90     VirtualFile shouldBeActive = null;
91     for (Map.Entry<String, TaskFile> entry : nextTaskFiles.entrySet()) {
92       String name = entry.getKey();
93       TaskFile taskFile = entry.getValue();
94       VirtualFile srcDir = taskDir.findChild("src");
95       VirtualFile vf = srcDir == null ? taskDir.findChild(name) : srcDir.findChild(name);
96       if (vf != null) {
97         FileEditorManager.getInstance(project).openFile(vf, true);
98         if (!taskFile.getAnswerPlaceholders().isEmpty()) {
99           shouldBeActive = vf;
100         }
101       }
102     }
103     return shouldBeActive != null ? shouldBeActive : getFirstTaskFile(taskDir, project);
104   }
105
106   @Nullable
107   private static VirtualFile getFirstTaskFile(@NotNull final VirtualFile taskDir, @NotNull final Project project) {
108     for (VirtualFile virtualFile : taskDir.getChildren()) {
109       if (StudyUtils.getTaskFile(project, virtualFile) != null) {
110         return virtualFile;
111       }
112     }
113     return null;
114   }
115
116   @Override
117   public void actionPerformed(AnActionEvent e) {
118     Project project = e.getProject();
119     if (project == null) {
120       return;
121     }
122     navigateTask(project);
123   }
124
125   protected abstract String getNavigationFinishedMessage();
126
127   protected abstract Task getTargetTask(@NotNull final Task sourceTask);
128
129   @Override
130   public void update(AnActionEvent e) {
131     StudyUtils.updateAction(e);
132   }
133 }