1 package com.jetbrains.edu.learning;
3 import com.intellij.ide.ui.UISettings;
4 import com.intellij.notification.Notification;
5 import com.intellij.notification.NotificationType;
6 import com.intellij.openapi.actionSystem.*;
7 import com.intellij.openapi.actionSystem.ex.AnActionListener;
8 import com.intellij.openapi.application.ApplicationManager;
9 import com.intellij.openapi.components.ProjectComponent;
10 import com.intellij.openapi.diagnostic.Logger;
11 import com.intellij.openapi.editor.EditorFactory;
12 import com.intellij.openapi.keymap.Keymap;
13 import com.intellij.openapi.keymap.ex.KeymapManagerEx;
14 import com.intellij.openapi.module.Module;
15 import com.intellij.openapi.module.ModuleManager;
16 import com.intellij.openapi.project.DumbAwareRunnable;
17 import com.intellij.openapi.project.Project;
18 import com.intellij.openapi.util.Pair;
19 import com.intellij.openapi.util.io.FileUtil;
20 import com.intellij.openapi.vfs.VirtualFile;
21 import com.intellij.openapi.vfs.VirtualFileAdapter;
22 import com.intellij.openapi.vfs.VirtualFileEvent;
23 import com.intellij.openapi.vfs.VirtualFileManager;
24 import com.intellij.openapi.wm.ToolWindow;
25 import com.intellij.openapi.wm.ToolWindowAnchor;
26 import com.intellij.openapi.wm.ToolWindowManager;
27 import com.intellij.util.containers.hash.HashMap;
28 import com.jetbrains.edu.EduNames;
29 import com.jetbrains.edu.EduUtils;
30 import com.jetbrains.edu.courseFormat.Course;
31 import com.jetbrains.edu.courseFormat.Lesson;
32 import com.jetbrains.edu.courseFormat.Task;
33 import com.jetbrains.edu.courseFormat.TaskFile;
34 import com.jetbrains.edu.learning.actions.StudyToolbarAction;
35 import com.jetbrains.edu.learning.editor.StudyEditorFactoryListener;
36 import com.jetbrains.edu.learning.ui.StudyProgressToolWindowFactory;
37 import com.jetbrains.edu.learning.ui.StudyToolWindow;
38 import com.jetbrains.edu.learning.ui.StudyToolWindowFactory;
39 import javafx.application.Platform;
40 import org.jetbrains.annotations.NotNull;
41 import org.jetbrains.annotations.Nullable;
45 import java.io.IOException;
46 import java.util.ArrayList;
47 import java.util.List;
51 public class StudyProjectComponent implements ProjectComponent {
52 private static final Logger LOG = Logger.getInstance(StudyProjectComponent.class.getName());
53 private final Project myProject;
54 private FileCreatedByUserListener myListener;
55 // Shows could we use JavaFX Task Description panel or should use Swing
56 private boolean useJavaFx = true;
57 private Map<Keymap, List<Pair<String, String>>> myDeletedShortcuts = new HashMap<Keymap, List<Pair<String, String>>>();
58 private StudyProjectComponent(@NotNull final Project project) {
63 public void projectOpened() {
64 final Course course = StudyTaskManager.getInstance(myProject).getCourse();
65 // Check if user has javafx lib in his JDK. Now bundled JDK doesn't have this lib inside.
67 Platform.setImplicitExit(false);
69 catch (NoClassDefFoundError e) {
73 if (course != null && !course.isUpToDate()) {
74 course.setUpToDate(true);
78 registerStudyToolWindow(course);
79 ApplicationManager.getApplication().invokeLater(new DumbAwareRunnable() {
82 ApplicationManager.getApplication().runWriteAction(new DumbAwareRunnable() {
86 UISettings.getInstance().HIDE_TOOL_STRIPES = false;
87 UISettings.getInstance().fireUISettingsChanged();
96 public void registerStudyToolWindow(@Nullable final Course course) {
97 if (course != null && "PyCharm".equals(course.getCourseType())) {
98 final ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(myProject);
99 registerToolWindows(toolWindowManager);
100 final ToolWindow studyToolWindow = toolWindowManager.getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW);
101 final ToolWindow progressToolWindow = toolWindowManager.getToolWindow(StudyProgressToolWindowFactory.ID);
102 if (studyToolWindow != null) {
103 studyToolWindow.show(null);
105 if (progressToolWindow != null) {
106 StudyUtils.initToolWindows(myProject);
107 progressToolWindow.show(null);
112 private void registerShortcuts() {
113 StudyToolWindow window = StudyUtils.getStudyToolWindow(myProject);
114 if (window != null) {
115 List<AnAction> actionsOnToolbar = window.getActions(true);
116 if (actionsOnToolbar != null) {
117 for (AnAction action : actionsOnToolbar) {
118 if (action instanceof StudyToolbarAction) {
119 String id = ((StudyToolbarAction)action).getActionId();
120 String[] shortcuts = ((StudyToolbarAction)action).getShortcuts();
121 addShortcut(id, shortcuts);
126 LOG.warn("Actions on toolbar are nulls");
131 private void registerToolWindows(@NotNull final ToolWindowManager toolWindowManager) {
132 final ToolWindow toolWindow = toolWindowManager.getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW);
133 if (toolWindow == null) {
134 toolWindowManager.registerToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW, true, ToolWindowAnchor.RIGHT, myProject, true);
136 ToolWindow progressToolWindow = toolWindowManager.getToolWindow(StudyProgressToolWindowFactory.ID);
137 if (progressToolWindow == null) {
138 toolWindowManager.registerToolWindow(StudyProgressToolWindowFactory.ID, true, ToolWindowAnchor.LEFT, myProject, true, true);
142 private void updateCourse() {
143 final Course course = StudyTaskManager.getInstance(myProject).getCourse();
144 if (course == null) {
147 final File resourceDirectory = new File(course.getCourseDirectory());
148 if (!resourceDirectory.exists()) {
151 StudyLanguageManager manager = StudyUtils.getLanguageManager(course);
152 if (manager == null) {
153 LOG.info("Study Language Manager is null for " + course.getLanguageById().getDisplayName());
156 final File[] files = resourceDirectory.listFiles();
157 if (files == null) return;
158 for (File file : files) {
159 String testHelper = manager.getTestHelperFileName();
160 if (file.getName().equals(testHelper)) {
161 copyFile(file, new File(myProject.getBasePath(), testHelper));
163 if (file.getName().startsWith(EduNames.LESSON)) {
164 final File[] tasks = file.listFiles();
165 if (tasks == null) continue;
166 for (File task : tasks) {
167 final File taskDescr = new File(task, EduNames.TASK_HTML);
168 String testFileName = manager.getTestFileName();
169 final File taskTests = new File(task, testFileName);
170 copyFile(taskDescr, new File(new File(new File(myProject.getBasePath(), file.getName()), task.getName()), EduNames.TASK_HTML));
171 copyFile(taskTests, new File(new File(new File(myProject.getBasePath(), file.getName()), task.getName()),
177 final Notification notification =
178 new Notification("Update.course", "Course update", "Current course is synchronized", NotificationType.INFORMATION);
179 notification.notify(myProject);
182 private static void copyFile(@NotNull final File from, @NotNull final File to) {
185 FileUtil.copy(from, to);
187 catch (IOException e) {
188 LOG.warn("Failed to copy " + from.getName());
193 private void addShortcut(@NotNull final String actionIdString, @NotNull final String[] shortcuts) {
194 KeymapManagerEx keymapManager = KeymapManagerEx.getInstanceEx();
195 for (Keymap keymap : keymapManager.getAllKeymaps()) {
196 List<Pair<String, String>> pairs = myDeletedShortcuts.get(keymap);
198 pairs = new ArrayList<Pair<String, String>>();
199 myDeletedShortcuts.put(keymap, pairs);
201 for (String shortcutString : shortcuts) {
202 Shortcut studyActionShortcut = new KeyboardShortcut(KeyStroke.getKeyStroke(shortcutString), null);
203 String[] actionsIds = keymap.getActionIds(studyActionShortcut);
204 for (String actionId : actionsIds) {
205 pairs.add(Pair.create(actionId, shortcutString));
206 keymap.removeShortcut(actionId, studyActionShortcut);
208 keymap.addShortcut(actionIdString, studyActionShortcut);
214 public void projectClosed() {
215 final Course course = StudyTaskManager.getInstance(myProject).getCourse();
216 if (course != null) {
217 final ToolWindow toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW);
218 if (toolWindow != null) {
219 toolWindow.getContentManager().removeAllContents(false);
221 final ToolWindow progressToolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(StudyProgressToolWindowFactory.ID);
222 if (progressToolWindow != null) {
223 progressToolWindow.getContentManager().removeAllContents(false);
225 KeymapManagerEx keymapManager = KeymapManagerEx.getInstanceEx();
226 for (Keymap keymap : keymapManager.getAllKeymaps()) {
227 List<Pair<String, String>> pairs = myDeletedShortcuts.get(keymap);
228 if (pairs != null && !pairs.isEmpty()) {
229 for (Pair<String, String> actionShortcut : pairs) {
230 keymap.addShortcut(actionShortcut.first, new KeyboardShortcut(KeyStroke.getKeyStroke(actionShortcut.second), null));
239 public void initComponent() {
240 EditorFactory.getInstance().addEditorFactoryListener(new StudyEditorFactoryListener(), myProject);
241 ActionManager.getInstance().addAnActionListener(new AnActionListener() {
243 public void beforeActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) {
244 AnAction[] newGroupActions = ((ActionGroup)ActionManager.getInstance().getAction("NewGroup")).getChildren(null);
245 for (AnAction newAction : newGroupActions) {
246 if (newAction == action) {
247 myListener = new FileCreatedByUserListener();
248 VirtualFileManager.getInstance().addVirtualFileListener(myListener);
255 public void afterActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) {
256 AnAction[] newGroupActions = ((ActionGroup)ActionManager.getInstance().getAction("NewGroup")).getChildren(null);
257 for (AnAction newAction : newGroupActions) {
258 if (newAction == action) {
259 VirtualFileManager.getInstance().removeVirtualFileListener(myListener);
265 public void beforeEditorTyping(char c, DataContext dataContext) {
272 public void disposeComponent() {
277 public String getComponentName() {
278 return "StudyTaskManager";
281 public static StudyProjectComponent getInstance(@NotNull final Project project) {
282 final Module module = ModuleManager.getInstance(project).getModules()[0];
283 return module.getComponent(StudyProjectComponent.class);
286 public boolean useJavaFx() {
290 private class FileCreatedByUserListener extends VirtualFileAdapter {
292 public void fileCreated(@NotNull VirtualFileEvent event) {
293 if (myProject.isDisposed()) return;
294 final VirtualFile createdFile = event.getFile();
295 final VirtualFile taskDir = createdFile.getParent();
296 final Course course = StudyTaskManager.getInstance(myProject).getCourse();
297 if (taskDir != null && taskDir.getName().contains(EduNames.TASK)) {
298 int taskIndex = EduUtils.getIndex(taskDir.getName(), EduNames.TASK);
299 final VirtualFile lessonDir = taskDir.getParent();
300 if (lessonDir != null && lessonDir.getName().contains(EduNames.LESSON)) {
301 int lessonIndex = EduUtils.getIndex(lessonDir.getName(), EduNames.LESSON);
302 if (course != null) {
303 List<Lesson> lessons = course.getLessons();
304 if (StudyUtils.indexIsValid(lessonIndex, lessons)) {
305 final Lesson lesson = lessons.get(lessonIndex);
306 final List<Task> tasks = lesson.getTaskList();
307 if (StudyUtils.indexIsValid(taskIndex, tasks)) {
308 final Task task = tasks.get(taskIndex);
309 final TaskFile taskFile = new TaskFile();
310 taskFile.initTaskFile(task, false);
311 taskFile.setUserCreated(true);
312 final String name = createdFile.getName();
313 taskFile.name = name;
314 task.getTaskFiles().put(name, taskFile);