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