extract util method
[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.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.jetbrains.edu.learning.StudyUtils;
24 import com.jetbrains.edu.learning.courseFormat.*;
25 import org.jetbrains.annotations.NonNls;
26 import org.jetbrains.annotations.NotNull;
27 import org.jetbrains.annotations.Nullable;
28
29 import javax.imageio.ImageIO;
30 import java.io.FileOutputStream;
31 import java.io.IOException;
32 import java.io.PrintWriter;
33 import java.util.*;
34
35 public class EduUtils {
36   private EduUtils() {
37   }
38
39   private static final Logger LOG = Logger.getInstance(EduUtils.class.getName());
40
41   public static final Comparator<StudyItem> INDEX_COMPARATOR = (o1, o2) -> o1.getIndex() - o2.getIndex();
42
43   public static void enableAction(@NotNull final AnActionEvent event, boolean isEnable) {
44     final Presentation presentation = event.getPresentation();
45     presentation.setVisible(isEnable);
46     presentation.setEnabled(isEnable);
47   }
48
49   /**
50    * Gets number index in directory names like "task1", "lesson2"
51    *
52    * @param fullName    full name of directory
53    * @param logicalName part of name without index
54    * @return index of object
55    */
56   public static int getIndex(@NotNull final String fullName, @NotNull final String logicalName) {
57     if (!fullName.startsWith(logicalName)) {
58       return -1;
59     }
60     try {
61       return Integer.parseInt(fullName.substring(logicalName.length())) - 1;
62     }
63     catch (NumberFormatException e) {
64       return -1;
65     }
66   }
67
68   public static boolean indexIsValid(int index, Collection collection) {
69     int size = collection.size();
70     return index >= 0 && index < size;
71   }
72
73   @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
74   @Nullable
75   public static VirtualFile flushWindows(@NotNull final TaskFile taskFile, @NotNull final VirtualFile file) {
76     final VirtualFile taskDir = file.getParent();
77     VirtualFile fileWindows = null;
78     final Document document = FileDocumentManager.getInstance().getDocument(file);
79     if (document == null) {
80       LOG.debug("Couldn't flush windows");
81       return null;
82     }
83     if (taskDir != null) {
84       final String name = file.getNameWithoutExtension() + EduNames.WINDOWS_POSTFIX;
85       deleteWindowsFile(taskDir, name);
86       PrintWriter printWriter = null;
87       try {
88         fileWindows = taskDir.createChildData(taskFile, name);
89         printWriter = new PrintWriter(new FileOutputStream(fileWindows.getPath()));
90         for (AnswerPlaceholder answerPlaceholder : taskFile.getAnswerPlaceholders()) {
91           int length = answerPlaceholder.getRealLength();
92           int start = answerPlaceholder.getOffset();
93           final String windowDescription = document.getText(new TextRange(start, start + length));
94           printWriter.println("#educational_plugin_window = " + windowDescription);
95         }
96         ApplicationManager.getApplication().runWriteAction(() -> FileDocumentManager.getInstance().saveDocument(document));
97       }
98       catch (IOException e) {
99         LOG.error(e);
100       }
101       finally {
102         if (printWriter != null) {
103           printWriter.close();
104         }
105         synchronize();
106       }
107     }
108     return fileWindows;
109   }
110
111   public static void synchronize() {
112     FileDocumentManager.getInstance().saveAllDocuments();
113     SaveAndSyncHandler.getInstance().refreshOpenFiles();
114     VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
115   }
116
117
118   public static VirtualFile copyFile(Object requestor, VirtualFile toDir, VirtualFile file) {
119     Document document = FileDocumentManager.getInstance().getDocument(file);
120     if (document != null) {
121       FileDocumentManager.getInstance().saveDocument(document);
122     }
123     String name = file.getName();
124     try {
125       VirtualFile userFile = toDir.findChild(name);
126       if (userFile != null) {
127         userFile.delete(requestor);
128       }
129       return VfsUtilCore.copyFile(requestor, file, toDir);
130     }
131     catch (IOException e) {
132       LOG.info("Failed to create file " + name + "  in folder " + toDir.getPath(), e);
133     }
134     return null;
135   }
136
137   @Nullable
138   public static Pair<VirtualFile, TaskFile> createStudentFile(Object requestor,
139                                                               Project project,
140                                                               VirtualFile answerFile,
141                                                               VirtualFile parentDir,
142                                                               @Nullable Task task) {
143
144     VirtualFile studentFile = copyFile(requestor, parentDir, answerFile);
145     if (studentFile == null) {
146       return null;
147     }
148     Document studentDocument = FileDocumentManager.getInstance().getDocument(studentFile);
149     if (studentDocument == null) {
150       return null;
151     }
152     if (task == null) {
153       task = StudyUtils.getTaskForFile(project, answerFile);
154       if (task == null) {
155         return null;
156       }
157       task = task.copy();
158     }
159     TaskFile taskFile = task.getTaskFile(answerFile.getName());
160     if (taskFile == null) {
161       return null;
162     }
163     EduDocumentListener listener = new EduDocumentListener(taskFile, false);
164     studentDocument.addDocumentListener(listener);
165
166     for (AnswerPlaceholder placeholder : taskFile.getAnswerPlaceholders()) {
167       replaceAnswerPlaceholder(project, studentDocument, placeholder);
168     }
169     studentDocument.removeDocumentListener(listener);
170     return Pair.create(studentFile, taskFile);
171   }
172
173   private static void replaceAnswerPlaceholder(@NotNull final Project project,
174                                                @NotNull final Document document,
175                                                @NotNull final AnswerPlaceholder answerPlaceholder) {
176     final String taskText = answerPlaceholder.getTaskText();
177     final int offset = answerPlaceholder.getOffset();
178     CommandProcessor.getInstance().executeCommand(project, () -> ApplicationManager.getApplication().runWriteAction(() -> {
179       document.replaceString(offset, offset + answerPlaceholder.getRealLength(), taskText);
180       FileDocumentManager.getInstance().saveDocument(document);
181     }), "Replace Answer Placeholders", "Replace Answer Placeholders");
182   }
183
184   public static void deleteWindowDescriptions(@NotNull final Task task, @NotNull final VirtualFile taskDir) {
185     for (Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
186       String name = entry.getKey();
187       VirtualFile virtualFile = taskDir.findChild(name);
188       if (virtualFile == null) {
189         continue;
190       }
191       String windowsFileName = virtualFile.getNameWithoutExtension() + EduNames.WINDOWS_POSTFIX;
192       deleteWindowsFile(taskDir, windowsFileName);
193     }
194   }
195
196   private static void deleteWindowsFile(@NotNull final VirtualFile taskDir, @NotNull final String name) {
197     final VirtualFile fileWindows = taskDir.findChild(name);
198     if (fileWindows != null && fileWindows.exists()) {
199       ApplicationManager.getApplication().runWriteAction(() -> {
200         try {
201           fileWindows.delete(taskDir);
202         }
203         catch (IOException e) {
204           LOG.warn("Tried to delete non existed _windows file");
205         }
206       });
207     }
208   }
209
210   @Nullable
211   public static Task getTask(@NotNull final PsiDirectory directory, @NotNull final Course course) {
212     PsiDirectory lessonDir = directory.getParent();
213     if (lessonDir == null) {
214       return null;
215     }
216     Lesson lesson = course.getLesson(lessonDir.getName());
217     if (lesson == null) {
218       return null;
219     }
220     return lesson.getTask(directory.getName());
221   }
222
223   public static boolean isImage(String fileName) {
224     final String[] readerFormatNames = ImageIO.getReaderFormatNames();
225     for (@NonNls String format : readerFormatNames) {
226       final String ext = format.toLowerCase();
227       if (fileName.endsWith(ext)) {
228         return true;
229       }
230     }
231     return false;
232   }
233
234   public static void runUndoableAction(Project project, String name, UndoableAction action) {
235     runUndoableAction(project, name, action, UndoConfirmationPolicy.DO_NOT_REQUEST_CONFIRMATION);
236   }
237
238   public static void runUndoableAction(Project project, String name, UndoableAction action, UndoConfirmationPolicy confirmationPolicy) {
239     new WriteCommandAction(project, name) {
240       protected void run(@NotNull final Result result) throws Throwable {
241         action.redo();
242         UndoManager.getInstance(project).undoableActionPerformed(action);
243       }
244
245       @Override
246       protected UndoConfirmationPolicy getUndoConfirmationPolicy() {
247         return confirmationPolicy;
248       }
249     }.execute();
250   }
251 }