save indent for task text
[idea/community.git] / python / educational-core / course-creator / src / com / jetbrains / edu / coursecreator / actions / placeholder / CCChangePlaceholderVisibility.java
1 package com.jetbrains.edu.coursecreator.actions.placeholder;
2
3 import com.intellij.openapi.actionSystem.AnActionEvent;
4 import com.intellij.openapi.actionSystem.Presentation;
5 import com.intellij.openapi.command.undo.BasicUndoableAction;
6 import com.intellij.openapi.command.undo.UnexpectedUndoException;
7 import com.intellij.openapi.editor.Document;
8 import com.intellij.openapi.util.TextRange;
9 import com.intellij.openapi.util.text.StringUtil;
10 import com.intellij.util.DocumentUtil;
11 import com.jetbrains.edu.learning.StudyUtils;
12 import com.jetbrains.edu.learning.core.EduUtils;
13 import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
14 import com.jetbrains.edu.learning.courseFormat.Task;
15 import org.jetbrains.annotations.NotNull;
16 import org.jetbrains.annotations.Nullable;
17
18 import java.util.Collections;
19
20 public abstract class CCChangePlaceholderVisibility extends CCAnswerPlaceholderAction {
21
22   protected CCChangePlaceholderVisibility(@Nullable String text, @Nullable String description) {
23     super(text, description);
24   }
25
26   @Override
27   protected void performAnswerPlaceholderAction(@NotNull CCState state) {
28     AnswerPlaceholder placeholder = state.getAnswerPlaceholder();
29     if (placeholder == null) {
30       return;
31     }
32     EduUtils.runUndoableAction(state.getProject(), getName(), new BasicUndoableAction(state.getEditor().getDocument()) {
33       @Override
34       public void undo() throws UnexpectedUndoException {
35         setVisible(placeholder, isVisible(), state);
36       }
37
38       @Override
39       public void redo() throws UnexpectedUndoException {
40         setVisible(placeholder, !isVisible(), state);
41       }
42     });
43   }
44
45   private void setVisible(AnswerPlaceholder placeholder, boolean visible, CCState state) {
46     placeholder.getActiveSubtaskInfo().setNeedInsertText(visible);
47     saveIndent(placeholder, state, !visible);
48     int length = isVisible() ? placeholder.getTaskText().length() : 0;
49     placeholder.setLength(length);
50     StudyUtils.drawAllAnswerPlaceholders(state.getEditor(), state.getTaskFile());
51   }
52
53   private static void saveIndent(AnswerPlaceholder placeholder, CCState state, boolean visible) {
54     Document document = state.getEditor().getDocument();
55     int offset = placeholder.getOffset();
56     int lineNumber = document.getLineNumber(offset);
57     int nonSpaceCharOffset = DocumentUtil.getFirstNonSpaceCharOffset(document, lineNumber);
58     int newOffset = offset;
59     int endOffset = offset + placeholder.getRealLength();
60     if (!visible && nonSpaceCharOffset == offset) {
61       newOffset = document.getLineStartOffset(lineNumber);
62     }
63     if (visible) {
64       newOffset = DocumentUtil.getFirstNonSpaceCharOffset(document, offset, endOffset);
65     }
66     placeholder.setOffset(newOffset);
67     int delta = offset - newOffset;
68     placeholder.setPossibleAnswer(document.getText(TextRange.create(newOffset, newOffset + delta + placeholder.getRealLength())));
69     String oldTaskText = placeholder.getTaskText();
70     if (delta >= 0) {
71       placeholder.setTaskText(StringUtil.repeat(" ", delta) + oldTaskText);
72     }
73     else {
74       String newTaskText = oldTaskText.substring(Math.abs(delta));
75       placeholder.setTaskText(newTaskText);
76     }
77   }
78
79   protected abstract String getName();
80
81   protected abstract boolean isVisible();
82
83   @Override
84   public void update(AnActionEvent e) {
85     Presentation presentation = e.getPresentation();
86     presentation.setEnabledAndVisible(false);
87     CCState state = getState(e);
88     if (state == null) {
89       return;
90     }
91     AnswerPlaceholder placeholder = state.getAnswerPlaceholder();
92     if (placeholder == null) {
93       return;
94     }
95     Task task = state.getTaskFile().getTask();
96     if (!task.hasSubtasks()) {
97       return;
98     }
99     Integer minSubtaskIndex = Collections.min(placeholder.getSubtaskInfos().keySet());
100     if (placeholder.isActive() && minSubtaskIndex != 0 && minSubtaskIndex == task.getActiveSubtaskIndex() && isAvailable(placeholder)) {
101       presentation.setEnabledAndVisible(true);
102     }
103   }
104
105   protected abstract boolean isAvailable(AnswerPlaceholder placeholder);
106 }