1 package com.jetbrains.edu.learning.core;
3 import com.intellij.ide.SaveAndSyncHandler;
4 import com.intellij.openapi.actionSystem.AnActionEvent;
5 import com.intellij.openapi.actionSystem.Presentation;
6 import com.intellij.openapi.application.ApplicationManager;
7 import com.intellij.openapi.application.Result;
8 import com.intellij.openapi.command.CommandProcessor;
9 import com.intellij.openapi.command.UndoConfirmationPolicy;
10 import com.intellij.openapi.command.WriteCommandAction;
11 import com.intellij.openapi.command.undo.UndoManager;
12 import com.intellij.openapi.command.undo.UndoableAction;
13 import com.intellij.openapi.diagnostic.Logger;
14 import com.intellij.openapi.editor.Document;
15 import com.intellij.openapi.fileEditor.FileDocumentManager;
16 import com.intellij.openapi.project.Project;
17 import com.intellij.openapi.util.Pair;
18 import com.intellij.openapi.util.TextRange;
19 import com.intellij.openapi.vfs.VfsUtilCore;
20 import com.intellij.openapi.vfs.VirtualFile;
21 import com.intellij.openapi.vfs.VirtualFileManager;
22 import com.intellij.psi.PsiDirectory;
23 import com.intellij.util.containers.ContainerUtil;
24 import com.jetbrains.edu.learning.StudyUtils;
25 import com.jetbrains.edu.learning.courseFormat.*;
26 import org.jetbrains.annotations.NonNls;
27 import org.jetbrains.annotations.NotNull;
28 import org.jetbrains.annotations.Nullable;
30 import javax.imageio.ImageIO;
31 import java.io.FileOutputStream;
32 import java.io.IOException;
33 import java.io.PrintWriter;
36 public class EduUtils {
40 private static final Logger LOG = Logger.getInstance(EduUtils.class.getName());
42 public static final Comparator<StudyItem> INDEX_COMPARATOR = (o1, o2) -> o1.getIndex() - o2.getIndex();
44 public static void enableAction(@NotNull final AnActionEvent event, boolean isEnable) {
45 final Presentation presentation = event.getPresentation();
46 presentation.setVisible(isEnable);
47 presentation.setEnabled(isEnable);
51 * Gets number index in directory names like "task1", "lesson2"
53 * @param fullName full name of directory
54 * @param logicalName part of name without index
55 * @return index of object
57 public static int getIndex(@NotNull final String fullName, @NotNull final String logicalName) {
58 if (!fullName.startsWith(logicalName)) {
62 return Integer.parseInt(fullName.substring(logicalName.length())) - 1;
64 catch (NumberFormatException e) {
69 public static boolean indexIsValid(int index, Collection collection) {
70 int size = collection.size();
71 return index >= 0 && index < size;
74 @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
76 public static VirtualFile flushWindows(@NotNull final TaskFile taskFile, @NotNull final VirtualFile file) {
77 final VirtualFile taskDir = file.getParent();
78 VirtualFile fileWindows = null;
79 final Document document = FileDocumentManager.getInstance().getDocument(file);
80 if (document == null) {
81 LOG.debug("Couldn't flush windows");
84 if (taskDir != null) {
85 final String name = file.getNameWithoutExtension() + EduNames.WINDOWS_POSTFIX;
86 deleteWindowsFile(taskDir, name);
87 PrintWriter printWriter = null;
89 fileWindows = taskDir.createChildData(taskFile, name);
90 printWriter = new PrintWriter(new FileOutputStream(fileWindows.getPath()));
91 for (AnswerPlaceholder answerPlaceholder : taskFile.getActivePlaceholders()) {
92 int length = answerPlaceholder.getRealLength();
93 int start = answerPlaceholder.getOffset();
94 final String windowDescription = document.getText(new TextRange(start, start + length));
95 printWriter.println("#educational_plugin_window = " + windowDescription);
97 ApplicationManager.getApplication().runWriteAction(() -> FileDocumentManager.getInstance().saveDocument(document));
99 catch (IOException e) {
103 if (printWriter != null) {
112 public static void synchronize() {
113 FileDocumentManager.getInstance().saveAllDocuments();
114 SaveAndSyncHandler.getInstance().refreshOpenFiles();
115 VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
119 public static VirtualFile copyFile(Object requestor, VirtualFile toDir, VirtualFile file) {
120 Document document = FileDocumentManager.getInstance().getDocument(file);
121 if (document != null) {
122 FileDocumentManager.getInstance().saveDocument(document);
124 String name = file.getName();
126 VirtualFile userFile = toDir.findChild(name);
127 if (userFile != null) {
128 userFile.delete(requestor);
130 return VfsUtilCore.copyFile(requestor, file, toDir);
132 catch (IOException e) {
133 LOG.info("Failed to create file " + name + " in folder " + toDir.getPath(), e);
139 public static Pair<VirtualFile, TaskFile> createStudentFile(Object requestor,
141 VirtualFile answerFile,
142 VirtualFile parentDir,
143 @Nullable Task task) {
145 VirtualFile studentFile = copyFile(requestor, parentDir, answerFile);
146 if (studentFile == null) {
149 Document studentDocument = FileDocumentManager.getInstance().getDocument(studentFile);
150 if (studentDocument == null) {
154 task = StudyUtils.getTaskForFile(project, answerFile);
160 TaskFile taskFile = task.getTaskFile(answerFile.getName());
161 if (taskFile == null) {
164 EduDocumentListener listener = new EduDocumentListener(taskFile, false);
165 studentDocument.addDocumentListener(listener);
167 for (AnswerPlaceholder placeholder : taskFile.getActivePlaceholders()) {
168 Set<Integer> indexes = placeholder.getSubtaskInfos().keySet();
169 int activeSubtaskIndex = task.getActiveSubtaskIndex();
170 if (Collections.min(indexes) < activeSubtaskIndex) {
171 Integer max = Collections.max(ContainerUtil.filter(indexes, i -> i < activeSubtaskIndex));
172 String possibleAnswer = placeholder.getSubtaskInfos().get(max).getPossibleAnswer();
173 replaceAnswerPlaceholder(project, studentDocument, placeholder, placeholder.getRealLength(), possibleAnswer);
176 replaceAnswerPlaceholder(project, studentDocument, placeholder, placeholder.getRealLength(), placeholder.getTaskText());
178 studentDocument.removeDocumentListener(listener);
179 return Pair.create(studentFile, taskFile);
182 public static void replaceAnswerPlaceholder(@NotNull final Project project,
183 @NotNull final Document document,
184 @NotNull final AnswerPlaceholder answerPlaceholder,
186 String replacementText) {
187 final int offset = answerPlaceholder.getOffset();
188 CommandProcessor.getInstance().executeCommand(project, () -> ApplicationManager.getApplication().runWriteAction(() -> {
189 document.replaceString(offset, offset + length, replacementText);
190 FileDocumentManager.getInstance().saveDocument(document);
191 }), "Replace Answer Placeholders", "Replace Answer Placeholders");
194 public static void deleteWindowDescriptions(@NotNull final Task task, @NotNull final VirtualFile taskDir) {
195 for (Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
196 String name = entry.getKey();
197 VirtualFile virtualFile = taskDir.findChild(name);
198 if (virtualFile == null) {
201 String windowsFileName = virtualFile.getNameWithoutExtension() + EduNames.WINDOWS_POSTFIX;
202 deleteWindowsFile(taskDir, windowsFileName);
206 private static void deleteWindowsFile(@NotNull final VirtualFile taskDir, @NotNull final String name) {
207 final VirtualFile fileWindows = taskDir.findChild(name);
208 if (fileWindows != null && fileWindows.exists()) {
209 ApplicationManager.getApplication().runWriteAction(() -> {
211 fileWindows.delete(taskDir);
213 catch (IOException e) {
214 LOG.warn("Tried to delete non existed _windows file");
221 public static Task getTask(@NotNull final PsiDirectory directory, @NotNull final Course course) {
222 PsiDirectory lessonDir = directory.getParent();
223 if (lessonDir == null) {
226 Lesson lesson = course.getLesson(lessonDir.getName());
227 if (lesson == null) {
230 return lesson.getTask(directory.getName());
233 public static boolean isImage(String fileName) {
234 final String[] readerFormatNames = ImageIO.getReaderFormatNames();
235 for (@NonNls String format : readerFormatNames) {
236 final String ext = format.toLowerCase();
237 if (fileName.endsWith(ext)) {
244 public static void runUndoableAction(Project project, String name, UndoableAction action) {
245 runUndoableAction(project, name, action, UndoConfirmationPolicy.DO_NOT_REQUEST_CONFIRMATION);
248 public static void runUndoableAction(Project project, String name, UndoableAction action, UndoConfirmationPolicy confirmationPolicy) {
249 new WriteCommandAction(project, name) {
250 protected void run(@NotNull final Result result) throws Throwable {
252 UndoManager.getInstance(project).undoableActionPerformed(action);
256 protected UndoConfirmationPolicy getUndoConfirmationPolicy() {
257 return confirmationPolicy;