<extensions defaultExtensionNs="com.intellij">
<directoryProjectGenerator implementation="com.jetbrains.edu.coursecreator.PyCCProjectGenerator"/>
- <fileTypeFactory implementation="com.jetbrains.edu.coursecreator.PyCCAnswerFileTypeFactory" />
<errorHandler implementation="com.intellij.diagnostic.ITNReporter"/>
</extensions>
+ <extensions defaultExtensionNs="Edu">
+ <StudyLanguageManager implementationClass="com.jetbrains.edu.coursecreator.PyStudyLanguageManager" language="Python"/>
+ </extensions>
+
<application-components>
<!-- Add your application components here -->
</application-components>
+++ /dev/null
-/*
- * Copyright 2000-2014 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.jetbrains.edu.coursecreator;
-
-
-import com.intellij.openapi.fileTypes.FileTypeConsumer;
-import com.intellij.openapi.fileTypes.FileTypeFactory;
-import com.jetbrains.python.PythonFileType;
-import org.jetbrains.annotations.NotNull;
-
-public class PyCCAnswerFileTypeFactory extends FileTypeFactory {
- @Override
- public void createFileTypes(@NotNull FileTypeConsumer fileTypeConsumer) {
- fileTypeConsumer.consume(PythonFileType.INSTANCE, "answer");
- }
-}
final CCProjectService service = CCProjectService.getInstance(project);
final Course course = new Course(name, author, description);
+ course.setLanguage("Python");
service.setCourse(course);
final PsiDirectory projectDir = PsiManager.getInstance(project).findDirectory(baseDir);
--- /dev/null
+package com.jetbrains.edu.coursecreator;
+
+import com.intellij.ide.fileTemplates.FileTemplate;
+import com.intellij.ide.fileTemplates.FileTemplateManager;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class PyStudyLanguageManager implements StudyLanguageManager {
+ @Nullable
+ @Override
+ public String getDefaultTaskFileExtension() {
+ return "py";
+ }
+
+ @Nullable
+ @Override
+ public FileTemplate getTaskFileTemplateForExtension(@NotNull final Project project, String extension) {
+ if (!extension.equals("py")) {
+ return null;
+ }
+ return getInternalTemplateByName(project, "task.answer.py");
+ }
+
+ @Nullable
+ @Override
+ public FileTemplate getTestsTemplate(@NotNull final Project project) {
+ return getInternalTemplateByName(project, "tests.py");
+ }
+
+ private static FileTemplate getInternalTemplateByName(@NotNull final Project project, String name) {
+ return FileTemplateManager.getInstance(project).getInternalTemplate(name);
+ }
+}
</component>
</project-components>
+ <extensionPoints>
+ <extensionPoint qualifiedName="Edu.StudyLanguageManager" beanClass="com.intellij.lang.LanguageExtensionPoint">
+ </extensionPoint>
+ </extensionPoints>
+
<actions>
<action id="CreateLesson" class="com.jetbrains.edu.coursecreator.actions.CCCreateLesson">
<add-to-group group-id="NewGroup" anchor="before" relative-to-action="NewFile"/>
--- /dev/null
+package com.jetbrains.edu.coursecreator;
+
+import com.intellij.ide.fileTemplates.FileTemplate;
+import com.intellij.lang.LanguageExtension;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public interface StudyLanguageManager {
+ LanguageExtension<StudyLanguageManager> INSTANCE = new LanguageExtension<StudyLanguageManager>("Edu.StudyLanguageManager");
+
+ @Nullable
+ String getDefaultTaskFileExtension();
+
+ @Nullable
+ FileTemplate getTaskFileTemplateForExtension(@NotNull final Project project, String extension);
+
+ @Nullable
+ FileTemplate getTestsTemplate(@NotNull final Project project);
+}
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.util.io.ZipUtil;
file = userFileDir.findChild(name);
assert file != null;
- String answerFileName = file.getNameWithoutExtension() + ".answer";
+ String answerFileName = file.getNameWithoutExtension() + ".answer." + file.getExtension();
VirtualFile answerFile = answerFileDir.findChild(answerFileName);
if (answerFile == null) {
return;
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
- document.replaceString(0, document.getTextLength(), answerDocument.getText());
+ document.replaceString(0, document.getTextLength(), answerDocument.getCharsSequence());
}
});
}
final AnswerPlaceholder answerPlaceholder = taskFile.getTaskWindows().get(i);
replaceTaskWindow(project, document, answerPlaceholder);
}
+ CommandProcessor.getInstance().executeCommand(project, new Runnable() {
+ @Override
+ public void run() {
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ FileDocumentManager.getInstance().saveDocument(document);
+ }
+ });
+ }
+ }, "x", "qwe");
document.removeDocumentListener(listener);
}
@Override
public boolean accept(File pathname) {
String name = pathname.getName();
- return !name.contains(".answer") && !name.contains("__pycache__") && !name.contains("_windows") && !name.contains(".pyc");
+ String nameWithoutExtension = FileUtil.getNameWithoutExtension(pathname);
+ return !nameWithoutExtension.endsWith(".answer") && !name.contains("__pycache__") && !name.contains("_windows") && !name.contains(".pyc");
}
}, null);
}
import com.intellij.ide.util.DirectoryChooserUtil;
import com.intellij.ide.util.DirectoryUtil;
import com.intellij.ide.util.EditorHelper;
+import com.intellij.lang.Language;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.util.PlatformIcons;
import com.jetbrains.edu.coursecreator.CCProjectService;
import com.jetbrains.edu.coursecreator.CCUtils;
+import com.jetbrains.edu.coursecreator.StudyLanguageManager;
import com.jetbrains.edu.coursecreator.format.Course;
import com.jetbrains.edu.coursecreator.format.Lesson;
import com.jetbrains.edu.coursecreator.format.Task;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
public class CCCreateTask extends DumbAwareAction {
+ private static final Logger LOG = Logger.getInstance(CCCreateTask.class.getName());
+
public CCCreateTask() {
super("Task", "Create new Task", PlatformIcons.DIRECTORY_CLOSED_ICON);
}
public void run() {
final PsiDirectory taskDirectory = DirectoryUtil.createSubdirectories("task" + (size + 1), lessonDir, "\\/");
if (taskDirectory != null) {
+ Language language = Language.findLanguageByID(course.getLanguage());
+ if (language == null) {
+ return;
+ }
+ final StudyLanguageManager studyLanguageManager = StudyLanguageManager.INSTANCE.forLanguage(language);
CCUtils.markDirAsSourceRoot(taskDirectory.getVirtualFile(), project);
- final FileTemplate template = FileTemplateManager.getInstance(project).getInternalTemplate("task.html");
- final FileTemplate testsTemplate = FileTemplateManager.getInstance(project).getInternalTemplate("tests");
- final FileTemplate taskTemplate = FileTemplateManager.getInstance(project).getInternalTemplate("task.answer");
- try {
- final PsiElement taskFile = FileTemplateUtil.createFromTemplate(template, "task.html", null, taskDirectory);
- final PsiElement testsFile = FileTemplateUtil.createFromTemplate(testsTemplate, "tests.py", null, taskDirectory);
- final PsiElement taskPyFile = FileTemplateUtil.createFromTemplate(taskTemplate, "file1", null, taskDirectory);
- final Task task = new Task(taskName);
- task.addTaskFile("file1.py", size + 1);
- task.setIndex(size + 1);
- lesson.addTask(task, taskDirectory);
- ApplicationManager.getApplication().invokeLater(new Runnable() {
- @Override
- public void run() {
- FileEditorManager fileEditorManager = FileEditorManager.getInstance(project);
- for (VirtualFile virtualFile : fileEditorManager.getOpenFiles()) {
- fileEditorManager.closeFile(virtualFile);
- }
- if (view != null) {
- EditorHelper.openInEditor(testsFile, false);
- EditorHelper.openInEditor(taskPyFile, false);
- view.selectElement(taskFile);
- EditorHelper.openInEditor(taskFile, false);
- }
- }
- });
+ createFromTemplateAndOpen(taskDirectory, studyLanguageManager.getTestsTemplate(project), view);
+ createFromTemplateAndOpen(taskDirectory, FileTemplateManager.getInstance(project).getInternalTemplate("task.html"), view);
+ String defaultExtension = studyLanguageManager.getDefaultTaskFileExtension();
+ String taskFileName = null;
+ if (defaultExtension != null) {
+ FileTemplate taskFileTemplate = studyLanguageManager.getTaskFileTemplateForExtension(project,
+ defaultExtension);
+ createFromTemplateAndOpen(taskDirectory, taskFileTemplate, view);
+ if (taskFileTemplate != null) {
+ taskFileName = taskFileTemplate.getName();
+ }
}
- catch (Exception ignored) {
+
+ final Task task = new Task(taskName);
+ task.setIndex(size + 1);
+ lesson.addTask(task, taskDirectory);
+ if (taskFileName != null) {
+ task.addTaskFile(taskFileName, size + 1);
}
+ ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ FileEditorManager fileEditorManager = FileEditorManager.getInstance(project);
+ for (VirtualFile virtualFile : fileEditorManager.getOpenFiles()) {
+ fileEditorManager.closeFile(virtualFile);
+ }
+ }
+ });
}
}
});
}
+ private static void createFromTemplateAndOpen(@NotNull final PsiDirectory taskDirectory,
+ @Nullable final FileTemplate template,
+ @Nullable IdeView view) {
+ if (template == null) {
+ return;
+ }
+ try {
+ final PsiElement file = FileTemplateUtil.createFromTemplate(template, template.getName(), null, taskDirectory);
+ if (view != null) {
+ EditorHelper.openInEditor(file, false);
+ view.selectElement(file);
+ }
+ }
+ catch (Exception e) {
+ LOG.error(e);
+ }
+ }
+
@Override
public void update(@NotNull AnActionEvent event) {
if (!CCProjectService.setCCActionAvailable(event)) {
import com.intellij.icons.AllIcons;
import com.intellij.ide.IdeView;
import com.intellij.ide.fileTemplates.FileTemplate;
-import com.intellij.ide.fileTemplates.FileTemplateManager;
import com.intellij.ide.fileTemplates.FileTemplateUtil;
+import com.intellij.ide.projectView.ProjectView;
import com.intellij.ide.util.DirectoryChooserUtil;
import com.intellij.ide.util.EditorHelper;
+import com.intellij.lang.Language;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
import com.jetbrains.edu.coursecreator.CCProjectService;
+import com.jetbrains.edu.coursecreator.StudyLanguageManager;
import com.jetbrains.edu.coursecreator.format.Course;
import com.jetbrains.edu.coursecreator.format.Lesson;
import com.jetbrains.edu.coursecreator.format.Task;
+import com.jetbrains.edu.coursecreator.ui.CreateTaskFileDialog;
import org.jetbrains.annotations.NotNull;
+import static com.intellij.openapi.ui.DialogWrapper.OK_EXIT_CODE;
+
public class CCCreateTaskFile extends DumbAwareAction {
public CCCreateTaskFile() {
}
@Override
- public void actionPerformed(AnActionEvent e) {
+ public void actionPerformed(final AnActionEvent e) {
final IdeView view = e.getData(LangDataKeys.IDE_VIEW);
final Project project = e.getData(CommonDataKeys.PROJECT);
final int index = task.getTaskFiles().size() + 1;
String generatedName = "file" + index;
- final String taskFileName = Messages.showInputDialog("Name:", "Task File Name", null, generatedName, null);
+ CreateTaskFileDialog dialog = new CreateTaskFileDialog(project, generatedName);
+ dialog.show();
+ if (dialog.getExitCode() != OK_EXIT_CODE) {
+ return;
+ }
+ final String taskFileName = dialog.getFileName();
if (taskFileName == null) return;
-
+ FileType type = dialog.getFileType();
+ if (type == null) {
+ return;
+ }
+ Language language = Language.findLanguageByID(course.getLanguage());
+ if (language == null) {
+ return;
+ }
+ final StudyLanguageManager studyLanguageManager = StudyLanguageManager.INSTANCE.forLanguage(language);
+ final String extension = type.getDefaultExtension();
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
- final FileTemplate taskTemplate = FileTemplateManager.getInstance(project).getInternalTemplate("task.answer");
- try {
- final PsiElement taskPyFile = FileTemplateUtil.createFromTemplate(taskTemplate, taskFileName, null, taskDir);
- task.addTaskFile(taskFileName + ".py", index);
+ final FileTemplate taskTemplate = studyLanguageManager.getTaskFileTemplateForExtension(project, extension);
+ final String answerFileName = taskFileName + ".answer." + extension;
+ try {
+ if (taskTemplate == null) {
+ VirtualFile file = taskDir.getVirtualFile().createChildData(this, answerFileName);
+ ProjectView.getInstance(project).select(file, file, false);
+ FileEditorManager.getInstance(project).openFile(file, true);
+ }
+ else {
+ final PsiElement taskFile = FileTemplateUtil.createFromTemplate(taskTemplate, answerFileName, null, taskDir);
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
- EditorHelper.openInEditor(taskPyFile, false);
- view.selectElement(taskPyFile);
+ EditorHelper.openInEditor(taskFile, false);
+ view.selectElement(taskFile);
}
});
}
- catch (Exception ignored) {
- }
+ task.addTaskFile(taskFileName + "." + extension, index);
+ }
+ catch (Exception ignored) {
+ }
}
});
}
@Expose private String name;
@Expose private String author;
+ @Expose private String language;
+
private Map<String, Lesson> myLessonsMap = new HashMap<String, Lesson>();
public Map<String, Lesson> getLessonsMap() {
public void setLessonsMap(Map<String, Lesson> lessonsMap) {
myLessonsMap = lessonsMap;
}
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
}
--- /dev/null
+package com.jetbrains.edu.coursecreator.ui;
+
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.fileTypes.FileTypeManager;
+import com.intellij.openapi.fileTypes.impl.FileTypeRenderer;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.ui.DoubleClickListener;
+import com.intellij.ui.ListScrollingUtil;
+import com.intellij.ui.components.JBList;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import java.awt.event.MouseEvent;
+
+public class CreateTaskFileDialog extends DialogWrapper {
+ private JPanel myPanel;
+ private JBList myList;
+ private JTextField myTextField;
+
+ @SuppressWarnings("unchecked")
+ public CreateTaskFileDialog(@Nullable Project project, String generatedFileName) {
+ super(project);
+ FileType[] fileTypes = FileTypeManager.getInstance().getRegisteredFileTypes();
+
+ DefaultListModel model = new DefaultListModel();
+ for (FileType type : fileTypes) {
+ if (!type.isReadOnly() && !type.getDefaultExtension().isEmpty()) {
+ model.addElement(type);
+ }
+ }
+ myList.setModel(model);
+ myTextField.setText(generatedFileName);
+ setTitle("Create New Task File");
+ init();
+ }
+
+ @Nullable
+ @Override
+ protected JComponent createCenterPanel() {
+ myList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ myList.setCellRenderer(new FileTypeRenderer());
+
+ new DoubleClickListener() {
+ @Override
+ protected boolean onDoubleClick(MouseEvent e) {
+ doOKAction();
+ return true;
+ }
+ }.installOn(myList);
+
+ myList.getSelectionModel().addListSelectionListener(
+ new ListSelectionListener() {
+ @Override
+ public void valueChanged(ListSelectionEvent e) {
+ //TODO: do smth to check validness
+ }
+ }
+ );
+
+ ListScrollingUtil.selectItem(myList, FileTypeManager.getInstance().getFileTypeByExtension("py"));
+ return myPanel;
+ }
+
+ @Nullable
+ @Override
+ public JComponent getPreferredFocusedComponent() {
+ return myTextField;
+ }
+
+ public String getFileName() {
+ return myTextField.getText();
+ }
+
+ public FileType getFileType() {
+ return (FileType)myList.getSelectedValue();
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.edu.coursecreator.ui.CreateTaskFileDialog">
+ <grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="3" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+ <margin top="0" left="0" bottom="0" right="0"/>
+ <constraints>
+ <xy x="20" y="20" width="500" height="400"/>
+ </constraints>
+ <properties/>
+ <border type="none"/>
+ <children>
+ <component id="e3f" class="com.intellij.ui.components.JBLabel">
+ <constraints>
+ <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <text value="File Name:"/>
+ </properties>
+ </component>
+ <component id="1f196" class="javax.swing.JTextField" binding="myTextField" default-binding="true">
+ <constraints>
+ <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
+ <preferred-size width="150" height="-1"/>
+ </grid>
+ </constraints>
+ <properties/>
+ </component>
+ <scrollpane id="2c770" class="com.intellij.ui.components.JBScrollPane">
+ <constraints>
+ <grid row="2" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties/>
+ <border type="none"/>
+ <children>
+ <component id="f5bb6" class="com.intellij.ui.components.JBList" binding="myList">
+ <constraints/>
+ <properties>
+ <layoutOrientation value="0"/>
+ </properties>
+ </component>
+ </children>
+ </scrollpane>
+ <grid id="22a58" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+ <margin top="0" left="0" bottom="0" right="0"/>
+ <constraints>
+ <grid row="1" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties/>
+ <border type="none"/>
+ <children>
+ <component id="ff15e" class="com.intellij.ui.components.JBLabel">
+ <constraints>
+ <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <text value="Select File Type:"/>
+ </properties>
+ </component>
+ </children>
+ </grid>
+ </children>
+ </grid>
+</form>