1 package com.jetbrains.edu.learning;
3 import com.intellij.execution.RunContentExecutor;
4 import com.intellij.execution.configurations.GeneralCommandLine;
5 import com.intellij.execution.process.ProcessHandler;
6 import com.intellij.lang.Language;
7 import com.intellij.openapi.actionSystem.AnActionEvent;
8 import com.intellij.openapi.actionSystem.CommonDataKeys;
9 import com.intellij.openapi.actionSystem.DataContext;
10 import com.intellij.openapi.actionSystem.Presentation;
11 import com.intellij.openapi.application.ApplicationManager;
12 import com.intellij.openapi.diagnostic.Logger;
13 import com.intellij.openapi.editor.Document;
14 import com.intellij.openapi.editor.Editor;
15 import com.intellij.openapi.editor.RangeMarker;
16 import com.intellij.openapi.editor.actionSystem.EditorActionManager;
17 import com.intellij.openapi.editor.colors.EditorColors;
18 import com.intellij.openapi.editor.colors.EditorColorsManager;
19 import com.intellij.openapi.editor.impl.DocumentImpl;
20 import com.intellij.openapi.fileEditor.FileDocumentManager;
21 import com.intellij.openapi.fileEditor.FileEditor;
22 import com.intellij.openapi.fileEditor.FileEditorManager;
23 import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
24 import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
25 import com.intellij.openapi.progress.ProgressManager;
26 import com.intellij.openapi.project.Project;
27 import com.intellij.openapi.project.ProjectManager;
28 import com.intellij.openapi.projectRoots.Sdk;
29 import com.intellij.openapi.ui.MessageType;
30 import com.intellij.openapi.ui.popup.Balloon;
31 import com.intellij.openapi.ui.popup.JBPopupFactory;
32 import com.intellij.openapi.util.Disposer;
33 import com.intellij.openapi.util.io.FileUtil;
34 import com.intellij.openapi.util.text.StringUtil;
35 import com.intellij.openapi.vfs.LocalFileSystem;
36 import com.intellij.openapi.vfs.VfsUtil;
37 import com.intellij.openapi.vfs.VirtualFile;
38 import com.intellij.openapi.wm.IdeFocusManager;
39 import com.intellij.openapi.wm.ToolWindow;
40 import com.intellij.openapi.wm.ToolWindowManager;
41 import com.intellij.psi.PsiDirectory;
42 import com.intellij.psi.PsiElement;
43 import com.intellij.psi.PsiFile;
44 import com.intellij.ui.JBColor;
45 import com.intellij.ui.awt.RelativePoint;
46 import com.intellij.ui.content.Content;
47 import com.intellij.util.ObjectUtils;
48 import com.intellij.util.TimeoutUtil;
49 import com.intellij.util.containers.ContainerUtil;
50 import com.intellij.util.text.MarkdownUtil;
51 import com.intellij.util.ui.UIUtil;
52 import com.jetbrains.edu.learning.checker.StudyExecutor;
53 import com.jetbrains.edu.learning.checker.StudyTestRunner;
54 import com.jetbrains.edu.learning.core.EduAnswerPlaceholderDeleteHandler;
55 import com.jetbrains.edu.learning.core.EduAnswerPlaceholderPainter;
56 import com.jetbrains.edu.learning.core.EduNames;
57 import com.jetbrains.edu.learning.core.EduUtils;
58 import com.jetbrains.edu.learning.courseFormat.*;
59 import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator;
60 import com.jetbrains.edu.learning.editor.StudyEditor;
61 import com.jetbrains.edu.learning.stepic.CourseInfo;
62 import com.jetbrains.edu.learning.ui.StudyToolWindow;
63 import com.jetbrains.edu.learning.ui.StudyToolWindowFactory;
64 import com.petebevin.markdown.MarkdownProcessor;
65 import org.jetbrains.annotations.NotNull;
66 import org.jetbrains.annotations.Nullable;
72 import java.util.List;
73 import java.util.concurrent.Callable;
74 import java.util.concurrent.ExecutionException;
75 import java.util.concurrent.Future;
77 public class StudyUtils {
78 private StudyUtils() {
81 private static final Logger LOG = Logger.getInstance(StudyUtils.class.getName());
82 private static final String EMPTY_TASK_TEXT = "Please, open any task to see task description";
83 private static final String ourPrefix = "<html><head><script type=\"text/x-mathjax-config\">\n" +
84 " MathJax.Hub.Config({\n" +
86 " inlineMath: [ ['$','$'], [\"\\\\(\",\"\\\\)\"] ],\n" +
87 " displayMath: [ ['$$','$$'], [\"\\\\[\",\"\\\\]\"] ],\n" +
88 " processEscapes: true,\n" +
89 " processEnvironments: true\n" +
91 " displayAlign: 'center',\n" +
92 " \"HTML-CSS\": {\n" +
93 " styles: {'#mydiv': {\"font-size\": %s}},\n" +
94 " preferredFont: null,\n" +
95 " linebreaks: { automatic: true }\n" +
98 "</script><script type=\"text/javascript\"\n" +
99 " src=\"http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML-full\">\n" +
100 " </script></head><body><div id=\"mydiv\">";
102 private static final String ourPostfix = "</div></body></html>";
104 public static void closeSilently(@Nullable final Closeable stream) {
105 if (stream != null) {
109 catch (IOException e) {
115 public static boolean isZip(String fileName) {
116 return fileName.contains(".zip");
120 public static <T> T getFirst(@NotNull final Iterable<T> container) {
121 Iterator<T> iterator = container.iterator();
122 if (!iterator.hasNext()) {
125 return iterator.next();
128 public static boolean indexIsValid(int index, @NotNull final Collection collection) {
129 int size = collection.size();
130 return index >= 0 && index < size;
133 @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
135 public static String getFileText(@Nullable final String parentDir, @NotNull final String fileName, boolean wrapHTML,
136 @NotNull final String encoding) {
137 final File inputFile = parentDir != null ? new File(parentDir, fileName) : new File(fileName);
138 if (!inputFile.exists()) return null;
139 final StringBuilder taskText = new StringBuilder();
140 BufferedReader reader = null;
142 reader = new BufferedReader(new InputStreamReader(new FileInputStream(inputFile), encoding));
144 while ((line = reader.readLine()) != null) {
145 taskText.append(line).append("\n");
147 taskText.append("<br>");
150 return wrapHTML ? UIUtil.toHtml(taskText.toString()) : taskText.toString();
152 catch (IOException e) {
153 LOG.info("Failed to get file text from file " + fileName, e);
156 closeSilently(reader);
161 public static void updateAction(@NotNull final AnActionEvent e) {
162 final Presentation presentation = e.getPresentation();
163 presentation.setEnabled(false);
164 final Project project = e.getProject();
165 if (project != null) {
166 final StudyEditor studyEditor = getSelectedStudyEditor(project);
167 if (studyEditor != null) {
168 presentation.setEnabledAndVisible(true);
173 public static void updateToolWindows(@NotNull final Project project) {
174 final StudyToolWindow studyToolWindow = getStudyToolWindow(project);
175 if (studyToolWindow != null) {
176 String taskText = getTaskText(project);
177 if (taskText != null) {
178 studyToolWindow.setTaskText(taskText, null, project);
181 LOG.warn("Task text is null");
183 studyToolWindow.updateCourseProgress(project);
187 public static void initToolWindows(@NotNull final Project project) {
188 final ToolWindowManager windowManager = ToolWindowManager.getInstance(project);
189 windowManager.getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW).getContentManager().removeAllContents(false);
190 StudyToolWindowFactory factory = new StudyToolWindowFactory();
191 factory.createToolWindowContent(project, windowManager.getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW));
196 public static StudyToolWindow getStudyToolWindow(@NotNull final Project project) {
197 if (project.isDisposed()) return null;
199 ToolWindow toolWindow = ToolWindowManager.getInstance(project).getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW);
200 if (toolWindow != null) {
201 Content[] contents = toolWindow.getContentManager().getContents();
202 for (Content content: contents) {
203 JComponent component = content.getComponent();
204 if (component != null && component instanceof StudyToolWindow) {
205 return (StudyToolWindow)component;
212 public static void deleteFile(@NotNull final VirtualFile file) {
214 file.delete(StudyUtils.class);
216 catch (IOException e) {
221 public static File copyResourceFile(@NotNull final String sourceName, @NotNull final String copyName, @NotNull final Project project,
222 @NotNull final Task task)
224 final StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
225 final Course course = taskManager.getCourse();
226 int taskNum = task.getIndex();
227 int lessonNum = task.getLesson().getIndex();
228 assert course != null;
229 final String pathToResource = FileUtil.join(course.getCourseDirectory(), EduNames.LESSON + lessonNum, EduNames.TASK + taskNum);
230 final File resourceFile = new File(pathToResource, copyName);
231 FileUtil.copy(new File(pathToResource, sourceName), resourceFile);
236 public static Sdk findSdk(@NotNull final Task task, @NotNull final Project project) {
237 final Language language = task.getLesson().getCourse().getLanguageById();
238 return StudyExecutor.INSTANCE.forLanguage(language).findSdk(project);
242 public static StudyTestRunner getTestRunner(@NotNull final Task task, @NotNull final VirtualFile taskDir) {
243 final Language language = task.getLesson().getCourse().getLanguageById();
244 return StudyExecutor.INSTANCE.forLanguage(language).getTestRunner(task, taskDir);
247 public static RunContentExecutor getExecutor(@NotNull final Project project, @NotNull final Task currentTask,
248 @NotNull final ProcessHandler handler) {
249 final Language language = currentTask.getLesson().getCourse().getLanguageById();
250 return StudyExecutor.INSTANCE.forLanguage(language).getExecutor(project, handler);
253 public static void setCommandLineParameters(@NotNull final GeneralCommandLine cmd,
254 @NotNull final Project project,
255 @NotNull final String filePath,
256 @NotNull final String sdkPath,
257 @NotNull final Task currentTask) {
258 final Language language = currentTask.getLesson().getCourse().getLanguageById();
259 StudyExecutor.INSTANCE.forLanguage(language).setCommandLineParameters(cmd, project, filePath, sdkPath, currentTask);
262 public static void showNoSdkNotification(@NotNull final Task currentTask, @NotNull final Project project) {
263 final Language language = currentTask.getLesson().getCourse().getLanguageById();
264 StudyExecutor.INSTANCE.forLanguage(language).showNoSdkNotification(project);
269 * shows pop up in the center of "check task" button in study editor
271 public static void showCheckPopUp(@NotNull final Project project, @NotNull final Balloon balloon) {
272 final StudyEditor studyEditor = getSelectedStudyEditor(project);
273 assert studyEditor != null;
275 balloon.show(computeLocation(studyEditor.getEditor()), Balloon.Position.above);
276 Disposer.register(project, balloon);
279 public static RelativePoint computeLocation(Editor editor){
281 final Rectangle visibleRect = editor.getComponent().getVisibleRect();
282 Point point = new Point(visibleRect.x + visibleRect.width + 10,
284 return new RelativePoint(editor.getComponent(), point);
289 * returns language manager which contains all the information about language specific file names
292 public static StudyLanguageManager getLanguageManager(@NotNull final Course course) {
293 Language language = course.getLanguageById();
294 return language == null ? null : StudyLanguageManager.INSTANCE.forLanguage(language);
297 public static boolean isTestsFile(@NotNull Project project, @NotNull final String name) {
298 Course course = StudyTaskManager.getInstance(project).getCourse();
299 if (course == null) {
302 StudyLanguageManager manager = getLanguageManager(course);
303 if (manager == null) {
306 return manager.getTestFileName().equals(name);
310 public static TaskFile getTaskFile(@NotNull final Project project, @NotNull final VirtualFile file) {
311 final Course course = StudyTaskManager.getInstance(project).getCourse();
312 if (course == null) {
315 VirtualFile taskDir = file.getParent();
316 if (taskDir == null) {
319 //need this because of multi-module generation
320 if (EduNames.SRC.equals(taskDir.getName())) {
321 taskDir = taskDir.getParent();
322 if (taskDir == null) {
326 final String taskDirName = taskDir.getName();
327 if (taskDirName.contains(EduNames.TASK)) {
328 final VirtualFile lessonDir = taskDir.getParent();
329 if (lessonDir != null) {
330 int lessonIndex = EduUtils.getIndex(lessonDir.getName(), EduNames.LESSON);
331 List<Lesson> lessons = course.getLessons();
332 if (!indexIsValid(lessonIndex, lessons)) {
335 final Lesson lesson = lessons.get(lessonIndex);
336 int taskIndex = EduUtils.getIndex(taskDirName, EduNames.TASK);
337 final List<Task> tasks = lesson.getTaskList();
338 if (!indexIsValid(taskIndex, tasks)) {
341 final Task task = tasks.get(taskIndex);
342 return task.getFile(file.getName());
348 public static void drawAllWindows(Editor editor, TaskFile taskFile) {
349 editor.getMarkupModel().removeAllHighlighters();
350 final Project project = editor.getProject();
351 if (project == null) return;
352 final StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
353 for (AnswerPlaceholder answerPlaceholder : taskFile.getAnswerPlaceholders()) {
354 final JBColor color = taskManager.getColor(answerPlaceholder);
355 EduAnswerPlaceholderPainter.drawAnswerPlaceholder(editor, answerPlaceholder, color);
357 final Document document = editor.getDocument();
358 EditorActionManager.getInstance()
359 .setReadonlyFragmentModificationHandler(document, new EduAnswerPlaceholderDeleteHandler(editor));
360 EduAnswerPlaceholderPainter.createGuardedBlocks(editor, taskFile);
361 editor.getColorsScheme().setColor(EditorColors.READONLY_FRAGMENT_BACKGROUND_COLOR, null);
365 public static StudyEditor getSelectedStudyEditor(@NotNull final Project project) {
367 final FileEditor fileEditor = FileEditorManagerEx.getInstanceEx(project).getSplitters().getCurrentWindow().
368 getSelectedEditor().getSelectedEditorWithProvider().getFirst();
369 if (fileEditor instanceof StudyEditor) {
370 return (StudyEditor)fileEditor;
373 catch (Exception e) {
380 public static Editor getSelectedEditor(@NotNull final Project project) {
381 final StudyEditor studyEditor = getSelectedStudyEditor(project);
382 if (studyEditor != null) {
383 return studyEditor.getEditor();
388 public static void deleteGuardedBlocks(@NotNull final Document document) {
389 if (document instanceof DocumentImpl) {
390 final DocumentImpl documentImpl = (DocumentImpl)document;
391 List<RangeMarker> blocks = documentImpl.getGuardedBlocks();
392 for (final RangeMarker block : blocks) {
393 ApplicationManager.getApplication().invokeLater(() -> ApplicationManager.getApplication().runWriteAction(() -> document.removeGuardedBlock(block)));
400 public static VirtualFile getPatternFile(@NotNull TaskFile taskFile, String name) {
401 Task task = taskFile.getTask();
402 String lessonDir = EduNames.LESSON + String.valueOf(task.getLesson().getIndex());
403 String taskDir = EduNames.TASK + String.valueOf(task.getIndex());
404 Course course = task.getLesson().getCourse();
405 File resourceFile = new File(course.getCourseDirectory());
406 if (!resourceFile.exists()) {
409 String patternPath = FileUtil.join(resourceFile.getPath(), lessonDir, taskDir, name);
410 VirtualFile patternFile = VfsUtil.findFileByIoFile(new File(patternPath), true);
411 if (patternFile == null) {
418 public static Document getPatternDocument(@NotNull final TaskFile taskFile, String name) {
419 VirtualFile patternFile = getPatternFile(taskFile, name);
420 if (patternFile == null) {
423 return FileDocumentManager.getInstance().getDocument(patternFile);
426 public static boolean isRenameableOrMoveable(@NotNull final Project project, @NotNull final Course course, @NotNull final PsiElement element) {
427 if (element instanceof PsiFile) {
428 VirtualFile virtualFile = ((PsiFile)element).getVirtualFile();
429 if (project.getBaseDir().equals(virtualFile.getParent())) {
432 TaskFile file = getTaskFile(project, virtualFile);
436 String name = virtualFile.getName();
437 return !isTestsFile(project, name) && !isTaskDescriptionFile(name);
439 if (element instanceof PsiDirectory) {
440 VirtualFile virtualFile = ((PsiDirectory)element).getVirtualFile();
441 VirtualFile parent = virtualFile.getParent();
442 if (parent == null) {
445 if (project.getBaseDir().equals(parent)) {
448 Lesson lesson = course.getLesson(parent.getName());
449 if (lesson != null) {
450 Task task = lesson.getTask(virtualFile.getName());
459 public static boolean canRenameOrMove(DataContext dataContext) {
460 Project project = CommonDataKeys.PROJECT.getData(dataContext);
461 PsiElement element = CommonDataKeys.PSI_ELEMENT.getData(dataContext);
462 if (element == null || project == null) {
465 Course course = StudyTaskManager.getInstance(project).getCourse();
466 if (course == null || !EduNames.STUDY.equals(course.getCourseMode())) {
470 if (!isRenameableOrMoveable(project, course, element)) {
477 public static String getTaskTextFromTask(@Nullable final VirtualFile taskDirectory, @Nullable final Task task) {
483 String text = task.getText();
484 if (text != null && !text.isEmpty()) {
485 return wrapTextToDisplayLatex(text);
487 if (taskDirectory != null) {
488 final String taskTextFileHtml = getTaskTextFromTaskName(taskDirectory, EduNames.TASK_HTML);
489 if (taskTextFileHtml != null) return wrapTextToDisplayLatex(taskTextFileHtml);
491 final String taskTextFileMd = getTaskTextFromTaskName(taskDirectory, EduNames.TASK_MD);
492 if (taskTextFileMd != null) return wrapTextToDisplayLatex(convertToHtml(taskTextFileMd));
497 public static String wrapTextToDisplayLatex(String taskTextFileHtml) {
498 final String prefix = String.format(ourPrefix, EditorColorsManager.getInstance().getGlobalScheme().getEditorFontSize());
499 return prefix + taskTextFileHtml + ourPostfix;
503 private static String getTaskTextFromTaskName(@NotNull VirtualFile taskDirectory, @NotNull String taskTextFilename) {
504 taskDirectory.refresh(false, true);
505 VirtualFile taskTextFile = taskDirectory.findChild(taskTextFilename);
506 if (taskTextFile == null) {
507 VirtualFile srcDir = taskDirectory.findChild(EduNames.SRC);
508 if (srcDir != null) {
509 taskTextFile = srcDir.findChild(taskTextFilename);
512 if (taskTextFile != null) {
513 return String.valueOf(LoadTextUtil.loadText(taskTextFile));
519 public static StudyPluginConfigurator getConfigurator(@NotNull final Project project) {
520 StudyPluginConfigurator[] extensions = StudyPluginConfigurator.EP_NAME.getExtensions();
521 for (StudyPluginConfigurator extension: extensions) {
522 if (extension.accept(project)) {
530 public static StudyTwitterPluginConfigurator getTwitterConfigurator(@NotNull final Project project) {
531 StudyTwitterPluginConfigurator[] extensions = StudyTwitterPluginConfigurator.EP_NAME.getExtensions();
532 for (StudyTwitterPluginConfigurator extension: extensions) {
533 if (extension.accept(project)) {
541 public static String getTaskText(@NotNull final Project project) {
542 TaskFile taskFile = getSelectedTaskFile(project);
543 if (taskFile == null) {
544 return EMPTY_TASK_TEXT;
546 final Task task = taskFile.getTask();
548 return getTaskTextFromTask(task.getTaskDir(project), task);
553 public static TaskFile getSelectedTaskFile(@NotNull Project project) {
554 VirtualFile[] files = FileEditorManager.getInstance(project).getSelectedFiles();
555 TaskFile taskFile = null;
556 for (VirtualFile file : files) {
557 taskFile = getTaskFile(project, file);
558 if (taskFile != null) {
566 public static Task getCurrentTask(@NotNull final Project project) {
567 final TaskFile taskFile = getSelectedTaskFile(project);
568 return taskFile != null ? taskFile.getTask() : null;
571 public static boolean isStudyProject(@NotNull Project project) {
572 return StudyTaskManager.getInstance(project).getCourse() != null;
576 public static Project getStudyProject() {
577 Project studyProject = null;
578 Project[] openProjects = ProjectManager.getInstance().getOpenProjects();
579 for (Project project : openProjects) {
580 if (StudyTaskManager.getInstance(project).getCourse() != null) {
581 studyProject = project;
588 public static File getCourseDirectory(@NotNull Project project, Course course) {
589 final File courseDirectory;
590 if (course.isAdaptive()) {
591 courseDirectory = new File(StudyProjectGenerator.OUR_COURSES_DIR,
592 StudyProjectGenerator.ADAPTIVE_COURSE_PREFIX + course.getName()
593 + "_" + StudyTaskManager.getInstance(project).getUser().getEmail());
596 courseDirectory = new File(StudyProjectGenerator.OUR_COURSES_DIR, course.getName());
598 return courseDirectory;
601 public static boolean hasJavaFx() {
603 Class.forName("javafx.application.Platform");
606 catch (ClassNotFoundException e) {
612 public static Task getTask(@NotNull Project project, @NotNull VirtualFile taskVF) {
613 Course course = StudyTaskManager.getInstance(project).getCourse();
614 if (course == null) {
617 VirtualFile lessonVF = taskVF.getParent();
618 if (lessonVF == null) {
621 Lesson lesson = course.getLesson(lessonVF.getName());
622 if (lesson == null) {
625 return lesson.getTask(taskVF.getName());
629 public static VirtualFile getTaskDir(@NotNull VirtualFile taskFile) {
630 VirtualFile parent = taskFile.getParent();
631 if (parent == null) {
634 String name = parent.getName();
635 if (name.contains(EduNames.TASK)) {
638 if (EduNames.SRC.equals(name)) {
639 return parent.getParent();
645 public static Task getTaskForFile(@NotNull Project project, @NotNull VirtualFile taskFile) {
646 VirtualFile taskDir = getTaskDir(taskFile);
647 if (taskDir == null) {
650 return getTask(project, taskDir);
653 // supposed to be called under progress
655 public static <T> T execCancelable(@NotNull final Callable<T> callable) {
656 final Future<T> future = ApplicationManager.getApplication().executeOnPooledThread(callable);
658 while (!future.isCancelled() && !future.isDone()) {
659 ProgressManager.checkCanceled();
660 TimeoutUtil.sleep(500);
664 result = future.get();
666 catch (InterruptedException | ExecutionException e) {
667 LOG.warn(e.getMessage());
673 public static Task getTaskFromSelectedEditor(Project project) {
674 final StudyEditor editor = getSelectedStudyEditor(project);
676 if (editor != null) {
677 final TaskFile file = editor.getTaskFile();
678 task = file.getTask();
683 private static String convertToHtml(@NotNull final String content) {
684 ArrayList<String> lines = ContainerUtil.newArrayList(content.split("\n|\r|\r\n"));
685 MarkdownUtil.replaceHeaders(lines);
686 MarkdownUtil.replaceCodeBlock(lines);
688 return new MarkdownProcessor().markdown(StringUtil.join(lines, "\n"));
691 public static boolean isTaskDescriptionFile(@NotNull final String fileName) {
692 return EduNames.TASK_HTML.equals(fileName) || EduNames.TASK_MD.equals(fileName);
696 public static VirtualFile findTaskDescriptionVirtualFile(@NotNull VirtualFile taskDir) {
697 return ObjectUtils.chooseNotNull(taskDir.findChild(EduNames.TASK_HTML), taskDir.findChild(EduNames.TASK_MD));
701 public static String getTaskDescriptionFileName(final boolean useHtml) {
702 return useHtml ? EduNames.TASK_HTML : EduNames.TASK_MD;
706 public static Document getDocument(String basePath, int lessonIndex, int taskIndex, String fileName) {
707 String taskPath = FileUtil.join(basePath, EduNames.LESSON + lessonIndex, EduNames.TASK + taskIndex);
708 VirtualFile taskFile = LocalFileSystem.getInstance().findFileByPath(FileUtil.join(taskPath, fileName));
709 if (taskFile == null) {
710 taskFile = LocalFileSystem.getInstance().findFileByPath(FileUtil.join(taskPath, EduNames.SRC, fileName));
712 if (taskFile == null) {
715 return FileDocumentManager.getInstance().getDocument(taskFile);
718 public static void showErrorPopupOnToolbar(@NotNull Project project) {
719 final Balloon balloon =
720 JBPopupFactory.getInstance().createHtmlTextBalloonBuilder("Couldn't post your reaction", MessageType.ERROR, null).createBalloon();
721 showCheckPopUp(project, balloon);
724 public static void sortCourses(List<CourseInfo> result) {
725 // sort courses so as to have non-adaptive courses in the beginning of the list
726 Collections.sort(result, (c1, c2) -> {
727 if ((c1.isAdaptive() && c2.isAdaptive()) || (!c1.isAdaptive() && !c2.isAdaptive())) {
731 return c1.isAdaptive() ? 1 : -1;
735 public static void selectFirstAnswerPlaceholder(@Nullable final StudyEditor studyEditor, @NotNull final Project project) {
736 if (studyEditor == null) return;
737 final Editor editor = studyEditor.getEditor();
738 IdeFocusManager.getInstance(project).requestFocus(editor.getContentComponent(), true);
739 final List<AnswerPlaceholder> placeholders = studyEditor.getTaskFile().getAnswerPlaceholders();
740 if (placeholders.isEmpty()) return;
741 final AnswerPlaceholder placeholder = placeholders.get(0);
742 int startOffset = placeholder.getOffset();
743 editor.getSelectionModel().setSelection(startOffset, startOffset + placeholder.getRealLength());