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.command.CommandProcessor;
8 import com.intellij.openapi.diagnostic.Logger;
9 import com.intellij.openapi.editor.Document;
10 import com.intellij.openapi.fileEditor.FileDocumentManager;
11 import com.intellij.openapi.project.Project;
12 import com.intellij.openapi.util.Pair;
13 import com.intellij.openapi.util.TextRange;
14 import com.intellij.openapi.vfs.VfsUtilCore;
15 import com.intellij.openapi.vfs.VirtualFile;
16 import com.intellij.openapi.vfs.VirtualFileManager;
17 import com.intellij.psi.PsiDirectory;
18 import com.jetbrains.edu.learning.StudyUtils;
19 import com.jetbrains.edu.learning.courseFormat.*;
20 import org.jetbrains.annotations.NonNls;
21 import org.jetbrains.annotations.NotNull;
22 import org.jetbrains.annotations.Nullable;
24 import javax.imageio.ImageIO;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.io.PrintWriter;
30 public class EduUtils {
34 private static final Logger LOG = Logger.getInstance(EduUtils.class.getName());
36 public static final Comparator<StudyItem> INDEX_COMPARATOR = (o1, o2) -> o1.getIndex() - o2.getIndex();
38 public static void enableAction(@NotNull final AnActionEvent event, boolean isEnable) {
39 final Presentation presentation = event.getPresentation();
40 presentation.setVisible(isEnable);
41 presentation.setEnabled(isEnable);
45 * Gets number index in directory names like "task1", "lesson2"
47 * @param fullName full name of directory
48 * @param logicalName part of name without index
49 * @return index of object
51 public static int getIndex(@NotNull final String fullName, @NotNull final String logicalName) {
52 if (!fullName.startsWith(logicalName)) {
56 return Integer.parseInt(fullName.substring(logicalName.length())) - 1;
58 catch (NumberFormatException e) {
63 public static boolean indexIsValid(int index, Collection collection) {
64 int size = collection.size();
65 return index >= 0 && index < size;
68 @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
70 public static VirtualFile flushWindows(@NotNull final TaskFile taskFile, @NotNull final VirtualFile file) {
71 final VirtualFile taskDir = file.getParent();
72 VirtualFile fileWindows = null;
73 final Document document = FileDocumentManager.getInstance().getDocument(file);
74 if (document == null) {
75 LOG.debug("Couldn't flush windows");
78 if (taskDir != null) {
79 final String name = file.getNameWithoutExtension() + EduNames.WINDOWS_POSTFIX;
80 deleteWindowsFile(taskDir, name);
81 PrintWriter printWriter = null;
83 fileWindows = taskDir.createChildData(taskFile, name);
84 printWriter = new PrintWriter(new FileOutputStream(fileWindows.getPath()));
85 for (AnswerPlaceholder answerPlaceholder : taskFile.getAnswerPlaceholders()) {
86 int length = answerPlaceholder.getRealLength();
87 int start = answerPlaceholder.getOffset();
88 final String windowDescription = document.getText(new TextRange(start, start + length));
89 printWriter.println("#educational_plugin_window = " + windowDescription);
91 ApplicationManager.getApplication().runWriteAction(() -> FileDocumentManager.getInstance().saveDocument(document));
93 catch (IOException e) {
97 if (printWriter != null) {
106 public static void synchronize() {
107 FileDocumentManager.getInstance().saveAllDocuments();
108 SaveAndSyncHandler.getInstance().refreshOpenFiles();
109 VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
113 public static VirtualFile copyFile(Object requestor, VirtualFile toDir, VirtualFile file) {
114 Document document = FileDocumentManager.getInstance().getDocument(file);
115 if (document != null) {
116 FileDocumentManager.getInstance().saveDocument(document);
118 String name = file.getName();
120 VirtualFile userFile = toDir.findChild(name);
121 if (userFile != null) {
122 userFile.delete(requestor);
124 return VfsUtilCore.copyFile(requestor, file, toDir);
126 catch (IOException e) {
127 LOG.info("Failed to create file " + name + " in folder " + toDir.getPath(), e);
133 public static Pair<VirtualFile, TaskFile> createStudentFile(Object requestor,
135 VirtualFile answerFile,
136 VirtualFile parentDir,
137 @Nullable Task task) {
139 VirtualFile studentFile = copyFile(requestor, parentDir, answerFile);
140 if (studentFile == null) {
143 Document studentDocument = FileDocumentManager.getInstance().getDocument(studentFile);
144 if (studentDocument == null) {
148 task = StudyUtils.getTaskForFile(project, answerFile);
154 TaskFile taskFile = task.getTaskFile(answerFile.getName());
155 if (taskFile == null) {
158 EduDocumentListener listener = new EduDocumentListener(taskFile, false);
159 studentDocument.addDocumentListener(listener);
161 for (AnswerPlaceholder placeholder : taskFile.getAnswerPlaceholders()) {
162 replaceAnswerPlaceholder(project, studentDocument, placeholder);
164 studentDocument.removeDocumentListener(listener);
165 return Pair.create(studentFile, taskFile);
168 private static void replaceAnswerPlaceholder(@NotNull final Project project,
169 @NotNull final Document document,
170 @NotNull final AnswerPlaceholder answerPlaceholder) {
171 final String taskText = answerPlaceholder.getTaskText();
172 final int offset = answerPlaceholder.getOffset();
173 CommandProcessor.getInstance().executeCommand(project, () -> ApplicationManager.getApplication().runWriteAction(() -> {
174 document.replaceString(offset, offset + answerPlaceholder.getRealLength(), taskText);
175 FileDocumentManager.getInstance().saveDocument(document);
176 }), "Replace Answer Placeholders", "Replace Answer Placeholders");
179 public static void deleteWindowDescriptions(@NotNull final Task task, @NotNull final VirtualFile taskDir) {
180 for (Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
181 String name = entry.getKey();
182 VirtualFile virtualFile = taskDir.findChild(name);
183 if (virtualFile == null) {
186 String windowsFileName = virtualFile.getNameWithoutExtension() + EduNames.WINDOWS_POSTFIX;
187 deleteWindowsFile(taskDir, windowsFileName);
191 private static void deleteWindowsFile(@NotNull final VirtualFile taskDir, @NotNull final String name) {
192 final VirtualFile fileWindows = taskDir.findChild(name);
193 if (fileWindows != null && fileWindows.exists()) {
194 ApplicationManager.getApplication().runWriteAction(() -> {
196 fileWindows.delete(taskDir);
198 catch (IOException e) {
199 LOG.warn("Tried to delete non existed _windows file");
206 public static Task getTask(@NotNull final PsiDirectory directory, @NotNull final Course course) {
207 PsiDirectory lessonDir = directory.getParent();
208 if (lessonDir == null) {
211 Lesson lesson = course.getLesson(lessonDir.getName());
212 if (lesson == null) {
215 return lesson.getTask(directory.getName());
218 public static boolean isImage(String fileName) {
219 final String[] readerFormatNames = ImageIO.getReaderFormatNames();
220 for (@NonNls String format : readerFormatNames) {
221 final String ext = format.toLowerCase();
222 if (fileName.endsWith(ext)) {