do not add task dirs to source roots
[idea/community.git] / python / educational / src / com / jetbrains / edu / EduUtils.java
1 package com.jetbrains.edu;
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.TextRange;
13 import com.intellij.openapi.vfs.VirtualFile;
14 import com.intellij.openapi.vfs.VirtualFileManager;
15 import com.jetbrains.edu.courseFormat.AnswerPlaceholder;
16 import com.jetbrains.edu.courseFormat.StudyOrderable;
17 import com.jetbrains.edu.courseFormat.Task;
18 import com.jetbrains.edu.courseFormat.TaskFile;
19 import org.jetbrains.annotations.NotNull;
20 import org.jetbrains.annotations.Nullable;
21
22 import java.io.FileOutputStream;
23 import java.io.IOException;
24 import java.io.PrintWriter;
25 import java.util.Collection;
26 import java.util.Comparator;
27 import java.util.Map;
28
29 public class EduUtils {
30   private EduUtils() {
31   }
32   private static final Logger LOG = Logger.getInstance(EduUtils.class.getName());
33
34   public static Comparator<StudyOrderable> INDEX_COMPARATOR = new Comparator<StudyOrderable>() {
35     @Override
36     public int compare(StudyOrderable o1, StudyOrderable o2) {
37       return o1.getIndex() - o2.getIndex();
38     }
39   };
40
41   public static void enableAction(@NotNull final AnActionEvent event, boolean isEnable) {
42     final Presentation presentation = event.getPresentation();
43     presentation.setVisible(isEnable);
44     presentation.setEnabled(isEnable);
45   }
46
47   /**
48    * Gets number index in directory names like "task1", "lesson2"
49    *
50    * @param fullName    full name of directory
51    * @param logicalName part of name without index
52    * @return index of object
53    */
54   public static int getIndex(@NotNull final String fullName, @NotNull final String logicalName) {
55     if (!fullName.startsWith(logicalName)) {
56       return -1;
57     }
58     try {
59       return Integer.parseInt(fullName.substring(logicalName.length())) - 1;
60     } catch(NumberFormatException e) {
61       return -1;
62     }
63   }
64
65   public static boolean indexIsValid(int index, Collection collection) {
66     int size = collection.size();
67     return index >= 0 && index < size;
68   }
69
70   @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
71   @Nullable
72   public static VirtualFile flushWindows(@NotNull final TaskFile taskFile, @NotNull final VirtualFile file,
73                                          boolean useLength) {
74     final VirtualFile taskDir = file.getParent();
75     VirtualFile fileWindows = null;
76     final Document document = FileDocumentManager.getInstance().getDocument(file);
77     if (document == null) {
78       LOG.debug("Couldn't flush windows");
79       return null;
80     }
81     if (taskDir != null) {
82       final String name = file.getNameWithoutExtension() + EduNames.WINDOWS_POSTFIX;
83       deleteWindowsFile(taskDir, name);
84       PrintWriter printWriter = null;
85       try {
86         fileWindows = taskDir.createChildData(taskFile, name);
87         printWriter = new PrintWriter(new FileOutputStream(fileWindows.getPath()));
88         for (AnswerPlaceholder answerPlaceholder : taskFile.getAnswerPlaceholders()) {
89           if (!answerPlaceholder.isValid(document)) {
90             printWriter.println("#educational_plugin_window = ");
91             continue;
92           }
93           int start = answerPlaceholder.getRealStartOffset(document);
94           int length = useLength ? answerPlaceholder.getLength() : answerPlaceholder.getPossibleAnswerLength();
95           final String windowDescription = document.getText(new TextRange(start, start + length));
96           printWriter.println("#educational_plugin_window = " + windowDescription);
97         }
98         ApplicationManager.getApplication().runWriteAction(new Runnable() {
99           @Override
100           public void run() {
101             FileDocumentManager.getInstance().saveDocument(document);
102           }
103         });
104       }
105       catch (IOException e) {
106         LOG.error(e);
107       }
108       finally {
109         if (printWriter != null) {
110           printWriter.close();
111         }
112         synchronize();
113       }
114     }
115     return fileWindows;
116   }
117
118   public static void synchronize() {
119     FileDocumentManager.getInstance().saveAllDocuments();
120     SaveAndSyncHandler.getInstance().refreshOpenFiles();
121     VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
122   }
123
124   public static void createStudentFileFromAnswer(@NotNull final Project project,
125                                                  @NotNull final VirtualFile userFileDir,
126                                                  @NotNull final VirtualFile answerFileDir,
127                                                  @NotNull final Map.Entry<String, TaskFile> taskFileEntry) {
128     final String name = taskFileEntry.getKey();
129     final TaskFile taskFile = taskFileEntry.getValue();
130     VirtualFile file = userFileDir.findChild(name);
131     if (file != null) {
132       try {
133         file.delete(project);
134       }
135       catch (IOException e) {
136         LOG.error(e);
137       }
138     }
139     try {
140       userFileDir.createChildData(project, name);
141     }
142     catch (IOException e) {
143       LOG.error(e);
144     }
145
146     file = userFileDir.findChild(name);
147     assert file != null;
148     String answerFileName = file.getNameWithoutExtension() + ".answer." + file.getExtension();
149     VirtualFile answerFile = answerFileDir.findChild(answerFileName);
150     if (answerFile == null) {
151       return;
152     }
153     final Document answerDocument = FileDocumentManager.getInstance().getDocument(answerFile);
154     if (answerDocument == null) {
155       return;
156     }
157     final Document document = FileDocumentManager.getInstance().getDocument(file);
158     if (document == null) return;
159
160     CommandProcessor.getInstance().executeCommand(project, new Runnable() {
161       @Override
162       public void run() {
163         ApplicationManager.getApplication().runWriteAction(new Runnable() {
164           @Override
165           public void run() {
166             document.replaceString(0, document.getTextLength(), answerDocument.getCharsSequence());
167           }
168         });
169       }
170     }, "Create Student File", "Create Student File");
171     EduDocumentListener listener = new EduDocumentListener(taskFile, false);
172     document.addDocumentListener(listener);
173     taskFile.sortAnswerPlaceholders();
174     for (int i = taskFile.getAnswerPlaceholders().size() - 1; i >= 0; i--) {
175       final AnswerPlaceholder answerPlaceholder = taskFile.getAnswerPlaceholders().get(i);
176       if (answerPlaceholder.getRealStartOffset(document) > document.getTextLength() || answerPlaceholder.getRealStartOffset(document) + answerPlaceholder.getPossibleAnswerLength() > document.getTextLength()) {
177         LOG.error("Wrong startOffset: " + answerPlaceholder.getRealStartOffset(document) + "; document: " + file.getPath());
178         return;
179       }
180       replaceAnswerPlaceholder(project, document, answerPlaceholder);
181     }
182     CommandProcessor.getInstance().executeCommand(project, new Runnable() {
183       @Override
184       public void run() {
185         ApplicationManager.getApplication().runWriteAction(new Runnable() {
186           @Override
187           public void run() {
188             FileDocumentManager.getInstance().saveDocument(document);
189           }
190         });
191       }
192     }, "Create Student File", "Create Student File");
193     document.removeDocumentListener(listener);
194   }
195
196   private static void replaceAnswerPlaceholder(@NotNull final Project project,
197                                                @NotNull final Document document,
198                                                @NotNull final AnswerPlaceholder answerPlaceholder) {
199     final String taskText = answerPlaceholder.getTaskText();
200     final int offset = answerPlaceholder.getRealStartOffset(document);
201     CommandProcessor.getInstance().executeCommand(project, new Runnable() {
202       @Override
203       public void run() {
204         ApplicationManager.getApplication().runWriteAction(new Runnable() {
205           @Override
206           public void run() {
207             document.replaceString(offset, offset + answerPlaceholder.getPossibleAnswerLength(), taskText);
208             FileDocumentManager.getInstance().saveDocument(document);
209           }
210         });
211       }
212     }, "Replace Answer Placeholders", "Replace Answer Placeholders");
213   }
214
215   public static void deleteWindowDescriptions(@NotNull final Task task, @NotNull final VirtualFile taskDir) {
216     for (Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
217       String name = entry.getKey();
218       VirtualFile virtualFile = taskDir.findChild(name);
219       if (virtualFile == null) {
220         continue;
221       }
222       String windowsFileName = virtualFile.getNameWithoutExtension() + EduNames.WINDOWS_POSTFIX;
223       deleteWindowsFile(taskDir, windowsFileName);
224     }
225   }
226
227   private static void deleteWindowsFile(@NotNull final VirtualFile taskDir, @NotNull final String name) {
228     final VirtualFile fileWindows = taskDir.findChild(name);
229     if (fileWindows != null && fileWindows.exists()) {
230       ApplicationManager.getApplication().runWriteAction(new Runnable() {
231         @Override
232         public void run() {
233           try {
234             fileWindows.delete(taskDir);
235           }
236           catch (IOException e) {
237             LOG.warn("Tried to delete non existed _windows file");
238           }
239         }
240       });
241     }
242   }
243 }