aab278175e0b62e83f3cde8e30fac1d023286266
[idea/community.git] / python / educational-core / course-creator / src / com / jetbrains / edu / coursecreator / actions / CCAddAnswerPlaceholder.java
1 package com.jetbrains.edu.coursecreator.actions;
2
3 import com.intellij.openapi.actionSystem.AnActionEvent;
4 import com.intellij.openapi.actionSystem.Presentation;
5 import com.intellij.openapi.editor.Document;
6 import com.intellij.openapi.editor.Editor;
7 import com.intellij.openapi.editor.SelectionModel;
8 import com.intellij.openapi.project.Project;
9 import com.intellij.openapi.ui.DialogWrapper;
10 import com.intellij.psi.PsiDocumentManager;
11 import com.intellij.psi.PsiFile;
12 import com.intellij.ui.JBColor;
13 import com.jetbrains.edu.coursecreator.ui.CCCreateAnswerPlaceholderDialog;
14 import com.jetbrains.edu.learning.StudyUtils;
15 import com.jetbrains.edu.learning.core.EduAnswerPlaceholderPainter;
16 import com.jetbrains.edu.learning.core.EduNames;
17 import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
18 import com.jetbrains.edu.learning.courseFormat.TaskFile;
19 import org.jetbrains.annotations.NotNull;
20
21 import java.util.List;
22
23 public class CCAddAnswerPlaceholder extends CCAnswerPlaceholderAction {
24
25   public CCAddAnswerPlaceholder() {
26     super("Add/Delete Answer Placeholder", "Add/Delete answer placeholder", null);
27   }
28
29
30   private static boolean arePlaceholdersIntersect(@NotNull final TaskFile taskFile, @NotNull final Document document, int start, int end) {
31     List<AnswerPlaceholder> answerPlaceholders = taskFile.getAnswerPlaceholders();
32     for (AnswerPlaceholder existingAnswerPlaceholder : answerPlaceholders) {
33       int twStart = existingAnswerPlaceholder.getRealStartOffset(document);
34       int twEnd = existingAnswerPlaceholder.getPossibleAnswerLength() + twStart;
35       if ((start >= twStart && start < twEnd) || (end > twStart && end <= twEnd) ||
36           (twStart >= start && twStart < end) || (twEnd > start && twEnd <= end)) {
37         return true;
38       }
39     }
40     return false;
41   }
42
43   private static void addPlaceholder(@NotNull CCState state) {
44     Editor editor = state.getEditor();
45     Project project = state.getProject();
46     PsiFile file = state.getFile();
47
48     final Document document = PsiDocumentManager.getInstance(project).getDocument(file);
49     if (document == null) {
50       return;
51     }
52
53     final SelectionModel model = editor.getSelectionModel();
54     final int start = model.getSelectionStart();
55     final int lineNumber = document.getLineNumber(start);
56     int realStart = start - document.getLineStartOffset(lineNumber);
57     final AnswerPlaceholder answerPlaceholder = new AnswerPlaceholder();
58     answerPlaceholder.setLine(lineNumber);
59     answerPlaceholder.setStart(realStart);
60     String selectedText = model.getSelectedText();
61     answerPlaceholder.setPossibleAnswer(selectedText);
62
63     CCCreateAnswerPlaceholderDialog dlg = new CCCreateAnswerPlaceholderDialog(project, answerPlaceholder);
64     dlg.show();
65     if (dlg.getExitCode() != DialogWrapper.OK_EXIT_CODE) {
66       return;
67     }
68
69     TaskFile taskFile = state.getTaskFile();
70     int index = taskFile.getAnswerPlaceholders().size() + 1;
71     answerPlaceholder.setIndex(index);
72     taskFile.addAnswerPlaceholder(answerPlaceholder);
73     taskFile.sortAnswerPlaceholders();
74     EduAnswerPlaceholderPainter.drawAnswerPlaceholder(editor, answerPlaceholder, false, JBColor.BLUE);
75     EduAnswerPlaceholderPainter.createGuardedBlocks(editor, answerPlaceholder, false);
76   }
77
78   @Override
79   protected void performAnswerPlaceholderAction(@NotNull CCState state) {
80     if (canAddPlaceholder(state)) {
81       addPlaceholder(state);
82       return;
83     }
84     if (canDeletePlaceholder(state)) {
85       deletePlaceholder(state);
86     }
87   }
88
89   private static void deletePlaceholder(@NotNull CCState state) {
90     Project project = state.getProject();
91     PsiFile psiFile = state.getFile();
92     final Document document = PsiDocumentManager.getInstance(project).getDocument(psiFile);
93     if (document == null) return;
94     TaskFile taskFile = state.getTaskFile();
95     AnswerPlaceholder answerPlaceholder = state.getAnswerPlaceholder();
96     final List<AnswerPlaceholder> answerPlaceholders = taskFile.getAnswerPlaceholders();
97     if (answerPlaceholders.contains(answerPlaceholder)) {
98       answerPlaceholders.remove(answerPlaceholder);
99       final Editor editor = state.getEditor();
100       editor.getMarkupModel().removeAllHighlighters();
101       StudyUtils.drawAllWindows(editor, taskFile);
102       EduAnswerPlaceholderPainter.createGuardedBlocks(editor, taskFile, false);
103     }
104   }
105
106   @Override
107   public void update(@NotNull AnActionEvent event) {
108     final Presentation presentation = event.getPresentation();
109     presentation.setEnabledAndVisible(false);
110
111     CCState state = getState(event);
112     if (state == null) {
113       return;
114     }
115
116     presentation.setVisible(true);
117     if (canAddPlaceholder(state) || canDeletePlaceholder(state)) {
118       presentation.setEnabled(true);
119       presentation.setText((state.getAnswerPlaceholder() == null ? "Add " : "Delete ") + EduNames.PLACEHOLDER);
120     }
121   }
122
123
124   private static boolean canAddPlaceholder(@NotNull CCState state) {
125     Editor editor = state.getEditor();
126     SelectionModel selectionModel = editor.getSelectionModel();
127     if (!selectionModel.hasSelection()) {
128       return false;
129     }
130     int start = selectionModel.getSelectionStart();
131     int end = selectionModel.getSelectionEnd();
132     return !arePlaceholdersIntersect(state.getTaskFile(), editor.getDocument(), start, end);
133   }
134
135   private static boolean canDeletePlaceholder(@NotNull CCState state) {
136     if (state.getEditor().getSelectionModel().hasSelection()) {
137       return false;
138     }
139     return state.getAnswerPlaceholder() != null;
140   }
141 }