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