mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Navigation to a target task
This commit is contained in:
+6
-3
@@ -17,8 +17,11 @@ package com.jetbrains.edu.learning.builtInServer;
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.jetbrains.edu.learning.courseFormat.Course;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author meanmail
|
||||
@@ -26,19 +29,19 @@ import org.jetbrains.annotations.NotNull;
|
||||
public class EduProjectCreator {
|
||||
public static final ExtensionPointName<EduProjectCreator> EP_NAME = ExtensionPointName.create("Edu.eduProjectCreator");
|
||||
|
||||
public static boolean createProject(@NotNull Course course) {
|
||||
public static boolean createProject(@NotNull Course course, @Nullable Consumer<Project> callback) {
|
||||
EduProjectCreator[] extensions = Extensions.getExtensions(EP_NAME);
|
||||
|
||||
for (EduProjectCreator projectCreator : extensions) {
|
||||
if (projectCreator.canCreateProject(course)) {
|
||||
return projectCreator.createCourseProject(course);
|
||||
return projectCreator.createCourseProject(course, callback);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean createCourseProject(@NotNull Course course) {
|
||||
public boolean createCourseProject(@NotNull Course course, @Nullable Consumer<Project> callback) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+14
-4
@@ -26,6 +26,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.ide.RestService;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -37,7 +38,8 @@ import static com.jetbrains.edu.learning.builtInServer.Utils.*;
|
||||
public class StepikRestService extends RestService {
|
||||
private static final Logger LOG = Logger.getInstance(StepikRestService.class.getName());
|
||||
private static final String SERVICE_NAME = "edu/stepik";
|
||||
private static final Pattern OPEN_COURSE = Pattern.compile("/" + SERVICE_NAME + "/course/[^/]*-(\\d+)(?:$|\\?|/.*)");
|
||||
public static final String STEP_ID = "step_id";
|
||||
private static final Pattern OPEN_COURSE = Pattern.compile("/" + SERVICE_NAME + "/course/(\\d+)");
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
@@ -59,15 +61,23 @@ public class StepikRestService extends RestService {
|
||||
@Override
|
||||
public String execute(@NotNull QueryStringDecoder urlDecoder, @NotNull FullHttpRequest request, @NotNull ChannelHandlerContext context)
|
||||
throws IOException {
|
||||
LOG.info("Request: " + urlDecoder.path());
|
||||
LOG.info("Request: " + urlDecoder.uri());
|
||||
|
||||
String path = urlDecoder.path();
|
||||
Matcher matcher = OPEN_COURSE.matcher(path);
|
||||
if (matcher.matches()) {
|
||||
int courseId = Integer.parseInt(matcher.group(1));
|
||||
LOG.info("Open course: " + courseId);
|
||||
List<String> stepIds = urlDecoder.parameters().get(STEP_ID);
|
||||
int stepId = 0;
|
||||
if (stepIds != null && !stepIds.isEmpty()) {
|
||||
try {
|
||||
stepId = Integer.parseInt(stepIds.get(0));
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
}
|
||||
LOG.info(String.format("Try to open a course: courseId=%s, stepId=%s", courseId, stepId));
|
||||
|
||||
if (findOpenProjectAndFocus(courseId) || findRecentProjectAndOpen(courseId) || createProjectAndOpen(courseId)) {
|
||||
if (focusOpenProject(courseId, stepId) || openRecentProject(courseId, stepId) || createProject(courseId, stepId)) {
|
||||
RestService.sendOk(request, context);
|
||||
LOG.info("Course opened: " + courseId);
|
||||
return null;
|
||||
|
||||
@@ -22,11 +22,12 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.TransactionGuard;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.wm.IdeFrame;
|
||||
import com.intellij.openapi.wm.WindowManager;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.jetbrains.edu.learning.StudyTaskManager;
|
||||
import com.jetbrains.edu.learning.courseFormat.Course;
|
||||
import com.jetbrains.edu.learning.courseFormat.Lesson;
|
||||
import com.jetbrains.edu.learning.courseFormat.RemoteCourse;
|
||||
import com.jetbrains.edu.learning.courseFormat.tasks.Task;
|
||||
import com.jetbrains.edu.learning.intellij.generation.EduProjectGenerator;
|
||||
import org.jdom.Document;
|
||||
import org.jdom.Element;
|
||||
@@ -35,11 +36,13 @@ import org.jdom.input.SAXBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static com.jetbrains.edu.learning.navigation.StudyNavigator.navigateToTask;
|
||||
|
||||
/**
|
||||
* @author meanmail
|
||||
@@ -47,43 +50,43 @@ import java.util.List;
|
||||
public class Utils {
|
||||
public static final String STUDY_PROJECT_XML_PATH = "/.idea/study_project.xml";
|
||||
|
||||
public static boolean findOpenProjectAndFocus(int courseId) {
|
||||
public static boolean focusOpenProject(int courseId, int stepId) {
|
||||
Project[] openProjects = ProjectManager.getInstance().getOpenProjects();
|
||||
for (Project project : openProjects) {
|
||||
StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
|
||||
if (taskManager != null) {
|
||||
Course course = taskManager.getCourse();
|
||||
RemoteCourse remoteCourse = course instanceof RemoteCourse ? (RemoteCourse)course : null;
|
||||
if (remoteCourse != null && remoteCourse.getId() == courseId) {
|
||||
ApplicationManager.getApplication().invokeLater(() -> requestFocus(project));
|
||||
return true;
|
||||
if (!project.isDefault()) {
|
||||
StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
|
||||
if (taskManager != null) {
|
||||
Course course = taskManager.getCourse();
|
||||
RemoteCourse remoteCourse = course instanceof RemoteCourse ? (RemoteCourse)course : null;
|
||||
if (remoteCourse != null && remoteCourse.getId() == courseId) {
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
requestFocus(project);
|
||||
navigateToStep(project, course, stepId);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean openProject(@NotNull String projectPath) {
|
||||
final boolean[] opened = {false};
|
||||
@Nullable
|
||||
private static Project openProject(@NotNull String projectPath) {
|
||||
final Project[] project = {null};
|
||||
ApplicationManager.getApplication().invokeAndWait(() -> {
|
||||
final Project[] project = new Project[1];
|
||||
TransactionGuard.getInstance().submitTransactionAndWait(() -> {
|
||||
project[0] = ProjectUtil.openProject(projectPath, null, true);
|
||||
opened[0] = project[0] != null;
|
||||
});
|
||||
TransactionGuard.getInstance().submitTransactionAndWait(() ->
|
||||
project[0] = ProjectUtil.openProject(projectPath, null, true));
|
||||
requestFocus(project[0]);
|
||||
});
|
||||
return opened[0];
|
||||
return project[0];
|
||||
}
|
||||
|
||||
private static void requestFocus(@NotNull Project project) {
|
||||
IdeFrame frame = WindowManager.getInstance().getIdeFrame(project);
|
||||
if (frame instanceof Window) {
|
||||
((Window)frame).toFront();
|
||||
}
|
||||
ProjectUtil.focusProjectWindow(project, false);
|
||||
}
|
||||
|
||||
public static boolean findRecentProjectAndOpen(int targetCourseId) {
|
||||
public static boolean openRecentProject(int targetCourseId, int stepId) {
|
||||
RecentProjectsManagerBase recentProjectsManager;
|
||||
recentProjectsManager = (RecentProjectsManagerBase)RecentProjectsManager.getInstance();
|
||||
|
||||
@@ -99,8 +102,8 @@ public class Utils {
|
||||
|
||||
List<String> recentPaths = state.recentPaths;
|
||||
|
||||
Project project = ProjectManager.getInstance().getDefaultProject();
|
||||
StudyTaskManager taskManager = new StudyTaskManager(project);
|
||||
Project defaultProject = ProjectManager.getInstance().getDefaultProject();
|
||||
StudyTaskManager taskManager = new StudyTaskManager(defaultProject);
|
||||
SAXBuilder parser = new SAXBuilder();
|
||||
|
||||
for (String projectPath : recentPaths) {
|
||||
@@ -110,8 +113,17 @@ public class Utils {
|
||||
}
|
||||
int courseId = getCourseId(taskManager, component);
|
||||
|
||||
if (courseId == targetCourseId && openProject(projectPath)) {
|
||||
return true;
|
||||
if (courseId == targetCourseId) {
|
||||
Project project = openProject(projectPath);
|
||||
if (project != null) {
|
||||
Course course = taskManager.getCourse();
|
||||
if (course != null) {
|
||||
ApplicationManager.getApplication().invokeLater(() ->
|
||||
navigateToStep(project, course, stepId)
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -146,7 +158,7 @@ public class Utils {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static boolean createProjectAndOpen(int courseId) {
|
||||
public static boolean createProject(int courseId, int stepId) {
|
||||
EduProjectGenerator generator = new EduProjectGenerator();
|
||||
Project defaultProject = ProjectManager.getInstance().getDefaultProject();
|
||||
String title = "Getting Available Courses";
|
||||
@@ -157,9 +169,41 @@ public class Utils {
|
||||
});
|
||||
for (Course course : availableCourses) {
|
||||
if (course instanceof RemoteCourse && ((RemoteCourse)course).getId() == courseId) {
|
||||
return EduProjectCreator.createProject(course);
|
||||
Consumer<Project> callback = project ->
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
|
||||
Course targetCourse = taskManager.getCourse();
|
||||
if (targetCourse != null) {
|
||||
navigateToStep(project, targetCourse, stepId);
|
||||
}
|
||||
});
|
||||
return EduProjectCreator.createProject(course, callback);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void navigateToStep(@NotNull Project project, @NotNull Course course, int stepId) {
|
||||
if (stepId == 0 || course.isAdaptive()) {
|
||||
return;
|
||||
}
|
||||
Task task = getTask(course, stepId);
|
||||
if (task != null) {
|
||||
navigateToTask(project, task);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Task getTask(@NotNull Course course, int stepId) {
|
||||
List<Lesson> lessons = course.getLessons();
|
||||
for (Lesson lesson : lessons) {
|
||||
Optional<Task> optionalTask = lesson.getTaskList().stream()
|
||||
.filter(task -> task.getStepId() == stepId)
|
||||
.findFirst();
|
||||
if (optionalTask.isPresent()) {
|
||||
return optionalTask.get();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-1
@@ -1,6 +1,7 @@
|
||||
package com.jetbrains.edu.learning.navigation;
|
||||
|
||||
import com.intellij.ide.projectView.ProjectView;
|
||||
import com.intellij.ide.projectView.impl.AbstractProjectViewPane;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
@@ -190,7 +191,11 @@ public class StudyNavigator {
|
||||
}
|
||||
|
||||
private static void updateProjectView(@NotNull Project project, @NotNull VirtualFile fileToActivate) {
|
||||
JTree tree = ProjectView.getInstance(project).getCurrentProjectViewPane().getTree();
|
||||
AbstractProjectViewPane viewPane = ProjectView.getInstance(project).getCurrentProjectViewPane();
|
||||
if (viewPane == null) {
|
||||
return;
|
||||
}
|
||||
JTree tree = viewPane.getTree();
|
||||
ProjectView.getInstance(project).selectCB(fileToActivate, fileToActivate, false).doWhenDone(() -> {
|
||||
List<TreePath> paths = TreeUtil.collectExpandedPaths(tree);
|
||||
List<TreePath> toCollapse = new ArrayList<>();
|
||||
|
||||
+13
-2
@@ -23,6 +23,7 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiDirectory;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.util.BooleanFunction;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.jetbrains.edu.learning.core.EduNames;
|
||||
import com.jetbrains.edu.learning.courseFormat.Course;
|
||||
import com.jetbrains.edu.learning.courseFormat.RemoteCourse;
|
||||
@@ -56,15 +57,17 @@ public class PyStudyDirectoryProjectGenerator extends PythonProjectGenerator<PyN
|
||||
private static final Logger LOG = Logger.getInstance(PyStudyDirectoryProjectGenerator.class.getName());
|
||||
private final StudyProjectGenerator myGenerator;
|
||||
private static final String NO_PYTHON_INTERPRETER = "<html><u>Add</u> python interpreter.</html>";
|
||||
private final Consumer<Project> myCallback;
|
||||
public ValidationResult myValidationResult = new ValidationResult("selected course is not valid");
|
||||
private StudyNewProjectPanel mySettingsPanel;
|
||||
private final StudyNewProjectPanel mySettingsPanel;
|
||||
|
||||
@SuppressWarnings("unused") // used on startup
|
||||
public PyStudyDirectoryProjectGenerator() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
public PyStudyDirectoryProjectGenerator(boolean isLocal) {
|
||||
public PyStudyDirectoryProjectGenerator(boolean isLocal, @Nullable Consumer<Project> callback) {
|
||||
myCallback = callback;
|
||||
myGenerator = new StudyProjectGenerator();
|
||||
myGenerator.addSettingsStateListener(new StudyProjectGenerator.SettingsListener() {
|
||||
@Override
|
||||
@@ -111,6 +114,10 @@ public class PyStudyDirectoryProjectGenerator extends PythonProjectGenerator<PyN
|
||||
});
|
||||
}
|
||||
|
||||
public PyStudyDirectoryProjectGenerator(boolean isLocal) {
|
||||
this(isLocal, null);
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
@@ -142,6 +149,10 @@ public class PyStudyDirectoryProjectGenerator extends PythonProjectGenerator<PyN
|
||||
catch (Exception exception) {
|
||||
LOG.error("Can't copy test_helper.py " + exception.getMessage());
|
||||
}
|
||||
|
||||
if (myCallback != null) {
|
||||
myCallback.consume(project);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+7
-4
@@ -15,12 +15,15 @@
|
||||
*/
|
||||
package com.jetbrains.edu.learning.builtInServer;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.platform.DirectoryProjectGenerator;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.jetbrains.edu.learning.PyStudyDirectoryProjectGenerator;
|
||||
import com.jetbrains.edu.learning.courseFormat.Course;
|
||||
import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator;
|
||||
import com.jetbrains.python.newProject.steps.PyCharmNewProjectStep;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -28,17 +31,17 @@ import java.util.ArrayList;
|
||||
* @author meanmail
|
||||
*/
|
||||
public class BuiltInServerNewProjectStep extends PyCharmNewProjectStep {
|
||||
public BuiltInServerNewProjectStep(@NotNull Course course) {
|
||||
super(new BuiltInServerNewProjectStep.MyCustomization(course));
|
||||
public BuiltInServerNewProjectStep(@NotNull Course course, @Nullable Consumer<Project> callback) {
|
||||
super(new BuiltInServerNewProjectStep.MyCustomization(course, callback));
|
||||
}
|
||||
|
||||
protected static class MyCustomization extends PyCharmNewProjectStep.Customization {
|
||||
private final Course myCourse;
|
||||
private final PyStudyDirectoryProjectGenerator myGenerator;
|
||||
|
||||
public MyCustomization(@NotNull Course course) {
|
||||
public MyCustomization(@NotNull Course course, @Nullable Consumer<Project> callback) {
|
||||
myCourse = course;
|
||||
myGenerator = new PyStudyDirectoryProjectGenerator(true);
|
||||
myGenerator = new PyStudyDirectoryProjectGenerator(true, callback);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+5
-2
@@ -18,9 +18,12 @@ package com.jetbrains.edu.learning.builtInServer;
|
||||
import com.intellij.ide.util.projectWizard.AbstractNewProjectDialog;
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.jetbrains.edu.learning.courseFormat.Course;
|
||||
import com.jetbrains.python.PythonLanguage;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author meanmail
|
||||
@@ -32,12 +35,12 @@ public class EduPythonProjectCreator extends EduProjectCreator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean createCourseProject(@NotNull Course course) {
|
||||
public boolean createCourseProject(@NotNull Course course, @Nullable Consumer<Project> callback) {
|
||||
ApplicationManager.getApplication().invokeAndWait(() -> {
|
||||
AbstractNewProjectDialog dlg = new AbstractNewProjectDialog() {
|
||||
@Override
|
||||
protected DefaultActionGroup createRootStep() {
|
||||
return new BuiltInServerNewProjectStep(course);
|
||||
return new BuiltInServerNewProjectStep(course, callback);
|
||||
}
|
||||
};
|
||||
dlg.show();
|
||||
|
||||
Reference in New Issue
Block a user