new editing mode for task description panel
[idea/community.git] / python / educational-core / student / src / com / jetbrains / edu / learning / actions / StudyRefreshTaskFileAction.java
1 package com.jetbrains.edu.learning.actions;
2
3 import com.intellij.icons.AllIcons;
4 import com.intellij.ide.projectView.ProjectView;
5 import com.intellij.openapi.actionSystem.AnActionEvent;
6 import com.intellij.openapi.actionSystem.KeyboardShortcut;
7 import com.intellij.openapi.application.ApplicationManager;
8 import com.intellij.openapi.command.CommandProcessor;
9 import com.intellij.openapi.diagnostic.Logger;
10 import com.intellij.openapi.editor.Document;
11 import com.intellij.openapi.editor.Editor;
12 import com.intellij.openapi.keymap.KeymapUtil;
13 import com.intellij.openapi.project.Project;
14 import com.intellij.openapi.ui.MessageType;
15 import com.intellij.openapi.ui.Messages;
16 import com.intellij.openapi.ui.popup.Balloon;
17 import com.intellij.openapi.ui.popup.BalloonBuilder;
18 import com.intellij.openapi.ui.popup.JBPopupFactory;
19 import com.intellij.openapi.util.Disposer;
20 import com.intellij.openapi.wm.IdeFocusManager;
21 import com.intellij.problems.WolfTheProblemSolver;
22 import com.jetbrains.edu.learning.core.EduAnswerPlaceholderPainter;
23 import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
24 import com.jetbrains.edu.learning.courseFormat.StudyStatus;
25 import com.jetbrains.edu.learning.courseFormat.TaskFile;
26 import com.jetbrains.edu.learning.StudyState;
27 import com.jetbrains.edu.learning.StudyTaskManager;
28 import com.jetbrains.edu.learning.StudyUtils;
29 import com.jetbrains.edu.learning.editor.StudyEditor;
30 import com.jetbrains.edu.learning.navigation.StudyNavigator;
31 import org.jetbrains.annotations.NotNull;
32 import org.jetbrains.annotations.Nullable;
33
34 import javax.swing.*;
35
36 public class StudyRefreshTaskFileAction extends StudyActionWithShortcut {
37   public static final String ACTION_ID = "RefreshTaskAction";
38   public static final String SHORTCUT = "ctrl shift pressed X";
39   private static final Logger LOG = Logger.getInstance(StudyRefreshTaskFileAction.class.getName());
40
41   public StudyRefreshTaskFileAction() {
42     super("Reset Task File (" + KeymapUtil.getShortcutText(new KeyboardShortcut(KeyStroke.getKeyStroke(SHORTCUT), null)) + ")", "Refresh current task", AllIcons.Actions.Refresh);
43   }
44
45   public static void refresh(@NotNull final Project project) {
46     ApplicationManager.getApplication().invokeLater(new Runnable() {
47       @Override
48       public void run() {
49         ApplicationManager.getApplication().runWriteAction(new Runnable() {
50           @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
51           @Override
52           public void run() {
53             StudyEditor studyEditor = StudyUtils.getSelectedStudyEditor(project);
54             StudyState studyState = new StudyState(studyEditor);
55             if (studyEditor == null || !studyState.isValid()) {
56               LOG.info("RefreshTaskFileAction was invoked outside of Study Editor");
57               return;
58             }
59             refreshFile(studyState, project);
60           }
61         });
62       }
63     });
64   }
65
66   private static void refreshFile(@NotNull final StudyState studyState, @NotNull final Project project) {
67     final Editor editor = studyState.getEditor();
68     final TaskFile taskFile = studyState.getTaskFile();
69     if (!resetTaskFile(editor.getDocument(), project, taskFile, studyState.getVirtualFile().getName())) {
70       Messages.showInfoMessage("The initial text of task file is unavailable", "Failed to Refresh Task File");
71       return;
72     }
73     WolfTheProblemSolver.getInstance(project).clearProblems(studyState.getVirtualFile());
74     taskFile.setHighlightErrors(false);
75     StudyUtils.drawAllWindows(editor, taskFile);
76     EduAnswerPlaceholderPainter.createGuardedBlocks(editor, taskFile, true);
77     ApplicationManager.getApplication().invokeLater(new Runnable() {
78       @Override
79       public void run() {
80         IdeFocusManager.getInstance(project).requestFocus(editor.getContentComponent(), true);
81       }
82     });
83
84     StudyNavigator.navigateToFirstAnswerPlaceholder(editor, taskFile);
85     showBalloon(project, "You can start again now", MessageType.INFO);
86   }
87
88   private static boolean resetTaskFile(@NotNull final Document document,
89                                        @NotNull final Project project,
90                                        TaskFile taskFile,
91                                        String name) {
92     if (!resetDocument(document, taskFile, name)) {
93       return false;
94     }
95     resetAnswerPlaceholders(taskFile, project);
96     ProjectView.getInstance(project).refresh();
97     StudyUtils.updateToolWindows(project);
98     return true;
99   }
100
101   private static void showBalloon(@NotNull final Project project, String text, @NotNull final MessageType messageType) {
102     BalloonBuilder balloonBuilder =
103       JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(text, messageType, null);
104     final Balloon balloon = balloonBuilder.createBalloon();
105     StudyEditor selectedStudyEditor = StudyUtils.getSelectedStudyEditor(project);
106     assert selectedStudyEditor != null;
107     balloon.show(StudyUtils.computeLocation(selectedStudyEditor.getEditor()), Balloon.Position.above);
108     Disposer.register(project, balloon);
109   }
110
111   private static void resetAnswerPlaceholders(TaskFile selectedTaskFile, Project project) {
112     final StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
113     for (AnswerPlaceholder answerPlaceholder : selectedTaskFile.getAnswerPlaceholders()) {
114       answerPlaceholder.reset();
115       taskManager.setStatus(answerPlaceholder, StudyStatus.Unchecked);
116     }
117   }
118
119
120   private static boolean resetDocument(@NotNull final Document document,
121                                        @NotNull final TaskFile taskFile,
122                                        String fileName) {
123     final Document patternDocument = StudyUtils.getPatternDocument(taskFile, fileName);
124     if (patternDocument == null) {
125       return false;
126     }
127     StudyUtils.deleteGuardedBlocks(document);
128     taskFile.setTrackChanges(false);
129     clearDocument(document);
130     document.setText(patternDocument.getCharsSequence());
131     taskFile.setTrackChanges(true);
132     return true;
133   }
134
135   private static void clearDocument(@NotNull final Document document) {
136     final int lineCount = document.getLineCount();
137     if (lineCount != 0) {
138       CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() {
139         @Override
140         public void run() {
141           document.deleteString(0, document.getLineEndOffset(lineCount - 1));
142         }
143       });
144     }
145   }
146
147   public void actionPerformed(@NotNull AnActionEvent event) {
148     final Project project = event.getProject();
149     if (project != null) {
150       refresh(project);
151     }
152   }
153
154   @Override
155   public void update(AnActionEvent event) {
156     StudyUtils.updateAction(event);
157     final Project project = event.getProject();
158     if (project != null) {
159       StudyEditor studyEditor = StudyUtils.getSelectedStudyEditor(project);
160       StudyState studyState = new StudyState(studyEditor);
161       if (!studyState.isValid()) {
162         event.getPresentation().setEnabled(false);
163       }
164     }
165   }
166
167   @NotNull
168   @Override
169   public String getActionId() {
170     return ACTION_ID;
171   }
172
173   @Nullable
174   @Override
175   public String[] getShortcuts() {
176     return new String[]{SHORTCUT};
177   }
178 }