9966a7b80ebd3dd005255664a2d16555d074e8e1
[idea/community.git] / python / educational-core / student / src / com / jetbrains / edu / learning / core / EduUtils.java
1 package com.jetbrains.edu.learning.core;
2
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;
23
24 import javax.imageio.ImageIO;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.io.PrintWriter;
28 import java.util.*;
29
30 public class EduUtils {
31   private EduUtils() {
32   }
33
34   private static final Logger LOG = Logger.getInstance(EduUtils.class.getName());
35
36   public static final Comparator<StudyItem> INDEX_COMPARATOR = (o1, o2) -> o1.getIndex() - o2.getIndex();
37
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);
42   }
43
44   /**
45    * Gets number index in directory names like "task1", "lesson2"
46    *
47    * @param fullName    full name of directory
48    * @param logicalName part of name without index
49    * @return index of object
50    */
51   public static int getIndex(@NotNull final String fullName, @NotNull final String logicalName) {
52     if (!fullName.startsWith(logicalName)) {
53       return -1;
54     }
55     try {
56       return Integer.parseInt(fullName.substring(logicalName.length())) - 1;
57     }
58     catch (NumberFormatException e) {
59       return -1;
60     }
61   }
62
63   public static boolean indexIsValid(int index, Collection collection) {
64     int size = collection.size();
65     return index >= 0 && index < size;
66   }
67
68   @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
69   @Nullable
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");
76       return null;
77     }
78     if (taskDir != null) {
79       final String name = file.getNameWithoutExtension() + EduNames.WINDOWS_POSTFIX;
80       deleteWindowsFile(taskDir, name);
81       PrintWriter printWriter = null;
82       try {
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);
90         }
91         ApplicationManager.getApplication().runWriteAction(() -> FileDocumentManager.getInstance().saveDocument(document));
92       }
93       catch (IOException e) {
94         LOG.error(e);
95       }
96       finally {
97         if (printWriter != null) {
98           printWriter.close();
99         }
100         synchronize();
101       }
102     }
103     return fileWindows;
104   }
105
106   public static void synchronize() {
107     FileDocumentManager.getInstance().saveAllDocuments();
108     SaveAndSyncHandler.getInstance().refreshOpenFiles();
109     VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
110   }
111
112
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);
117     }
118     String name = file.getName();
119     try {
120       VirtualFile userFile = toDir.findChild(name);
121       if (userFile != null) {
122         userFile.delete(requestor);
123       }
124       return VfsUtilCore.copyFile(requestor, file, toDir);
125     }
126     catch (IOException e) {
127       LOG.info("Failed to create file " + name + "  in folder " + toDir.getPath(), e);
128     }
129     return null;
130   }
131
132   @Nullable
133   public static Pair<VirtualFile, TaskFile> createStudentFile(Object requestor,
134                                                               Project project,
135                                                               VirtualFile answerFile,
136                                                               VirtualFile parentDir,
137                                                               @Nullable Task task) {
138
139     VirtualFile studentFile = copyFile(requestor, parentDir, answerFile);
140     if (studentFile == null) {
141       return null;
142     }
143     Document studentDocument = FileDocumentManager.getInstance().getDocument(studentFile);
144     if (studentDocument == null) {
145       return null;
146     }
147     if (task == null) {
148       task = StudyUtils.getTaskForFile(project, answerFile);
149       if (task == null) {
150         return null;
151       }
152       task = task.copy();
153     }
154     TaskFile taskFile = task.getTaskFile(answerFile.getName());
155     if (taskFile == null) {
156       return null;
157     }
158     EduDocumentListener listener = new EduDocumentListener(taskFile, false);
159     studentDocument.addDocumentListener(listener);
160
161     for (AnswerPlaceholder placeholder : taskFile.getAnswerPlaceholders()) {
162       replaceAnswerPlaceholder(project, studentDocument, placeholder);
163     }
164     studentDocument.removeDocumentListener(listener);
165     return Pair.create(studentFile, taskFile);
166   }
167
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");
177   }
178
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) {
184         continue;
185       }
186       String windowsFileName = virtualFile.getNameWithoutExtension() + EduNames.WINDOWS_POSTFIX;
187       deleteWindowsFile(taskDir, windowsFileName);
188     }
189   }
190
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(() -> {
195         try {
196           fileWindows.delete(taskDir);
197         }
198         catch (IOException e) {
199           LOG.warn("Tried to delete non existed _windows file");
200         }
201       });
202     }
203   }
204
205   @Nullable
206   public static Task getTask(@NotNull final PsiDirectory directory, @NotNull final Course course) {
207     PsiDirectory lessonDir = directory.getParent();
208     if (lessonDir == null) {
209       return null;
210     }
211     Lesson lesson = course.getLesson(lessonDir.getName());
212     if (lesson == null) {
213       return null;
214     }
215     return lesson.getTask(directory.getName());
216   }
217
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)) {
223         return true;
224       }
225     }
226     return false;
227   }
228 }