blob: 3013fbcb05d30dc4272175a927a44ec43d3a71f7 [file] [log] [blame]
package com.jetbrains.python.edu;
import com.intellij.ide.ui.UISettings;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.ex.AnActionListener;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.*;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.keymap.Keymap;
import com.intellij.openapi.keymap.KeymapManager;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.DumbAwareRunnable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileAdapter;
import com.intellij.openapi.vfs.VirtualFileEvent;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.wm.*;
import com.intellij.util.xmlb.XmlSerializer;
import com.jetbrains.python.edu.actions.StudyNextWindowAction;
import com.jetbrains.python.edu.actions.StudyPrevWindowAction;
import com.jetbrains.python.edu.actions.StudyShowHintAction;
import com.jetbrains.python.edu.course.Course;
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.ui.StudyCondition;
import com.jetbrains.python.edu.ui.StudyToolWindowFactory;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Implementation of class which contains all the information
* about study in context of current project
*/
@State(
name = "StudySettings",
storages = {
@Storage(
id = "others",
file = "$PROJECT_CONFIG_DIR$/study_project.xml",
scheme = StorageScheme.DIRECTORY_BASED
)}
)
public class StudyTaskManager implements ProjectComponent, PersistentStateComponent<Element>, DumbAware {
public static final String COURSE_ELEMENT = "courseElement";
private static Map<String, StudyTaskManager> myTaskManagers = new HashMap<String, StudyTaskManager>();
private static Map<String, String> myDeletedShortcuts = new HashMap<String, String>();
private final Project myProject;
private Course myCourse;
private FileCreatedListener myListener;
public void setCourse(Course course) {
myCourse = course;
}
private StudyTaskManager(@NotNull final Project project) {
myTaskManagers.put(project.getBasePath(), this);
myProject = project;
}
@Nullable
public Course getCourse() {
return myCourse;
}
@Nullable
@Override
public Element getState() {
Element el = new Element("taskManager");
if (myCourse != null) {
Element courseElement = new Element(COURSE_ELEMENT);
XmlSerializer.serializeInto(myCourse, courseElement);
el.addContent(courseElement);
}
return el;
}
@Override
public void loadState(Element el) {
myCourse = XmlSerializer.deserialize(el.getChild(COURSE_ELEMENT), Course.class);
if (myCourse != null) {
myCourse.init(true);
}
}
@Override
public void projectOpened() {
ApplicationManager.getApplication().invokeLater(new DumbAwareRunnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new DumbAwareRunnable() {
@Override
public void run() {
if (myCourse != null) {
StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new Runnable() {
@Override
public void run() {
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;
try {
Method method = toolWindowManager.getClass().getDeclaredMethod("registerToolWindow", String.class,
JComponent.class,
ToolWindowAnchor.class,
boolean.class, boolean.class, boolean.class);
method.setAccessible(true);
method.invoke(toolWindowManager, toolWindowId, null, ToolWindowAnchor.LEFT, true, true, true);
}
catch (Exception e) {
final ToolWindow toolWindow = toolWindowManager.getToolWindow(toolWindowId);
if (toolWindow == null)
toolWindowManager.registerToolWindow(toolWindowId, true, ToolWindowAnchor.RIGHT, myProject, true);
}
final ToolWindow studyToolWindow = toolWindowManager.getToolWindow(toolWindowId);
if (studyToolWindow != null) {
StudyUtils.updateStudyToolWindow(myProject);
studyToolWindow.show(null);
}
addShortcut(StudyNextWindowAction.SHORTCUT, StudyNextWindowAction.ACTION_ID);
addShortcut(StudyPrevWindowAction.SHORTCUT, StudyPrevWindowAction.ACTION_ID);
addShortcut(StudyShowHintAction.SHORTCUT, StudyShowHintAction.ACTION_ID);
addShortcut(StudyNextWindowAction.SHORTCUT2, StudyNextWindowAction.ACTION_ID);
}
}
});
}
});
}
private static void addShortcut(@NotNull final String shortcutString, @NotNull final String actionIdString) {
Keymap keymap = KeymapManager.getInstance().getActiveKeymap();
Shortcut studyActionShortcut = new KeyboardShortcut(KeyStroke.getKeyStroke(shortcutString), null);
String[] actionsIds = keymap.getActionIds(studyActionShortcut);
for (String actionId : actionsIds) {
myDeletedShortcuts.put(actionId, shortcutString);
keymap.removeShortcut(actionId, studyActionShortcut);
}
keymap.addShortcut(actionIdString, studyActionShortcut);
}
@Override
public void projectClosed() {
StudyCondition.VALUE = false;
if (myCourse != null) {
ToolWindowManager.getInstance(myProject).getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW).getContentManager()
.removeAllContents(false);
if (!myDeletedShortcuts.isEmpty()) {
for (Map.Entry<String, String> shortcut : myDeletedShortcuts.entrySet()) {
Keymap keymap = KeymapManager.getInstance().getActiveKeymap();
Shortcut actionShortcut = new KeyboardShortcut(KeyStroke.getKeyStroke(shortcut.getValue()), null);
keymap.addShortcut(shortcut.getKey(), actionShortcut);
}
}
}
}
@Override
public void initComponent() {
EditorFactory.getInstance().addEditorFactoryListener(new StudyEditorFactoryListener(), myProject);
ActionManager.getInstance().addAnActionListener(new AnActionListener() {
@Override
public void beforeActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) {
AnAction[] newGroupActions = ((ActionGroup)ActionManager.getInstance().getAction("NewGroup")).getChildren(null);
for (AnAction newAction : newGroupActions) {
if (newAction == action) {
myListener = new FileCreatedListener();
VirtualFileManager.getInstance().addVirtualFileListener(myListener);
break;
}
}
}
@Override
public void afterActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) {
AnAction[] newGroupActions = ((ActionGroup)ActionManager.getInstance().getAction("NewGroup")).getChildren(null);
for (AnAction newAction : newGroupActions) {
if (newAction == action) {
VirtualFileManager.getInstance().removeVirtualFileListener(myListener);
}
}
}
@Override
public void beforeEditorTyping(char c, DataContext dataContext) {
}
});
}
@Override
public void disposeComponent() {
}
@NotNull
@Override
public String getComponentName() {
return "StudyTaskManager";
}
public static StudyTaskManager getInstance(@NotNull final Project project) {
StudyTaskManager item = myTaskManagers.get(project.getBasePath());
return item != null ? item : new StudyTaskManager(project);
}
@Nullable
public TaskFile getTaskFile(@NotNull final VirtualFile file) {
if (myCourse == null) {
return null;
}
VirtualFile taskDir = file.getParent();
if (taskDir != null) {
String taskDirName = taskDir.getName();
if (taskDirName.contains(Task.TASK_DIR)) {
VirtualFile lessonDir = taskDir.getParent();
if (lessonDir != null) {
String lessonDirName = lessonDir.getName();
int lessonIndex = StudyUtils.getIndex(lessonDirName, Lesson.LESSON_DIR);
List<Lesson> lessons = myCourse.getLessons();
if (!StudyUtils.indexIsValid(lessonIndex, lessons)) {
return null;
}
Lesson lesson = lessons.get(lessonIndex);
int taskIndex = StudyUtils.getIndex(taskDirName, Task.TASK_DIR);
List<Task> tasks = lesson.getTaskList();
if (!StudyUtils.indexIsValid(taskIndex, tasks)) {
return null;
}
Task task = tasks.get(taskIndex);
return task.getFile(file.getName());
}
}
}
return null;
}
class FileCreatedListener extends VirtualFileAdapter {
@Override
public void fileCreated(@NotNull VirtualFileEvent event) {
VirtualFile createdFile = event.getFile();
VirtualFile taskDir = createdFile.getParent();
String taskLogicalName = Task.TASK_DIR;
if (taskDir != null && taskDir.getName().contains(taskLogicalName)) {
int taskIndex = StudyUtils.getIndex(taskDir.getName(), taskLogicalName);
VirtualFile lessonDir = taskDir.getParent();
String lessonLogicalName = Lesson.LESSON_DIR;
if (lessonDir != null && lessonDir.getName().contains(lessonLogicalName)) {
int lessonIndex = StudyUtils.getIndex(lessonDir.getName(), lessonLogicalName);
if (myCourse != null) {
List<Lesson> lessons = myCourse.getLessons();
if (StudyUtils.indexIsValid(lessonIndex, lessons)) {
Lesson lesson = lessons.get(lessonIndex);
List<Task> tasks = lesson.getTaskList();
if (StudyUtils.indexIsValid(taskIndex, tasks)) {
Task task = tasks.get(taskIndex);
TaskFile taskFile = new TaskFile();
taskFile.init(task, false);
taskFile.setUserCreated(true);
task.getTaskFiles().put(createdFile.getName(), taskFile);
}
}
}
}
}
}
}
}