1 package com.jetbrains.python.edu.actions;
3 import com.intellij.codeInsight.documentation.DocumentationComponent;
4 import com.intellij.codeInsight.documentation.DocumentationManager;
5 import com.intellij.openapi.actionSystem.AnActionEvent;
6 import com.intellij.openapi.editor.Editor;
7 import com.intellij.openapi.editor.LogicalPosition;
8 import com.intellij.openapi.project.DumbAwareAction;
9 import com.intellij.openapi.project.Project;
10 import com.intellij.openapi.ui.popup.JBPopup;
11 import com.intellij.openapi.ui.popup.JBPopupFactory;
12 import com.intellij.openapi.util.Disposer;
13 import com.intellij.psi.PsiElement;
14 import com.intellij.psi.PsiFile;
15 import com.intellij.psi.PsiManager;
16 import com.jetbrains.python.edu.StudyState;
17 import com.jetbrains.python.edu.StudyTaskManager;
18 import com.jetbrains.python.edu.StudyUtils;
19 import com.jetbrains.python.edu.course.Course;
20 import com.jetbrains.python.edu.course.TaskWindow;
21 import com.jetbrains.python.edu.editor.StudyEditor;
22 import icons.StudyIcons;
23 import org.jetbrains.annotations.NotNull;
24 import org.jetbrains.annotations.Nullable;
28 public class StudyShowHintAction extends DumbAwareAction {
29 public static final String ACTION_ID = "ShowHintAction";
30 public static final String SHORTCUT = "ctrl pressed 7";
31 public static final String OUTSIDE_TASK_WINDOW_MESSAGE = "Put caret to answer placeholder to get hint";
32 public static final String HINT_NOT_AVAILABLE = "There is no hint for this answer placeholder";
34 public StudyShowHintAction() {
35 super("Show hint", "Show hint", StudyIcons.ShowHint);
38 public void actionPerformed(@NotNull AnActionEvent e) {
39 final Project project = e.getProject();
40 if (project == null) {
46 public static void showHint(Project project) {
47 Course course = StudyTaskManager.getInstance(project).getCourse();
51 StudyState studyState = new StudyState(StudyEditor.getSelectedStudyEditor(project));
52 if (!studyState.isValid()) {
55 PsiFile file = PsiManager.getInstance(project).findFile(studyState.getVirtualFile());
56 final Editor editor = studyState.getEditor();
57 LogicalPosition pos = editor.getCaretModel().getLogicalPosition();
58 TaskWindow taskWindow = studyState.getTaskFile().getTaskWindow(editor.getDocument(), pos);
62 String hintText = OUTSIDE_TASK_WINDOW_MESSAGE;
63 if (taskWindow != null) {
64 hintText = getHintText(taskWindow, course);
66 int offset = editor.getDocument().getLineStartOffset(pos.line) + pos.column;
67 PsiElement element = file.findElementAt(offset);
68 DocumentationManager documentationManager = DocumentationManager.getInstance(project);
69 DocumentationComponent component = new DocumentationComponent(documentationManager);
70 component.setData(element != null ? element : file, element != null ? hintText : OUTSIDE_TASK_WINDOW_MESSAGE, true, null);
71 showHintPopUp(project, editor, component);
75 private static String getHintText(@NotNull final TaskWindow taskWindow, @NotNull final Course course) {
76 String hintFileName = taskWindow.getHint();
77 String hintText = HINT_NOT_AVAILABLE;
78 if (hintFileName != null && !hintFileName.isEmpty()) {
79 File resourceFile = new File(course.getResourcePath());
80 File resourceRoot = resourceFile.getParentFile();
81 if (resourceRoot != null && resourceRoot.exists()) {
82 File hintsDir = new File(resourceRoot, Course.HINTS_DIR);
83 if (hintsDir.exists()) {
84 hintText = StudyUtils.getFileText(hintsDir.getAbsolutePath(), hintFileName, true);
88 return hintText != null ? hintText : OUTSIDE_TASK_WINDOW_MESSAGE;
91 private static void showHintPopUp(Project project, Editor editor, DocumentationComponent component) {
93 JBPopupFactory.getInstance().createComponentPopupBuilder(component, component)
94 .setDimensionServiceKey(project, DocumentationManager.JAVADOC_LOCATION_AND_SIZE, false)
97 .setRequestFocus(true)
99 component.setHint(popup);
100 popup.showInBestPositionFor(editor);
101 Disposer.dispose(component);
105 public void update(@NotNull AnActionEvent e) {
106 StudyUtils.updateAction(e);