Merge branch 'kiryushkina/edu_fixes'

This commit is contained in:
Ekaterina Tuzova
2017-05-19 18:11:06 +03:00
16 changed files with 148 additions and 144 deletions
@@ -83,9 +83,8 @@
<action id="StudySwitchPanel" class="com.jetbrains.edu.learning.actions.StudySwitchTaskPanelAction"
text="Switch Task Description Panel">
</action>
<action id="Edu.OpenTaskInStepik" class="com.jetbrains.edu.learning.actions.StudyOpenTaskInStepikAction"
text="Open this task in Stepik">
</action>
<action id="Edu.UpdateRecommendation" class="com.jetbrains.edu.learning.actions.StudyUpdateRecommendationAction"/>
<!--course creator-->
<action id="CreateLesson" class="com.jetbrains.edu.coursecreator.actions.CCCreateLesson">
@@ -21,18 +21,37 @@
<script src="${language_script}"></script>
<!--suppress CssInvalidPropertyValue -->
<style media="screen" type="text/css">
body {
html, body {
height:100%;
overflow:hidden;
font-size: ${font_size}pt !important;
}
.wrapper {
overflow-y:scroll;
height: 96%;
}
/*used to place task on Stepik link*/
/*noinspection CssUnusedSymbol*/
.footer {
position:fixed;
line-height: 3.5em;
bottom: 0;
height: 4%;
width: 95%;
text-align: right;
}
</style>
</head>
<body>
<div class=wrapper>
${code}
</div>
<script>
var nodeList = document.body.getElementsByTagName("code");
nodes = Array.prototype.slice.call(nodeList, 0);
nodes.forEach(function (node) {
var text = node.innerHTML
node.innerHTML = text.replace(/<br\s*>/g, '\n')
@@ -331,9 +331,9 @@ public class CCStepicConnector {
private static void showStepicNotification(@NotNull Project project,
@NotNull NotificationType notificationType, @NotNull String failedActionName) {
String text = "Authorize on Stepik to " + failedActionName;
String text = "Log in to Stepik to " + failedActionName;
Notification notification = new Notification("Stepik", "Failed to " + failedActionName, text, notificationType);
notification.addAction(new AnAction("Authorize") {
notification.addAction(new AnAction("Log in") {
@Override
public void actionPerformed(AnActionEvent e) {
@@ -120,7 +120,7 @@ public interface EduPluginConfigurator {
StudyNextTaskAction.ACTION_ID,
StudyRefreshTaskFileAction.ACTION_ID,
StudyShowHintAction.ACTION_ID,
StudyOpenTaskInStepikAction.ACTION_ID,
StudyUpdateRecommendationAction.ACTION_ID
};
ActionManager actionManager = ActionManager.getInstance();
Arrays.stream(ids)
@@ -95,6 +95,7 @@ public class StudyProjectComponent implements ProjectComponent {
instance.setHideToolStripes(false);
instance.fireUISettingsChanged();
registerShortcuts();
addStepicWidget();
EduUsagesCollector.projectTypeOpened(course.isAdaptive() ? EduNames.ADAPTIVE : EduNames.STUDY);
}
})));
@@ -110,6 +111,10 @@ public class StudyProjectComponent implements ProjectComponent {
}
});
selectStep();
}
private void addStepicWidget() {
StudyStepicUserWidget widget = StudyUtils.getStepicWidget();
if (widget == null) {
StatusBar statusBar = WindowManager.getInstance().getStatusBar(myProject);
@@ -118,8 +123,6 @@ public class StudyProjectComponent implements ProjectComponent {
else {
widget.update();
}
selectStep();
}
private void selectStep() {
@@ -67,6 +67,7 @@ import com.jetbrains.edu.learning.courseFormat.tasks.Task;
import com.jetbrains.edu.learning.courseFormat.tasks.TaskWithSubtasks;
import com.jetbrains.edu.learning.courseFormat.tasks.TheoryTask;
import com.jetbrains.edu.learning.editor.StudyEditor;
import com.jetbrains.edu.learning.stepic.EduStepikUtils;
import com.jetbrains.edu.learning.stepic.OAuthDialog;
import com.jetbrains.edu.learning.stepic.StepicUser;
import com.jetbrains.edu.learning.ui.StudyStepicUserWidget;
@@ -430,14 +431,23 @@ public class StudyUtils {
}
private static String wrapAdaptiveCourseText(Task task, @NotNull String text) {
String finalText = text;
if (task instanceof TheoryTask) {
return text + "\n\n<b>Note</b>: This theory task aims to help you solve difficult tasks. " +
finalText += "\n\n<b>Note</b>: This theory task aims to help you solve difficult tasks. " +
"Please, read it and press \"Check\" to go further.";
}
else if (!(task instanceof ChoiceTask)) {
return text + "\n\n<b>Note</b>: Use standard input to obtain input for the task.";
finalText += "\n\n<b>Note</b>: Use standard input to obtain input for the task.";
}
return text;
finalText += getFooterWithLink(task);
return finalText;
}
@NotNull
private static String getFooterWithLink(Task task) {
return
"<div class=\"footer\">" + "<a href=" + EduStepikUtils.getAdaptiveLink(task) + ">Open on Stepik</a>" + "</div>";
}
@NotNull
@@ -1,90 +0,0 @@
/*
* Copyright 2000-2017 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.learning.actions;
import com.intellij.ide.BrowserUtil;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.KeyboardShortcut;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.project.Project;
import com.jetbrains.edu.learning.StudyUtils;
import com.jetbrains.edu.learning.courseFormat.tasks.Task;
import com.jetbrains.edu.learning.stepic.EduStepikUtils;
import icons.EducationalCoreIcons;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
public class StudyOpenTaskInStepikAction extends StudyActionWithShortcut {
public static final String SHORTCUT = "ctrl alt pressed HOME";
public static final String ACTION_ID = "Edu.OpenTaskInStepik";
private static final String TEXT = "Open this task in Stepik";
public StudyOpenTaskInStepikAction() {
super(getTextWithShortcuts(), TEXT, EducationalCoreIcons.Stepik);
}
@NotNull
private static String getTextWithShortcuts() {
return TEXT + "(" + KeymapUtil.getShortcutText(new KeyboardShortcut(KeyStroke.getKeyStroke(SHORTCUT), null)) + ")";
}
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
Project project = e.getProject();
if (project == null) {
return;
}
Task currentTask = StudyUtils.getCurrentTask(project);
String link = EduStepikUtils.getLink(currentTask);
if (link != null) {
BrowserUtil.browse(link);
}
}
@Override
public void update(AnActionEvent e) {
final Presentation presentation = e.getPresentation();
StudyUtils.updateAction(e);
Project project = e.getProject();
if (project == null) {
presentation.setVisible(false);
return;
}
Task currentTask = StudyUtils.getCurrentTask(project);
String link = EduStepikUtils.getLink(currentTask);
boolean visible = link != null;
presentation.setVisible(visible);
presentation.setEnabled(visible);
if (visible) {
presentation.setText(getTextWithShortcuts() + '\n' + link);
}
}
@NotNull
@Override
public String getActionId() {
return ACTION_ID;
}
@Override
public String[] getShortcuts() {
return new String[]{SHORTCUT};
}
}
@@ -0,0 +1,77 @@
package com.jetbrains.edu.learning.actions;
import com.intellij.ide.projectView.ProjectView;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.jetbrains.edu.learning.StudyTaskManager;
import com.jetbrains.edu.learning.StudyUtils;
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.navigation.StudyNavigator;
import com.jetbrains.edu.learning.stepic.EduAdaptiveStepicConnector;
import icons.EducationalCoreIcons;
public class StudyUpdateRecommendationAction extends DumbAwareAction {
public static final String ACTION_ID = "Edu.UpdateRecommendation";
public StudyUpdateRecommendationAction() {
super("Update course", "Update course", EducationalCoreIcons.Stepik);
}
@Override
public void actionPerformed(AnActionEvent e) {
Project project = e.getProject();
assert project != null;
Course course = StudyTaskManager.getInstance(project).getCourse();
assert course != null;
Lesson adaptiveLesson = course.getLessons().get(0);
assert adaptiveLesson != null;
int taskNumber = adaptiveLesson.getTaskList().size();
Task lastRecommendationInCourse = adaptiveLesson.getTaskList().get(taskNumber - 1);
Task lastRecommendationOnStepik = ProgressManager.getInstance().runProcessWithProgressSynchronously(
() -> {
ProgressManager.getInstance().getProgressIndicator().setIndeterminate(true);
return StudyUtils.execCancelable(() -> EduAdaptiveStepicConnector.getNextRecommendation(project, (RemoteCourse)course));
},
"Updating Course", true, project);
if (lastRecommendationOnStepik != null && lastRecommendationOnStepik.getStepId() != lastRecommendationInCourse.getStepId()) {
lastRecommendationOnStepik.initTask(adaptiveLesson, false);
EduAdaptiveStepicConnector.replaceCurrentTask(project, lastRecommendationOnStepik, adaptiveLesson);
ApplicationManager.getApplication().invokeLater(() -> {
VirtualFileManager.getInstance().refreshWithoutFileWatcher(false);
ProjectView.getInstance(project).refresh();
StudyNavigator.navigateToTask(project, lastRecommendationOnStepik);
});
}
}
@Override
public void update(AnActionEvent e) {
Presentation presentation = e.getPresentation();
Project project = e.getProject();
if (project == null) {
presentation.setEnabledAndVisible(false);
return;
}
Course course = StudyTaskManager.getInstance(project).getCourse();
if (course == null || !course.isAdaptive()) {
presentation.setEnabledAndVisible(false);
return;
}
presentation.setEnabledAndVisible(true);
}
}
@@ -122,14 +122,14 @@ public class EduStepikRestService extends RestService {
if (stepicUser != null) {
StudySettings.getInstance().setUser(stepicUser);
sendHtmlResponse(request, context, "/oauthResponsePages/okPage.html");
showStepicNotification(NotificationType.INFORMATION, "Authorized as " + stepicUser.getFirstName() + " " + stepicUser.getLastName());
showStepicNotification(NotificationType.INFORMATION, "Logged in as " + stepicUser.getFirstName() + " " + stepicUser.getLastName());
focusOnApplicationWindow();
return null;
}
}
sendHtmlResponse(request, context, "/oauthResponsePages/errorPage.html");
showStepicNotification(NotificationType.ERROR, "Failed to authorize");
showStepicNotification(NotificationType.ERROR, "Failed to log in");
return "Couldn't find code parameter for Stepik OAuth";
}
@@ -28,6 +28,7 @@ import com.intellij.util.ui.UIUtil;
import com.jetbrains.edu.learning.EduPluginConfigurator;
import com.jetbrains.edu.learning.StudySettings;
import com.jetbrains.edu.learning.StudyUtils;
import com.jetbrains.edu.learning.core.EduNames;
import com.jetbrains.edu.learning.courseFormat.Course;
import com.jetbrains.edu.learning.courseFormat.RemoteCourse;
import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator;
@@ -440,7 +441,7 @@ public class EduCoursesPanel extends JPanel {
List<String> tags = new ArrayList<>();
tags.add(course.getLanguageById().getDisplayName());
if (course.isAdaptive()) {
tags.add("Adaptive");
tags.add(EduNames.ADAPTIVE);
}
return tags;
}
@@ -300,7 +300,7 @@ public class EduAdaptiveStepicConnector {
if (user == null) {
LOG.warn("Can't get next recommendation: user is null");
ApplicationManager.getApplication().invokeLater(() -> StudyUtils.showErrorPopupOnToolbar(project,
"Can't get next recommendation: you're not authorized"));
"Can't get next recommendation: you're not logged in"));
return;
}
@@ -363,7 +363,7 @@ public class EduAdaptiveStepicConnector {
}
}
private static void replaceCurrentTask(@NotNull Project project, @NotNull Task task, @NotNull Lesson lesson) {
public static void replaceCurrentTask(@NotNull Project project, @NotNull Task task, @NotNull Lesson lesson) {
Course course = StudyTaskManager.getInstance(project).getCourse();
assert course != null;
@@ -260,7 +260,7 @@ public class EduStepicConnector {
}
else {
final Lesson lesson = new Lesson();
lesson.setName("Adaptive");
lesson.setName(EduNames.ADAPTIVE);
remoteCourse.addLesson(lesson);
//TODO: more specific name?
final Task recommendation = EduAdaptiveStepicConnector.getNextRecommendation(project, remoteCourse);
@@ -22,7 +22,7 @@ import org.jetbrains.annotations.Nullable;
public class EduStepikUtils {
@Nullable
public static String getLink(@Nullable Task task) {
public static String getLink(@Nullable Task task, int stepNumber) {
if (task == null) {
return null;
}
@@ -31,6 +31,12 @@ public class EduStepikUtils {
return null;
}
return String.format("%s/lesson/%d/step/%d", EduStepicNames.STEPIC_URL, lesson.getId(), task.getPosition());
return String.format("%s/lesson/%d/step/%d", EduStepicNames.STEPIC_URL, lesson.getId(), stepNumber);
}
@Nullable
public static String getAdaptiveLink(@Nullable Task task) {
String link = getLink(task, 1);
return link == null ? null : link + "?adaptive=true";
}
}
@@ -15,23 +15,19 @@
*/
package com.jetbrains.edu.learning.stepic;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.DefaultProjectFactory;
import com.intellij.ui.HoverHyperlinkLabel;
import com.intellij.ui.HyperlinkAdapter;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.components.JBLabel;
import com.jetbrains.edu.learning.StudySettings;
import com.jetbrains.edu.learning.StudyUtils;
import com.jetbrains.edu.learning.settings.StudyOptionsProvider;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
public class StepicStudyOptions implements StudyOptionsProvider {
private JPanel myPane;
@@ -61,32 +57,16 @@ public class StepicStudyOptions implements StudyOptionsProvider {
@Override
protected void hyperlinkActivated(HyperlinkEvent e) {
StudySettings studySettings = StudySettings.getInstance();
StepicUser oldUser = studySettings.getUser();
EduStepicConnector.doAuthorize(() -> showDialog());
ProgressManager.getInstance()
.runProcessWithProgressSynchronously(() -> {
ProgressManager.getInstance().getProgressIndicator().setIndeterminate(true);
StudyUtils.execCancelable(waitForUserToBeSet(studySettings, oldUser));
}, "Authorizing",
true,
DefaultProjectFactory.getInstance().getDefaultProject());
}
@NotNull
private Callable<Object> waitForUserToBeSet(StudySettings studySettings, StepicUser oldUser) {
return () -> {
StepicUser newUser = studySettings.getUser();
while (newUser == null || newUser.equals(oldUser)) {
TimeUnit.MILLISECONDS.sleep(500);
newUser = studySettings.getUser();
ApplicationManager.getApplication().getMessageBus().connect().subscribe(StudySettings.SETTINGS_CHANGED, () -> {
StepicUser user = StudySettings.getInstance().getUser();
if (user != null && !user.equals(myStepicUser)) {
StudySettings.getInstance().setUser(myStepicUser);
myStepicUser = user;
updateLoginLabels(myStepicUser);
}
StudySettings.getInstance().setUser(myStepicUser);
myStepicUser = newUser;
updateLoginLabels(myStepicUser);
return null;
};
});
EduStepicConnector.doAuthorize(() -> showDialog());
}
};
}
@@ -122,7 +102,7 @@ public class StepicStudyOptions implements StudyOptionsProvider {
if (stepicUser == null) {
myUsernameLabel.setText("You're not logged in");
myHoverHyperlinkLabel.setText("Authorize on Stepik");
myHoverHyperlinkLabel.setText("Log in to Stepik");
myListener = createAuthorizeListener();
myHoverHyperlinkLabel.addHyperlinkListener(myListener);
@@ -92,7 +92,7 @@ public class StudyStepicUserWidget implements IconLikeCustomStatusBarWidget {
setLayout(layout);
if (user == null) {
createUserPanel("You're not logged in", "Authorize on Stepik", createAuthorizeUserListener());
createUserPanel("You're not logged in", "Log in to Stepik", createAuthorizeUserListener());
}
else {
String firstName = user.getFirstName();
@@ -23,6 +23,5 @@ public class PyStudyInstructionPainter extends EditorEmptyTextPainter {
appendAction(painter, "Reset current task file", getActionShortcutText(StudyRefreshTaskFileAction.ACTION_ID));
appendAction(painter, "Check task", getActionShortcutText(StudyCheckAction.ACTION_ID));
appendAction(painter, "Get hint for the answer placeholder", getActionShortcutText(StudyShowHintAction.ACTION_ID));
appendAction(painter, "Open this task in Stepik", getActionShortcutText(StudyOpenTaskInStepikAction.ACTION_ID));
}
}