IDEA-136705 (delay post-execution refresh to allow FS changes to reach the IDE)
[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.ide.projectView.actions.MarkRootActionBase;
5 import com.intellij.openapi.actionSystem.AnActionEvent;
6 import com.intellij.openapi.actionSystem.Presentation;
7 import com.intellij.openapi.application.ApplicationManager;
8 import com.intellij.openapi.command.CommandProcessor;
9 import com.intellij.openapi.diagnostic.Logger;
10 import com.intellij.openapi.editor.Document;
11 import com.intellij.openapi.fileEditor.FileDocumentManager;
12 import com.intellij.openapi.module.Module;
13 import com.intellij.openapi.module.ModuleUtilCore;
14 import com.intellij.openapi.project.Project;
15 import com.intellij.openapi.roots.ContentEntry;
16 import com.intellij.openapi.roots.ModifiableRootModel;
17 import com.intellij.openapi.roots.ModuleRootManager;
18 import com.intellij.openapi.util.TextRange;
19 import com.intellij.openapi.vfs.VirtualFile;
20 import com.intellij.openapi.vfs.VirtualFileManager;
21 import com.jetbrains.edu.courseFormat.AnswerPlaceholder;
22 import com.jetbrains.edu.courseFormat.TaskFile;
23 import org.jetbrains.annotations.NotNull;
24 import org.jetbrains.annotations.Nullable;
25
26 import java.io.FileOutputStream;
27 import java.io.IOException;
28 import java.io.PrintWriter;
29 import java.util.Collection;
30 import java.util.Map;
31
32 public class EduUtils {
33   private EduUtils() {
34   }
35   private static final Logger LOG = Logger.getInstance(EduUtils.class.getName());
36
37
38   public static void markDirAsSourceRoot(@NotNull final VirtualFile dir, @NotNull final Project project) {
39     final Module module = ModuleUtilCore.findModuleForFile(dir, project);
40     if (module == null) {
41       LOG.info("Module for " + dir.getPath() + " was not found");
42       return;
43     }
44     final ModifiableRootModel model = ModuleRootManager.getInstance(module).getModifiableModel();
45     final ContentEntry entry = MarkRootActionBase.findContentEntry(model, dir);
46     if (entry == null) {
47       LOG.info("Content entry for " + dir.getPath() + " was not found");
48       return;
49     }
50     entry.addSourceFolder(dir, false);
51     ApplicationManager.getApplication().runWriteAction(new Runnable() {
52       @Override
53       public void run() {
54         model.commit();
55         module.getProject().save();
56       }
57     });
58   }
59
60   public static void enableAction(@NotNull final AnActionEvent event, boolean isEnable) {
61     final Presentation presentation = event.getPresentation();
62     presentation.setVisible(isEnable);
63     presentation.setEnabled(isEnable);
64   }
65
66   /**
67    * Gets number index in directory names like "task1", "lesson2"
68    *
69    * @param fullName    full name of directory
70    * @param logicalName part of name without index
71    * @return index of object
72    */
73   public static int getIndex(@NotNull final String fullName, @NotNull final String logicalName) {
74     if (!fullName.contains(logicalName)) {
75       return -1;
76     }
77     return Integer.parseInt(fullName.substring(logicalName.length())) - 1;
78   }
79
80   public static boolean indexIsValid(int index, Collection collection) {
81     int size = collection.size();
82     return index >= 0 && index < size;
83   }
84
85   @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
86   @Nullable
87   public static VirtualFile flushWindows(@NotNull final TaskFile taskFile, @NotNull final VirtualFile file,
88                                          boolean useLength) {
89     final VirtualFile taskDir = file.getParent();
90     VirtualFile fileWindows = null;
91     final Document document = FileDocumentManager.getInstance().getDocument(file);
92     if (document == null) {
93       LOG.debug("Couldn't flush windows");
94       return null;
95     }
96     if (taskDir != null) {
97       final String name = file.getNameWithoutExtension() + "_windows";
98       PrintWriter printWriter = null;
99       try {
100         fileWindows = taskDir.createChildData(taskFile, name);
101         printWriter = new PrintWriter(new FileOutputStream(fileWindows.getPath()));
102         for (AnswerPlaceholder answerPlaceholder : taskFile.getAnswerPlaceholders()) {
103           if (!answerPlaceholder.isValid(document)) {
104             printWriter.println("#educational_plugin_window = ");
105             continue;
106           }
107           int start = answerPlaceholder.getRealStartOffset(document);
108           int length = useLength ? answerPlaceholder.getLength() : answerPlaceholder.getPossibleAnswerLength();
109           final String windowDescription = document.getText(new TextRange(start, start + length));
110           printWriter.println("#educational_plugin_window = " + windowDescription);
111         }
112         ApplicationManager.getApplication().runWriteAction(new Runnable() {
113           @Override
114           public void run() {
115             FileDocumentManager.getInstance().saveDocument(document);
116           }
117         });
118       }
119       catch (IOException e) {
120         LOG.error(e);
121       }
122       finally {
123         if (printWriter != null) {
124           printWriter.close();
125         }
126         synchronize();
127       }
128     }
129     return fileWindows;
130   }
131
132   public static void synchronize() {
133     FileDocumentManager.getInstance().saveAllDocuments();
134     SaveAndSyncHandler.getInstance().refreshOpenFiles();
135     VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
136   }
137
138   public static void createStudentFileFromAnswer(@NotNull final Project project,
139                                                  @NotNull final VirtualFile userFileDir,
140                                                  @NotNull final VirtualFile answerFileDir,
141                                                  @NotNull final Map.Entry<String, TaskFile> taskFileEntry) {
142     final String name = taskFileEntry.getKey();
143     final TaskFile taskFile = taskFileEntry.getValue();
144     VirtualFile file = userFileDir.findChild(name);
145     if (file != null) {
146       try {
147         file.delete(project);
148       }
149       catch (IOException e) {
150         LOG.error(e);
151       }
152     }
153     try {
154       userFileDir.createChildData(project, name);
155     }
156     catch (IOException e) {
157       LOG.error(e);
158     }
159
160     file = userFileDir.findChild(name);
161     assert file != null;
162     String answerFileName = file.getNameWithoutExtension() + ".answer." + file.getExtension();
163     VirtualFile answerFile = answerFileDir.findChild(answerFileName);
164     if (answerFile == null) {
165       return;
166     }
167     final Document answerDocument = FileDocumentManager.getInstance().getDocument(answerFile);
168     if (answerDocument == null) {
169       return;
170     }
171     final Document document = FileDocumentManager.getInstance().getDocument(file);
172     if (document == null) return;
173
174     CommandProcessor.getInstance().executeCommand(project, new Runnable() {
175       @Override
176       public void run() {
177         ApplicationManager.getApplication().runWriteAction(new Runnable() {
178           @Override
179           public void run() {
180             document.replaceString(0, document.getTextLength(), answerDocument.getCharsSequence());
181           }
182         });
183       }
184     }, "Create Student File", "Create Student File");
185     EduDocumentListener listener = new EduDocumentListener(taskFile, false);
186     document.addDocumentListener(listener);
187     taskFile.sortAnswerPlaceholders();
188     for (int i = taskFile.getAnswerPlaceholders().size() - 1; i >= 0; i--) {
189       final AnswerPlaceholder answerPlaceholder = taskFile.getAnswerPlaceholders().get(i);
190       replaceAnswerPlaceholder(project, document, answerPlaceholder);
191     }
192     CommandProcessor.getInstance().executeCommand(project, new Runnable() {
193       @Override
194       public void run() {
195         ApplicationManager.getApplication().runWriteAction(new Runnable() {
196           @Override
197           public void run() {
198             FileDocumentManager.getInstance().saveDocument(document);
199           }
200         });
201       }
202     }, "Create Student File", "Create Student File");
203     document.removeDocumentListener(listener);
204   }
205
206   private static void replaceAnswerPlaceholder(@NotNull final Project project,
207                                                @NotNull final Document document,
208                                                @NotNull final AnswerPlaceholder answerPlaceholder) {
209     final String taskText = answerPlaceholder.getTaskText();
210     final int offset = answerPlaceholder.getRealStartOffset(document);
211     CommandProcessor.getInstance().executeCommand(project, new Runnable() {
212       @Override
213       public void run() {
214         ApplicationManager.getApplication().runWriteAction(new Runnable() {
215           @Override
216           public void run() {
217             document.replaceString(offset, offset + answerPlaceholder.getPossibleAnswerLength(), taskText);
218             FileDocumentManager.getInstance().saveDocument(document);
219           }
220         });
221       }
222     }, "Replace Answer Placeholders", "Replace Answer Placeholders");
223   }
224 }