From dc0870e4a21c0af03835b7dec1c2e45ab5e67b69 Mon Sep 17 00:00:00 2001 From: meanmail Date: Sat, 15 Apr 2017 21:36:39 +0700 Subject: [PATCH 01/22] Added shortcut for getting a current user [API client] --- .../java/org/stepik/api/actions/StepikStepiksAction.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/stepik-java-api/src/main/java/org/stepik/api/actions/StepikStepiksAction.java b/stepik-java-api/src/main/java/org/stepik/api/actions/StepikStepiksAction.java index 9f6bf630..112bdb0a 100644 --- a/stepik-java-api/src/main/java/org/stepik/api/actions/StepikStepiksAction.java +++ b/stepik-java-api/src/main/java/org/stepik/api/actions/StepikStepiksAction.java @@ -2,6 +2,7 @@ import org.jetbrains.annotations.NotNull; import org.stepik.api.client.StepikApiClient; +import org.stepik.api.objects.users.User; import org.stepik.api.queries.stepiks.StepikStepiksGetQuery; /** @@ -16,4 +17,10 @@ public StepikStepiksAction(@NotNull StepikApiClient stepikApiClient) { public StepikStepiksGetQuery get() { return new StepikStepiksGetQuery(this); } + + public User getCurrentUser() { + return this.get() + .id(1) + .execute().getUser(); + } } From f0f2c86b03ca9e818a1a9239b5cd9a58f84ee5cb Mon Sep 17 00:00:00 2001 From: meanmail Date: Sat, 15 Apr 2017 21:39:11 +0700 Subject: [PATCH 02/22] Added a login button in the Step Description if user is not authenticated --- .../stepHelpers/FreeAnswerQuizHelper.java | 11 +++- .../courseFormat/stepHelpers/QuizHelper.java | 23 ++++++-- .../main/resources/templates/quiz/base.ftl | 5 +- .../resources/templates/quiz/base_step.ftl | 20 +++---- .../main/resources/templates/quiz/choice.ftl | 23 ++++---- .../main/resources/templates/quiz/dataset.ftl | 43 ++++++++------- .../resources/templates/quiz/fill-blanks.ftl | 53 ++++++++++--------- .../resources/templates/quiz/free-answer.ftl | 16 +++--- .../resources/templates/quiz/matching.ftl | 30 ++++++----- .../main/resources/templates/quiz/math.ftl | 3 +- .../main/resources/templates/quiz/number.ftl | 3 +- .../main/resources/templates/quiz/sorting.ftl | 24 +++++---- .../main/resources/templates/quiz/string.ftl | 2 +- .../main/resources/templates/quiz/table.ftl | 50 ++++++++--------- 14 files changed, 171 insertions(+), 135 deletions(-) diff --git a/stepik-union/src/main/java/org/stepik/core/courseFormat/stepHelpers/FreeAnswerQuizHelper.java b/stepik-union/src/main/java/org/stepik/core/courseFormat/stepHelpers/FreeAnswerQuizHelper.java index e3a76399..36d1d16c 100644 --- a/stepik-union/src/main/java/org/stepik/core/courseFormat/stepHelpers/FreeAnswerQuizHelper.java +++ b/stepik-union/src/main/java/org/stepik/core/courseFormat/stepHelpers/FreeAnswerQuizHelper.java @@ -8,7 +8,9 @@ import org.stepik.api.objects.instructions.Instructions; import org.stepik.api.objects.steps.Step; import org.stepik.core.courseFormat.StepNode; -import org.stepik.core.stepik.StepikConnectorLogin; + +import static org.stepik.core.stepik.StepikConnectorLogin.authAndGetStepikApiClient; +import static org.stepik.core.stepik.StepikConnectorLogin.isAuthenticated; /** * @author meanmail @@ -59,7 +61,10 @@ private boolean isFrozen() { } try { - StepikApiClient stepikClient = StepikConnectorLogin.authAndGetStepikApiClient(); + StepikApiClient stepikClient = authAndGetStepikApiClient(); + if (!isAuthenticated()) { + return true; + } Instructions instructions = stepikClient.instructions() .get() .id(instructionId) @@ -73,11 +78,13 @@ private boolean isFrozen() { return true; } + @SuppressWarnings("SameReturnValue") private boolean needWait() { // TODO not implemented return false; } + @SuppressWarnings("SameReturnValue") private boolean complete() { // TODO not implemented return false; diff --git a/stepik-union/src/main/java/org/stepik/core/courseFormat/stepHelpers/QuizHelper.java b/stepik-union/src/main/java/org/stepik/core/courseFormat/stepHelpers/QuizHelper.java index 45c1a088..7ba903ee 100644 --- a/stepik-union/src/main/java/org/stepik/core/courseFormat/stepHelpers/QuizHelper.java +++ b/stepik-union/src/main/java/org/stepik/core/courseFormat/stepHelpers/QuizHelper.java @@ -19,10 +19,12 @@ import org.stepik.api.urls.Urls; import org.stepik.core.courseFormat.StepNode; import org.stepik.core.courseFormat.StudyStatus; -import org.stepik.core.stepik.StepikConnectorLogin; import java.util.List; +import static org.stepik.core.stepik.StepikConnectorLogin.authAndGetStepikApiClient; +import static org.stepik.core.stepik.StepikConnectorLogin.getCurrentUser; + /** * @author meanmail */ @@ -131,6 +133,7 @@ public String getReplyUrl() { return submission != null ? submission.getReplyUrl() : ""; } + @SuppressWarnings("SameReturnValue") public String getBaseUrl() { return Urls.STEPIK_URL; } @@ -144,8 +147,13 @@ void initStepOptions() { status = ""; try { - StepikApiClient stepikApiClient = StepikConnectorLogin.authAndGetStepikApiClient(); - User user = StepikConnectorLogin.getCurrentUser(); + StepikApiClient stepikApiClient = authAndGetStepikApiClient(); + User user = getCurrentUser(); + if (user.isGuest()) { + status = "need_login"; + return; + } + long userId = user.getId(); if (!loadAttempt(stepikApiClient, userId)) { @@ -189,12 +197,17 @@ void onInitFailed() { public int getSubmissionsCount() { if (submissionsCount == -1) { try { - StepikApiClient stepikApiClient = StepikConnectorLogin.authAndGetStepikApiClient(); - User user = StepikConnectorLogin.getCurrentUser(); + StepikApiClient stepikApiClient = authAndGetStepikApiClient(); + User user = getCurrentUser(); + if (user.isGuest()) { + status = "need_login"; + return 0; + } long userId = user.getId(); submissionsCount = 0; Submissions submissions; int page = 1; + do { submissions = stepikApiClient.submissions() .get() diff --git a/stepik-union/src/main/resources/templates/quiz/base.ftl b/stepik-union/src/main/resources/templates/quiz/base.ftl index 09320bd7..029f1fed 100644 --- a/stepik-union/src/main/resources/templates/quiz/base.ftl +++ b/stepik-union/src/main/resources/templates/quiz/base.ftl @@ -55,6 +55,8 @@ submitCaption = "Click to solve"; } else if (status === "active" || status === "active_wrong") { submitCaption = "Submit"; + } else if (status === "need_login") { + submitCaption = "Login"; } else if (status !== "evaluation") { submitCaption = "Click to solve again"; } else { @@ -78,10 +80,9 @@ - <#if isHasSubmissionsRestrictions> + <#if isHasSubmissionsRestrictions && status != "need_login">

${maxSubmissionsCount - submissionsCount} attempts left

- \ No newline at end of file diff --git a/stepik-union/src/main/resources/templates/quiz/base_step.ftl b/stepik-union/src/main/resources/templates/quiz/base_step.ftl index 975c5560..0bb3b493 100644 --- a/stepik-union/src/main/resources/templates/quiz/base_step.ftl +++ b/stepik-union/src/main/resources/templates/quiz/base_step.ftl @@ -1,9 +1,11 @@ +<#-- @ftlvariable name="status" type="java.lang.String" --> <#-- @ftlvariable name="stepNode" type="org.stepik.core.courseFormat.stepHelpers.StepHelper" --> <#-- @ftlvariable name="text" type="java.lang.String" --> + <#include "base_step.ftl"> <@step_content> @@ -7,28 +21,34 @@ <#macro quiz_content>
<#assign status = stepNode.getStatus()/> - <#assign isHasSubmissionsRestrictions = stepNode.isHasSubmissionsRestrictions() /> - <#assign maxSubmissionsCount = stepNode.getMaxSubmissionsCount() /> - <#assign submissionsCount = stepNode.getSubmissionsCount() /> + <#assign action = stepNode.getAction()/> + <#assign needLogin = action == "need_login"> + <#assign isHasSubmissionsRestrictions = !needLogin && stepNode.isHasSubmissionsRestrictions() /> + <#if isHasSubmissionsRestrictions> + <#assign maxSubmissionsCount = stepNode.getMaxSubmissionsCount() /> + <#assign submissionsCount = stepNode.getSubmissionsCount() /> + <#else> + <#assign maxSubmissionsCount = 0 /> + <#assign submissionsCount = 0 /> + + <#assign locked = isHasSubmissionsRestrictions && (submissionsCount >= maxSubmissionsCount) />
- <#if status != "active" && status != "active_wrong"> + <#if action != "submit"> <#assign disabled = "disabled" /> - <#if status == "wrong" || status == "active_wrong"> -

Wrong

+ <#if status != "unchecked"> +

${status}

${stepNode.getHint()}
- <#elseif status == "correct"> -

Correct

<#nested/> - + @@ -36,51 +56,44 @@ <#if !locked> - <#if status == "active_wrong"> + <#if status != "unchecked" && action == "submit">
- <#if isHasSubmissionsRestrictions && status != "need_login"> + <#if isHasSubmissionsRestrictions>

${maxSubmissionsCount - submissionsCount} attempts left

diff --git a/stepik-union/src/main/resources/templates/quiz/base_sorting.ftl b/stepik-union/src/main/resources/templates/quiz/base_sorting.ftl index 611cf334..020603ca 100644 --- a/stepik-union/src/main/resources/templates/quiz/base_sorting.ftl +++ b/stepik-union/src/main/resources/templates/quiz/base_sorting.ftl @@ -1,4 +1,3 @@ -<#-- @ftlvariable name="status" type="java.lang.String" --> <#-- @ftlvariable name="backgroundColor" type="java.lang.String" --> <#-- @ftlvariable name="darcula" type="java.lang.Boolean" --> <#-- @ftlvariable name="stepNode" type="org.stepik.core.courseFormat.stepHelpers.MatchingQuizHelper" --> diff --git a/stepik-union/src/main/resources/templates/quiz/base_step.ftl b/stepik-union/src/main/resources/templates/quiz/base_step.ftl index 0bb3b493..45cdf123 100644 --- a/stepik-union/src/main/resources/templates/quiz/base_step.ftl +++ b/stepik-union/src/main/resources/templates/quiz/base_step.ftl @@ -1,4 +1,4 @@ -<#-- @ftlvariable name="status" type="java.lang.String" --> +<#-- @ftlvariable name="action" type="java.lang.String" --> <#-- @ftlvariable name="stepNode" type="org.stepik.core.courseFormat.stepHelpers.StepHelper" --> <#-- @ftlvariable name="text" type="java.lang.String" --> <#macro step_content> @@ -29,4 +43,33 @@ ${stepNode.getContent()}
<#nested/> +
+ + + + + + + + + + + + + + + +
+
+ + + \ No newline at end of file From 0fe8410b434061e54cc0a053756618187106b015 Mon Sep 17 00:00:00 2001 From: meanmail Date: Sun, 16 Apr 2017 02:18:31 +0700 Subject: [PATCH 06/22] Minor: delete excess html-tag [Step Description] --- .../src/main/resources/templates/quiz/base_step.ftl | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/stepik-union/src/main/resources/templates/quiz/base_step.ftl b/stepik-union/src/main/resources/templates/quiz/base_step.ftl index 2b0e40f2..9e4c8590 100644 --- a/stepik-union/src/main/resources/templates/quiz/base_step.ftl +++ b/stepik-union/src/main/resources/templates/quiz/base_step.ftl @@ -62,14 +62,13 @@ ${stepNode.getContent()}
-
- + function showLoadAnimation() { + load_animation.style.display = "flex"; + } + \ No newline at end of file From 5c108b8c9c99a1a94215501b874bbf150337c815 Mon Sep 17 00:00:00 2001 From: meanmail Date: Sun, 16 Apr 2017 04:15:17 +0700 Subject: [PATCH 07/22] Added a sending logs from JavaScript to Java [Step Description] --- .../java/org/stepik/core/ui/FormListener.java | 1 + .../stepik/core/ui/StudyBrowserWindow.java | 35 ++++++++++++++++++- .../resources/templates/quiz/base_step.ftl | 1 - 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/stepik-union/src/main/java/org/stepik/core/ui/FormListener.java b/stepik-union/src/main/java/org/stepik/core/ui/FormListener.java index 66bb637e..ffaaa0e6 100644 --- a/stepik-union/src/main/java/org/stepik/core/ui/FormListener.java +++ b/stepik-union/src/main/java/org/stepik/core/ui/FormListener.java @@ -114,6 +114,7 @@ public void handleEvent(Event event) { logger.warn(e); } event.preventDefault(); + event.stopPropagation(); } } diff --git a/stepik-union/src/main/java/org/stepik/core/ui/StudyBrowserWindow.java b/stepik-union/src/main/java/org/stepik/core/ui/StudyBrowserWindow.java index b89e4227..aab1e6ad 100644 --- a/stepik-union/src/main/java/org/stepik/core/ui/StudyBrowserWindow.java +++ b/stepik-union/src/main/java/org/stepik/core/ui/StudyBrowserWindow.java @@ -19,6 +19,7 @@ import javafx.scene.layout.StackPane; import javafx.scene.web.WebEngine; import javafx.scene.web.WebView; +import netscape.javascript.JSObject; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.stepik.api.client.StepikApiClient; @@ -118,6 +119,7 @@ private void initComponents() { engine = webComponent.getEngine(); pane.getChildren().add(webComponent); initHyperlinkListener(); + initConsoleListener(); Scene scene = new Scene(pane); panel.setScene(scene); panel.setVisible(true); @@ -128,6 +130,22 @@ private void initComponents() { setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); } + private void initConsoleListener() { + engine.getLoadWorker() + .stateProperty() + .addListener((observable, oldValue, newValue) -> { + JSObject window = (JSObject) engine.executeScript("window"); + JavaBridge bridge = new JavaBridge(); + window.setMember("java", bridge); + engine.executeScript( + "console.error = function(message){java.error(message);};" + + "console.warn = function(message){java.warn(message);};" + + "console.info = function(message){java.info(message);};" + + "console.debug = function(message){java.debug(message);};" + ); + }); + } + void loadContent(@NotNull final String content) { String withCodeHighlighting = createHtmlWithCodeHighlighting(content); Platform.runLater(() -> engine.loadContent(withCodeHighlighting)); @@ -399,7 +417,7 @@ private void setPanel(JFXPanel panel) { } void showLoadAnimation() { - Platform.runLater(() -> engine.executeScript("showLoadAnimation();")); + Platform.runLater(() -> engine.executeScript("if (window.showLoadAnimation !== undefined) showLoadAnimation();")); } private class StudyLafManagerListener implements LafManagerListener { @@ -408,4 +426,19 @@ public void lookAndFeelChanged(LafManager manager) { updateLaf(manager.getCurrentLookAndFeel() instanceof DarculaLookAndFeelInfo); } } + + public class JavaBridge { + public void log(String text) { + logger.info("console: " + text); + } + public void error(String text) { + logger.error("console: " + text); + } + public void warn(String text) { + logger.warn("console: " + text); + } + public void debug(String text) { + logger.debug("console: " + text); + } + } } diff --git a/stepik-union/src/main/resources/templates/quiz/base_step.ftl b/stepik-union/src/main/resources/templates/quiz/base_step.ftl index 9e4c8590..090941b3 100644 --- a/stepik-union/src/main/resources/templates/quiz/base_step.ftl +++ b/stepik-union/src/main/resources/templates/quiz/base_step.ftl @@ -57,7 +57,6 @@ ${stepNode.getContent()}
- From 4a3846d8ae13932ef3040e102bcc0c82c8638bd6 Mon Sep 17 00:00:00 2001 From: meanmail Date: Sun, 16 Apr 2017 06:13:18 +0700 Subject: [PATCH 08/22] Catch JavaScript exceptions [Step Description] --- .../stepik/core/ui/StudyBrowserWindow.java | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/stepik-union/src/main/java/org/stepik/core/ui/StudyBrowserWindow.java b/stepik-union/src/main/java/org/stepik/core/ui/StudyBrowserWindow.java index aab1e6ad..7d462a16 100644 --- a/stepik-union/src/main/java/org/stepik/core/ui/StudyBrowserWindow.java +++ b/stepik-union/src/main/java/org/stepik/core/ui/StudyBrowserWindow.java @@ -19,7 +19,9 @@ import javafx.scene.layout.StackPane; import javafx.scene.web.WebEngine; import javafx.scene.web.WebView; +import netscape.javascript.JSException; import netscape.javascript.JSObject; +import org.intellij.lang.annotations.Language; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.stepik.api.client.StepikApiClient; @@ -137,12 +139,17 @@ private void initConsoleListener() { JSObject window = (JSObject) engine.executeScript("window"); JavaBridge bridge = new JavaBridge(); window.setMember("java", bridge); - engine.executeScript( - "console.error = function(message){java.error(message);};" + + @Language("JavaScript") + String script = "console.error = function(message){java.error(message);};" + "console.warn = function(message){java.warn(message);};" + - "console.info = function(message){java.info(message);};" + - "console.debug = function(message){java.debug(message);};" - ); + "console.log = function(message){java.log(message);};" + + "console.debug = function(message){java.debug(message);};" + + "window.addEventListener('error', function (e) {" + + " java.doError(e.filename, e.lineno, e.colno, e.message);" + + " return true;"+ + " }" + + ");"; + engine.executeScript(script); }); } @@ -417,7 +424,13 @@ private void setPanel(JFXPanel panel) { } void showLoadAnimation() { - Platform.runLater(() -> engine.executeScript("if (window.showLoadAnimation !== undefined) showLoadAnimation();")); + Platform.runLater(() -> { + try { + engine.executeScript("if (window.showLoadAnimation !== undefined) showLoadAnimation();"); + } catch (JSException e) { + logger.error(e); + } + }); } private class StudyLafManagerListener implements LafManagerListener { @@ -431,14 +444,21 @@ public class JavaBridge { public void log(String text) { logger.info("console: " + text); } + public void error(String text) { logger.error("console: " + text); } + public void warn(String text) { logger.warn("console: " + text); } + public void debug(String text) { logger.debug("console: " + text); } + + public void doError(String filename, int lineno, int colno, String message) { + error("\nfilename: " + filename + "\nline: " + lineno + "\ncolumn: " + colno + "\nmessage: " + message); + } } } From 8e65b989012cc68201d412bfd42cfac4feb400b4 Mon Sep 17 00:00:00 2001 From: meanmail Date: Mon, 17 Apr 2017 01:53:08 +0700 Subject: [PATCH 09/22] A language switch runs not inside Swing thread event queue --- .../org/stepik/core/ui/StudyToolWindow.java | 23 +++--- .../core/utils/ProgrammingLanguageUtils.java | 64 ++++++++++----- .../stepik/core/utils/ProjectFilesUtils.java | 81 +++++++++++-------- 3 files changed, 104 insertions(+), 64 deletions(-) diff --git a/stepik-union/src/main/java/org/stepik/core/ui/StudyToolWindow.java b/stepik-union/src/main/java/org/stepik/core/ui/StudyToolWindow.java index 0797d994..e6a6127f 100644 --- a/stepik-union/src/main/java/org/stepik/core/ui/StudyToolWindow.java +++ b/stepik-union/src/main/java/org/stepik/core/ui/StudyToolWindow.java @@ -360,16 +360,21 @@ public void actionPerformed(ActionEvent e) { final StepNode targetNode = stepNode; - ApplicationManager.getApplication().invokeLater(() -> { - SupportedLanguages selectedLang = (SupportedLanguages) languageBox.getSelectedItem(); - if (selectedLang != null) { - ProgrammingLanguageUtils.switchProgrammingLanguage(project, targetNode, selectedLang); - if (selectedLang != targetNode.getCurrentLang()) { - languageBox.setSelectedItem(targetNode.getCurrentLang()); - } - } + executor.execute(() -> { + final SupportedLanguages[] selectedLang = new SupportedLanguages[1]; + ApplicationManager.getApplication().invokeAndWait(() -> + selectedLang[0] = (SupportedLanguages) languageBox.getSelectedItem() + ); + + if (selectedLang[0] != null) { + ProgrammingLanguageUtils.switchProgrammingLanguage(project, targetNode, selectedLang[0]); + if (selectedLang[0] != targetNode.getCurrentLang()) { + ApplicationManager.getApplication().invokeLater(() -> + languageBox.setSelectedItem(targetNode.getCurrentLang()) + ); } - ); + } + }); } private int getVideoQuality() { diff --git a/stepik-union/src/main/java/org/stepik/core/utils/ProgrammingLanguageUtils.java b/stepik-union/src/main/java/org/stepik/core/utils/ProgrammingLanguageUtils.java index f4218de1..70bfe774 100644 --- a/stepik-union/src/main/java/org/stepik/core/utils/ProgrammingLanguageUtils.java +++ b/stepik-union/src/main/java/org/stepik/core/utils/ProgrammingLanguageUtils.java @@ -1,12 +1,14 @@ package org.stepik.core.utils; import com.intellij.ide.projectView.ProjectView; +import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiFile; @@ -48,11 +50,9 @@ public static void switchProgrammingLanguage( } SupportedLanguages currentLang = targetStepNode.getCurrentLang(); + String currentMainFileName = currentLang.getMainFileName(); - String mainFilePath = String.join("/", - targetStepNode.getPath(), - EduNames.SRC, - currentLang.getMainFileName()); + String mainFilePath = String.join("/", targetStepNode.getPath(), EduNames.SRC, currentMainFileName); VirtualFile mainFile = project.getBaseDir().findFileByRelativePath(mainFilePath); boolean mainFileExists = mainFile != null; @@ -61,7 +61,7 @@ public static void switchProgrammingLanguage( return; } - if (currentLang.getMainFileName().equals(language.getMainFileName()) && mainFileExists) { + if (currentMainFileName.equals(language.getMainFileName()) && mainFileExists) { targetStepNode.setCurrentLang(language); Metrics.switchLanguage(project, targetStepNode, SUCCESSFUL); return; @@ -77,7 +77,7 @@ public static void switchProgrammingLanguage( return; } - PsiFile second = src.findFile(language.getMainFileName()); + PsiFile second = findFile(src, language.getMainFileName()); boolean moveSecond = second == null; if (moveSecond) { second = getOrCreateMainFile(project, hide.getVirtualFile(), language, targetStepNode); @@ -87,26 +87,42 @@ public static void switchProgrammingLanguage( } } - PsiFile first = hide.findFile(currentLang.getMainFileName()); + PsiFile first = findFile(hide, currentMainFileName); boolean moveFirst = first == null; if (moveFirst) { - first = src.findFile(currentLang.getMainFileName()); + first = findFile(src, currentMainFileName); moveFirst = !second.isEquivalentTo(first); } targetStepNode.setCurrentLang(language); ArrayList needClose = closeStepNodeFile(project, targetStepNode); - FileEditorManager.getInstance(project).openFile(second.getVirtualFile(), true); - FileEditorManager editorManager = FileEditorManager.getInstance(project); - needClose.forEach(editorManager::closeFile); - exchangeFiles(src, hide, first, second, moveFirst, moveSecond); + PsiFile finalSecond = second; + PsiFile finalFirst = first; + boolean finalMoveFirst = moveFirst; + ApplicationManager.getApplication() + .invokeAndWait(() -> { + FileEditorManager.getInstance(project).openFile(finalSecond.getVirtualFile(), true); + FileEditorManager editorManager = FileEditorManager.getInstance(project); + needClose.forEach(editorManager::closeFile); + + exchangeFiles(src, hide, finalFirst, finalSecond, finalMoveFirst, moveSecond); + + ProjectView.getInstance(project).selectPsiElement(finalSecond, false); + }); - ProjectView.getInstance(project).selectPsiElement(second, false); Metrics.switchLanguage(project, targetStepNode, SUCCESSFUL); } + @Nullable + private static PsiFile findFile(@NotNull PsiDirectory parent, @NotNull String name) { + return ApplicationManager.getApplication() + .runReadAction((Computable) () -> + parent.findFile(name) + ); + } + private static void exchangeFiles( @NotNull PsiDirectory src, @NotNull PsiDirectory hide, @@ -138,11 +154,16 @@ private static ArrayList closeStepNodeFile( if (StudyUtils.getStudyNode(project, file) != targetStepNode) { continue; } - Document document = documentManager.getDocument(file); + final Document document = ApplicationManager.getApplication() + .runReadAction((Computable) () -> + documentManager.getDocument(file) + ); if (document == null) { continue; } - documentManager.saveDocument(document); + ApplicationManager.getApplication().invokeAndWait(() -> + documentManager.saveDocument(document) + ); needClose.add(file); } @@ -158,10 +179,10 @@ private static PsiFile getOrCreateMainFile( String fileName = language.getMainFileName(); final VirtualFile[] file = {parent.findChild(fileName)}; + Application application = ApplicationManager.getApplication(); if (file[0] == null) { - ApplicationManager - .getApplication() - .runWriteAction(() -> { + application.invokeAndWait(() -> + application.runWriteAction(() -> { try { file[0] = parent.createChildData(null, fileName); String template = null; @@ -200,8 +221,11 @@ private static PsiFile getOrCreateMainFile( } catch (IOException e) { file[0] = null; } - }); + }) + ); } - return PsiManager.getInstance(project).findFile(file[0]); + return application.runReadAction((Computable) () -> + PsiManager.getInstance(project).findFile(file[0]) + ); } } diff --git a/stepik-union/src/main/java/org/stepik/core/utils/ProjectFilesUtils.java b/stepik-union/src/main/java/org/stepik/core/utils/ProjectFilesUtils.java index 668ec9b0..4b3e93cb 100644 --- a/stepik-union/src/main/java/org/stepik/core/utils/ProjectFilesUtils.java +++ b/stepik-union/src/main/java/org/stepik/core/utils/ProjectFilesUtils.java @@ -1,5 +1,6 @@ package org.stepik.core.utils; +import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.ModifiableModuleModel; import com.intellij.openapi.module.ModuleManager; @@ -10,12 +11,12 @@ import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.stepik.core.StudyUtils; import org.stepik.core.core.EduNames; import org.stepik.core.courseFormat.StepNode; import org.stepik.core.courseFormat.StudyNode; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.io.IOException; @@ -145,12 +146,15 @@ public static VirtualFile getOrCreateSrcDirectory( model = ModuleManager.getInstance(project).getModifiableModel(); } ModifiableModuleModel finalModel = model; - ApplicationManager.getApplication().runWriteAction(() -> { - ModuleUtils.createStepModule(project, stepNode, finalModel); - if (modelOwner) { - finalModel.commit(); - } - }); + Application application = ApplicationManager.getApplication(); + application.invokeAndWait(() -> + application.runWriteAction(() -> { + ModuleUtils.createStepModule(project, stepNode, finalModel); + if (modelOwner) { + finalModel.commit(); + } + }) + ); if (refresh) { VirtualFileManager.getInstance().syncRefresh(); } @@ -161,36 +165,40 @@ public static VirtualFile getOrCreateSrcDirectory( @Nullable static PsiDirectory getOrCreateSrcPsiDirectory(@NotNull Project project, @NotNull StepNode stepNode) { - VirtualFile directory = getOrCreateSrcDirectory(project, stepNode, true); - if (directory == null) { - return null; - } - return PsiManager.getInstance(project).findDirectory(directory); + Application application = ApplicationManager.getApplication(); + return application.runReadAction((Computable) () -> { + VirtualFile directory = getOrCreateSrcDirectory(project, stepNode, true); + if (directory == null) { + return null; + } + return PsiManager.getInstance(project).findDirectory(directory); + }); } @Nullable private static VirtualFile getOrCreateDirectory(@NotNull VirtualFile baseDir, @NotNull String directoryPath) { VirtualFile srcDir = baseDir.findFileByRelativePath(directoryPath); if (srcDir == null) { - srcDir = ApplicationManager.getApplication().runWriteAction((Computable) () -> { - VirtualFile dir; - try { - String[] paths = directoryPath.split("/"); - dir = baseDir; - for (String path : paths) { - VirtualFile child = dir.findChild(path); - if (child == null) { - dir = dir.createChildDirectory(null, path); - } else { - dir = child; + srcDir = ApplicationManager.getApplication() + .runWriteAction((Computable) () -> { + VirtualFile dir; + try { + String[] paths = directoryPath.split("/"); + dir = baseDir; + for (String path : paths) { + VirtualFile child = dir.findChild(path); + if (child == null) { + dir = dir.createChildDirectory(null, path); + } else { + dir = child; + } + } + } catch (IOException e) { + return null; } - } - } catch (IOException e) { - return null; - } - return dir; - }); + return dir; + }); } return srcDir; } @@ -199,10 +207,13 @@ static PsiDirectory getOrCreatePsiDirectory( @NotNull Project project, @NotNull PsiDirectory baseDir, @NotNull String relativePath) { - VirtualFile directory = getOrCreateDirectory(baseDir.getVirtualFile(), relativePath); - if (directory == null) { - return null; - } - return PsiManager.getInstance(project).findDirectory(directory); + Application application = ApplicationManager.getApplication(); + return application.runReadAction((Computable) () -> { + VirtualFile directory = getOrCreateDirectory(baseDir.getVirtualFile(), relativePath); + if (directory == null) { + return null; + } + return PsiManager.getInstance(project).findDirectory(directory); + }); } } From 529318ffb3a0e3be19b7eb4820b26a9b6702215b Mon Sep 17 00:00:00 2001 From: meanmail Date: Mon, 17 Apr 2017 02:00:57 +0700 Subject: [PATCH 10/22] Actions on the toolpanel: send, download submissions, reset are enabled for the code-quiz only --- .../plugin/actions/step/CodeQuizAction.java | 31 ++++++++++++++++ .../actions/step/DownloadSubmission.java | 2 +- .../actions/step/InsertStepikDirectives.java | 17 ++------- .../actions/step/StepikResetStepAction.java | 19 +++------- ...aPostAction.java => StepikSendAction.java} | 34 ++++++++++++++--- .../plugin/actions/step/StudyCheckAction.java | 37 ------------------- .../src/main/resources/META-INF/plugin.xml | 2 +- 7 files changed, 70 insertions(+), 72 deletions(-) create mode 100644 stepik-union/src/main/java/org/stepik/plugin/actions/step/CodeQuizAction.java rename stepik-union/src/main/java/org/stepik/plugin/actions/step/{StepikJavaPostAction.java => StepikSendAction.java} (85%) delete mode 100644 stepik-union/src/main/java/org/stepik/plugin/actions/step/StudyCheckAction.java diff --git a/stepik-union/src/main/java/org/stepik/plugin/actions/step/CodeQuizAction.java b/stepik-union/src/main/java/org/stepik/plugin/actions/step/CodeQuizAction.java new file mode 100644 index 00000000..e1c08722 --- /dev/null +++ b/stepik-union/src/main/java/org/stepik/plugin/actions/step/CodeQuizAction.java @@ -0,0 +1,31 @@ +package org.stepik.plugin.actions.step; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.Presentation; +import org.jetbrains.annotations.Nullable; +import org.stepik.core.StepikProjectManager; +import org.stepik.core.courseFormat.StepNode; +import org.stepik.core.courseFormat.StudyNode; + +import javax.swing.*; + +import static org.stepik.core.courseFormat.StepType.CODE; + +abstract class CodeQuizAction extends AbstractStepAction { + CodeQuizAction( + @Nullable String text, + @Nullable String description, + @Nullable Icon icon) { + super(text, description, icon); + } + + @Override + public void update(AnActionEvent e) { + super.update(e); + Presentation presentation = e.getPresentation(); + StudyNode selectedNode = StepikProjectManager.getSelected(e.getProject()); + boolean enabled = presentation.isEnabled(); + boolean canEnabled = (selectedNode instanceof StepNode) && (((StepNode) selectedNode).getType() == CODE); + presentation.setEnabled(enabled && canEnabled); + } +} diff --git a/stepik-union/src/main/java/org/stepik/plugin/actions/step/DownloadSubmission.java b/stepik-union/src/main/java/org/stepik/plugin/actions/step/DownloadSubmission.java index 182606a9..fa600125 100644 --- a/stepik-union/src/main/java/org/stepik/plugin/actions/step/DownloadSubmission.java +++ b/stepik-union/src/main/java/org/stepik/plugin/actions/step/DownloadSubmission.java @@ -59,7 +59,7 @@ * @author meanmail * @since 0.8 */ -public class DownloadSubmission extends AbstractStepAction { +public class DownloadSubmission extends CodeQuizAction { private static final Logger logger = Logger.getInstance(DownloadSubmission.class); private static final String ACTION_ID = "STEPIK.DownloadSubmission"; private static final String SHORTCUT = "ctrl alt pressed PAGE_DOWN"; diff --git a/stepik-union/src/main/java/org/stepik/plugin/actions/step/InsertStepikDirectives.java b/stepik-union/src/main/java/org/stepik/plugin/actions/step/InsertStepikDirectives.java index c50f96bd..0d43ec64 100644 --- a/stepik-union/src/main/java/org/stepik/plugin/actions/step/InsertStepikDirectives.java +++ b/stepik-union/src/main/java/org/stepik/plugin/actions/step/InsertStepikDirectives.java @@ -3,7 +3,6 @@ import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.KeyboardShortcut; -import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.FileEditorManager; @@ -11,12 +10,12 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.stepik.core.StepikProjectManager; import org.stepik.core.SupportedLanguages; import org.stepik.core.courseFormat.StepNode; import org.stepik.core.courseFormat.StudyNode; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.stepik.core.metrics.Metrics; import org.stepik.plugin.utils.DirectivesUtils; import org.stepik.plugin.utils.ReformatUtils; @@ -31,7 +30,7 @@ import static org.stepik.plugin.utils.DirectivesUtils.writeInToFile; -public class InsertStepikDirectives extends AbstractStepAction { +public class InsertStepikDirectives extends CodeQuizAction { private static final String SHORTCUT = "ctrl alt pressed R"; private static final String ACTION_ID = "STEPIK.InsertStepikDirectives"; @@ -109,14 +108,4 @@ public void actionPerformed(AnActionEvent e) { } } } - - @Override - public void update(AnActionEvent e) { - super.update(e); - Presentation presentation = e.getPresentation(); - StudyNode selectedNode = StepikProjectManager.getSelected(e.getProject()); - boolean enabled = presentation.isEnabled(); - boolean canEnabled = (selectedNode instanceof StepNode) && (((StepNode) selectedNode).getType() == CODE); - presentation.setEnabled(enabled && canEnabled); - } } diff --git a/stepik-union/src/main/java/org/stepik/plugin/actions/step/StepikResetStepAction.java b/stepik-union/src/main/java/org/stepik/plugin/actions/step/StepikResetStepAction.java index 0a522720..b4ee6deb 100644 --- a/stepik-union/src/main/java/org/stepik/plugin/actions/step/StepikResetStepAction.java +++ b/stepik-union/src/main/java/org/stepik/plugin/actions/step/StepikResetStepAction.java @@ -3,7 +3,7 @@ import com.intellij.ide.projectView.ProjectView; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.KeyboardShortcut; -import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.editor.Document; @@ -26,7 +26,7 @@ import static org.stepik.core.courseFormat.StepType.CODE; import static org.stepik.core.utils.ProjectFilesUtils.getOrCreateSrcDirectory; -public class StepikResetStepAction extends AbstractStepAction { +public class StepikResetStepAction extends CodeQuizAction { private static final String ACTION_ID = "STEPIK.ResetStepAction"; private static final String SHORTCUT = "ctrl shift pressed X"; @@ -37,8 +37,9 @@ public StepikResetStepAction() { } private static void reset(@NotNull final Project project) { - ApplicationManager.getApplication() - .invokeLater(() -> ApplicationManager.getApplication().runWriteAction(() -> resetFile(project))); + Application application = ApplicationManager.getApplication(); + application.invokeLater(() -> + application.runWriteAction(() -> resetFile(project))); } private static void resetFile(@NotNull final Project project) { @@ -106,14 +107,4 @@ public String getActionId() { public String[] getShortcuts() { return new String[]{SHORTCUT}; } - - @Override - public void update(AnActionEvent e) { - super.update(e); - Presentation presentation = e.getPresentation(); - StudyNode selectedNode = StepikProjectManager.getSelected(e.getProject()); - boolean enabled = presentation.isEnabled(); - boolean canEnabled = (selectedNode instanceof StepNode) && (((StepNode) selectedNode).getType() == CODE); - presentation.setEnabled(enabled && canEnabled); - } } diff --git a/stepik-union/src/main/java/org/stepik/plugin/actions/step/StepikJavaPostAction.java b/stepik-union/src/main/java/org/stepik/plugin/actions/step/StepikSendAction.java similarity index 85% rename from stepik-union/src/main/java/org/stepik/plugin/actions/step/StepikJavaPostAction.java rename to stepik-union/src/main/java/org/stepik/plugin/actions/step/StepikSendAction.java index 08ebe86f..666c3e7b 100644 --- a/stepik-union/src/main/java/org/stepik/plugin/actions/step/StepikJavaPostAction.java +++ b/stepik-union/src/main/java/org/stepik/plugin/actions/step/StepikSendAction.java @@ -1,11 +1,16 @@ package org.stepik.plugin.actions.step; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.KeyboardShortcut; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; +import icons.AllStepikIcons; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.stepik.api.client.StepikApiClient; @@ -22,6 +27,8 @@ import org.stepik.plugin.actions.SendAction; import org.stepik.plugin.utils.DirectivesUtils; +import javax.swing.*; + import static org.stepik.core.metrics.MetricsStatus.DATA_NOT_LOADED; import static org.stepik.core.metrics.MetricsStatus.FAILED_POST; import static org.stepik.core.metrics.MetricsStatus.SUCCESSFUL; @@ -30,11 +37,14 @@ import static org.stepik.core.stepik.StepikConnectorLogin.isAuthenticated; import static org.stepik.core.utils.ProjectFilesUtils.getOrCreateSrcDirectory; -public class StepikJavaPostAction extends StudyCheckAction { - private static final Logger logger = Logger.getInstance(StepikJavaPostAction.class); - private static final String ACTION_ID = "STEPIC.StepikJavaPostAction"; +public class StepikSendAction extends CodeQuizAction { + private static final Logger logger = Logger.getInstance(StepikSendAction.class); + private static final String ACTION_ID = "STEPIC.StepikSendAction"; + private static final String SHORTCUT = "ctrl alt pressed ENTER"; - public StepikJavaPostAction() { + public StepikSendAction() { + super("Check Step (" + KeymapUtil.getShortcutText(new KeyboardShortcut(KeyStroke.getKeyStroke(SHORTCUT), + null)) + ")", "Check current step", AllStepikIcons.ToolWindow.checkTask); } @Nullable @@ -158,7 +168,21 @@ private static void notifyFailed( } @Override - public void check(@NotNull Project project) { + public void actionPerformed(@NotNull AnActionEvent e) { + Project project = e.getProject(); + if (project == null) { + return; + } + FileDocumentManager.getInstance().saveAllDocuments(); + check(project); + } + + @Override + public String[] getShortcuts() { + return new String[]{SHORTCUT}; + } + + private void check(@NotNull Project project) { logger.info("Start checking step"); StudyNode selected = StepikProjectManager.getSelected(project); if (!(selected instanceof StepNode)) { diff --git a/stepik-union/src/main/java/org/stepik/plugin/actions/step/StudyCheckAction.java b/stepik-union/src/main/java/org/stepik/plugin/actions/step/StudyCheckAction.java deleted file mode 100644 index ecdfc579..00000000 --- a/stepik-union/src/main/java/org/stepik/plugin/actions/step/StudyCheckAction.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.stepik.plugin.actions.step; - -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.KeyboardShortcut; -import com.intellij.openapi.fileEditor.FileDocumentManager; -import com.intellij.openapi.keymap.KeymapUtil; -import com.intellij.openapi.project.Project; -import icons.AllStepikIcons; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; - -public abstract class StudyCheckAction extends AbstractStepAction { - private static final String SHORTCUT = "ctrl alt pressed ENTER"; - - StudyCheckAction() { - super("Check Step (" + KeymapUtil.getShortcutText(new KeyboardShortcut(KeyStroke.getKeyStroke(SHORTCUT), - null)) + ")", "Check current step", AllStepikIcons.ToolWindow.checkTask); - } - - protected abstract void check(@NotNull final Project project); - - @Override - public void actionPerformed(@NotNull AnActionEvent e) { - Project project = e.getProject(); - if (project == null) { - return; - } - FileDocumentManager.getInstance().saveAllDocuments(); - check(project); - } - - @Override - public String[] getShortcuts() { - return new String[]{SHORTCUT}; - } -} diff --git a/stepik-union/src/main/resources/META-INF/plugin.xml b/stepik-union/src/main/resources/META-INF/plugin.xml index c03601a1..8a979341 100644 --- a/stepik-union/src/main/resources/META-INF/plugin.xml +++ b/stepik-union/src/main/resources/META-INF/plugin.xml @@ -36,7 +36,7 @@ - + From f3fcf3eacfae3bbb74f6759e4145c9ebc7c95a71 Mon Sep 17 00:00:00 2001 From: meanmail Date: Mon, 17 Apr 2017 02:04:54 +0700 Subject: [PATCH 11/22] Update a progress when success authenticated or logout --- .../stepik/api/objects/metrics/Metric.java | 6 +-- .../metrics/StepikMetricsPostQuery.java | 2 +- .../org/stepik/core/StepikProjectManager.java | 28 ++++++++----- .../stepik/core/StudyProjectComponent.java | 33 ++++++++------- .../org/stepik/core/courseFormat/Node.java | 36 ++++++++-------- .../stepik/core/courseFormat/StepNode.java | 5 --- .../stepik/core/courseFormat/StudyNode.java | 7 +--- .../stepik/core/courseFormat/StudyStatus.java | 4 +- .../java/org/stepik/core/metrics/Metrics.java | 9 +++- .../core/stepik/StepikConnectorLogin.java | 42 +++++++++++++++---- .../java/org/stepik/core/ui/FormListener.java | 12 +----- .../stepik/core/utils/PresentationUtils.java | 8 ++-- .../plugin/StepikPluginConfigurator.java | 4 +- .../pycharm/StepikPyProjectGenerator.java | 6 ++- .../plugin/utils/PresentationDataUtils.java | 4 +- 15 files changed, 115 insertions(+), 91 deletions(-) diff --git a/stepik-java-api/src/main/java/org/stepik/api/objects/metrics/Metric.java b/stepik-java-api/src/main/java/org/stepik/api/objects/metrics/Metric.java index fb8c8d80..af031b99 100644 --- a/stepik-java-api/src/main/java/org/stepik/api/objects/metrics/Metric.java +++ b/stepik-java-api/src/main/java/org/stepik/api/objects/metrics/Metric.java @@ -11,7 +11,7 @@ */ public class Metric { private String name; - private Integer timestamp; + private Long timestamp; private Map tags; private Map data; @@ -57,11 +57,11 @@ public void setName(@Nullable String name) { } @Nullable - public Integer getTimestamp() { + public Long getTimestamp() { return timestamp; } - public void setTimestamp(@Nullable Integer timestamp) { + public void setTimestamp(@Nullable Long timestamp) { this.timestamp = timestamp; } } diff --git a/stepik-java-api/src/main/java/org/stepik/api/queries/metrics/StepikMetricsPostQuery.java b/stepik-java-api/src/main/java/org/stepik/api/queries/metrics/StepikMetricsPostQuery.java index a744e865..8b4195b6 100644 --- a/stepik-java-api/src/main/java/org/stepik/api/queries/metrics/StepikMetricsPostQuery.java +++ b/stepik-java-api/src/main/java/org/stepik/api/queries/metrics/StepikMetricsPostQuery.java @@ -26,7 +26,7 @@ public StepikMetricsPostQuery name(@NotNull String name) { } @NotNull - public StepikMetricsPostQuery timestamp(int value) { + public StepikMetricsPostQuery timestamp(long value) { metrics.getMetric().setTimestamp(value); return this; } diff --git a/stepik-union/src/main/java/org/stepik/core/StepikProjectManager.java b/stepik-union/src/main/java/org/stepik/core/StepikProjectManager.java index fcebfbb7..bf47726d 100644 --- a/stepik-union/src/main/java/org/stepik/core/StepikProjectManager.java +++ b/stepik-union/src/main/java/org/stepik/core/StepikProjectManager.java @@ -2,6 +2,7 @@ import com.google.gson.internal.LinkedTreeMap; import com.intellij.ide.projectView.ProjectView; +import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.components.ServiceManager; @@ -62,6 +63,8 @@ import java.io.IOException; import java.io.OutputStreamWriter; import java.util.UUID; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import static java.nio.charset.StandardCharsets.UTF_8; import static org.stepik.core.stepik.StepikConnectorLogin.authAndGetStepikApiClient; @@ -84,6 +87,8 @@ public class StepikProjectManager implements PersistentStateComponent, private static DOMBuilder domBuilder; @XStreamOmitField private final Project project; + @XStreamOmitField + private final ExecutorService executor = Executors.newSingleThreadExecutor(); private StudyNode root; private StudyNode selected; private boolean showHint = false; @@ -315,7 +320,7 @@ private void refreshCourse() { root.setProject(project); - new Thread(() -> { + executor.execute(() -> { StepikApiClient stepikApiClient = authAndGetStepikApiClient(); if (isAuthenticated()) { root.reloadData(project, stepikApiClient); @@ -332,14 +337,17 @@ public void run(@NotNull ProgressIndicator indicator) { ModifiableModuleModel model = ModuleManager.getInstance(project) .getModifiableModel(); - ApplicationManager.getApplication().runWriteAction(() -> { - try { - new SandboxModuleBuilder(projectDir.getPath()).createModule(model); - model.commit(); - } catch (IOException | ConfigurationException | JDOMException | ModuleWithNameAlreadyExists e) { - logger.warn("Failed repair Sandbox", e); - } - }); + Application application = ApplicationManager.getApplication(); + application.invokeLater(() -> + application.runWriteAction(() -> { + try { + new SandboxModuleBuilder(projectDir.getPath()).createModule(model); + model.commit(); + } catch (IOException | ConfigurationException | JDOMException | ModuleWithNameAlreadyExists e) { + logger.warn("Failed repair Sandbox", e); + } + }) + ); } ApplicationManager.getApplication().invokeLater(() -> @@ -347,7 +355,7 @@ public void run(@NotNull ProgressIndicator indicator) { ); } }); - }).start(); + }); } private void repairProjectFiles(@NotNull StudyNode node) { diff --git a/stepik-union/src/main/java/org/stepik/core/StudyProjectComponent.java b/stepik-union/src/main/java/org/stepik/core/StudyProjectComponent.java index 6fcf15bc..2591a8c4 100644 --- a/stepik-union/src/main/java/org/stepik/core/StudyProjectComponent.java +++ b/stepik-union/src/main/java/org/stepik/core/StudyProjectComponent.java @@ -13,6 +13,7 @@ import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.DumbAwareRunnable; import com.intellij.openapi.project.Project; +import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.util.Pair; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowAnchor; @@ -72,22 +73,8 @@ public void projectOpened() { registerShortcuts(); })); Metrics.openProject(project, SUCCESSFUL); - } - - public void registerStudyToolWindow() { - if (!StepikProjectManager.isStepikProject(project)) { - return; - } - final ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project); - registerToolWindows(toolWindowManager); - final ToolWindow studyToolWindow = - toolWindowManager.getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW); - if (studyToolWindow != null) { - studyToolWindow.show(null); - StudyUtils.initToolWindows(project); - } - executor.execute(() -> { + StartupManager.getInstance(project).runWhenProjectIsInitialized(() -> executor.execute(() -> { StepikProjectManager projectManager = StepikProjectManager.getInstance(project); if (projectManager == null) { return; @@ -112,7 +99,21 @@ public void registerStudyToolWindow() { projectManager.setSelected(selected); } - }); + })); + } + + public void registerStudyToolWindow() { + if (!StepikProjectManager.isStepikProject(project)) { + return; + } + final ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project); + registerToolWindows(toolWindowManager); + final ToolWindow studyToolWindow = + toolWindowManager.getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW); + if (studyToolWindow != null) { + studyToolWindow.show(null); + StudyUtils.initToolWindows(project); + } } private void registerShortcuts() { diff --git a/stepik-union/src/main/java/org/stepik/core/courseFormat/Node.java b/stepik-union/src/main/java/org/stepik/core/courseFormat/Node.java index bd02a7d8..2ceb767b 100644 --- a/stepik-union/src/main/java/org/stepik/core/courseFormat/Node.java +++ b/stepik-union/src/main/java/org/stepik/core/courseFormat/Node.java @@ -21,6 +21,9 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import static org.stepik.core.courseFormat.StudyStatus.NEED_CHECK; +import static org.stepik.core.courseFormat.StudyStatus.SOLVED; +import static org.stepik.core.courseFormat.StudyStatus.UNCHECKED; import static org.stepik.core.stepik.StepikConnectorLogin.authAndGetStepikApiClient; import static org.stepik.core.stepik.StepikConnectorLogin.isAuthenticated; @@ -33,7 +36,7 @@ abstract class Node< DC extends StudyObject, CC extends Node> implements StudyNode { private static final Logger logger = Logger.getInstance(Node.class); - private static final ExecutorService executor = Executors.newSingleThreadExecutor(); + private static final ExecutorService executor = Executors.newFixedThreadPool(5); private StudyNode parent; private D data; private List children; @@ -285,16 +288,25 @@ public void reloadData(@NotNull Project project, @NotNull StepikApiClient stepik @Override public boolean isUnknownStatus() { - return status == null; + return status == null || status == NEED_CHECK; + } + + public void resetStatus() { + getChildren().forEach(StudyNode::resetStatus); + status = NEED_CHECK; } @NotNull @Override public StudyStatus getStatus() { if (isUnknownStatus()) { - status = StudyStatus.UNCHECKED; + status = UNCHECKED; executor.execute(() -> { + StepikApiClient stepikApiClient = authAndGetStepikApiClient(); + if (!isAuthenticated()) { + return; + } try { Map progressMap = new HashMap<>(); Node.this.getChildren().stream() @@ -320,11 +332,6 @@ public StudyStatus getStatus() { int start = 0; int end; - StepikApiClient stepikApiClient = authAndGetStepikApiClient(); - if (!isAuthenticated()) { - return; - } - while (start < size) { end = start + 20; if (end > size) { @@ -342,7 +349,7 @@ public StudyStatus getStatus() { String id = progress.getId(); StudyNode node = progressMap.get(id); if (progress.isPassed()) { - node.setRawStatus(StudyStatus.SOLVED); + node.setRawStatus(SOLVED); } }); } @@ -366,8 +373,8 @@ public StudyStatus getStatus() { @Override public void setStatus(@Nullable StudyStatus status) { - if (status == StudyStatus.SOLVED && this.status != status) { - this.status = StudyStatus.SOLVED; + if (status == SOLVED && this.status != status) { + this.status = SOLVED; StudyNode parent = getParent(); @@ -385,7 +392,7 @@ public void setRawStatus(@Nullable StudyStatus status) { @Override public void passed() { - setStatus(StudyStatus.SOLVED); + setStatus(SOLVED); } @Nullable @@ -422,11 +429,6 @@ public void setId(long id) { } } - @Override - public boolean canBeLeaf() { - return false; - } - @Override public int getPosition() { StudyObject data = getData(); diff --git a/stepik-union/src/main/java/org/stepik/core/courseFormat/StepNode.java b/stepik-union/src/main/java/org/stepik/core/courseFormat/StepNode.java index 3b5fc825..ce0975a4 100644 --- a/stepik-union/src/main/java/org/stepik/core/courseFormat/StepNode.java +++ b/stepik-union/src/main/java/org/stepik/core/courseFormat/StepNode.java @@ -258,11 +258,6 @@ String getDirectoryPrefix() { return EduNames.STEP; } - @Override - public boolean canBeLeaf() { - return true; - } - @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/stepik-union/src/main/java/org/stepik/core/courseFormat/StudyNode.java b/stepik-union/src/main/java/org/stepik/core/courseFormat/StudyNode.java index 225f9d6b..8bf538cd 100644 --- a/stepik-union/src/main/java/org/stepik/core/courseFormat/StudyNode.java +++ b/stepik-union/src/main/java/org/stepik/core/courseFormat/StudyNode.java @@ -64,8 +64,6 @@ default void init(@NotNull Project project, @NotNull StepikApiClient stepikApiCl init(project, stepikApiClient, null); } - boolean canBeLeaf(); - void reloadData(@NotNull Project project, @NotNull StepikApiClient stepikApiClient); boolean getWasDeleted(); @@ -76,10 +74,9 @@ default void init(@NotNull Project project, @NotNull StepikApiClient stepikApiCl void setRawStatus(@Nullable StudyStatus status); - void passed(); + void resetStatus(); - @Nullable - Project getProject(); + void passed(); void setProject(@NotNull Project project); } diff --git a/stepik-union/src/main/java/org/stepik/core/courseFormat/StudyStatus.java b/stepik-union/src/main/java/org/stepik/core/courseFormat/StudyStatus.java index 8921eb69..235ec11f 100644 --- a/stepik-union/src/main/java/org/stepik/core/courseFormat/StudyStatus.java +++ b/stepik-union/src/main/java/org/stepik/core/courseFormat/StudyStatus.java @@ -3,11 +3,11 @@ import org.jetbrains.annotations.Nullable; public enum StudyStatus { - UNCHECKED, SOLVED, FAILED; + UNCHECKED, SOLVED, FAILED, NEED_CHECK; public static StudyStatus of(@Nullable String status) { if (status == null) { - return UNCHECKED; + return NEED_CHECK; } status = status.toLowerCase(); diff --git a/stepik-union/src/main/java/org/stepik/core/metrics/Metrics.java b/stepik-union/src/main/java/org/stepik/core/metrics/Metrics.java index d0ce975f..b00f6184 100644 --- a/stepik-union/src/main/java/org/stepik/core/metrics/Metrics.java +++ b/stepik-union/src/main/java/org/stepik/core/metrics/Metrics.java @@ -16,6 +16,9 @@ import org.stepik.core.utils.Utils; import java.util.UUID; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import static org.stepik.core.stepik.StepikConnectorLogin.authAndGetStepikApiClient; import static org.stepik.core.stepik.StepikConnectorLogin.isAuthenticated; @@ -26,12 +29,13 @@ public class Metrics { private static final Logger logger = Logger.getInstance(Metrics.class); private static final String session = UUID.randomUUID().toString(); + private static final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); private static void postMetrics( @NotNull Project project, @NotNull Metric metric, @NotNull MetricsStatus status) { - new Thread(() -> { + executor.schedule(() -> { StepikMetricsPostQuery query = null; try { StepikApiClient stepikApiClient = authAndGetStepikApiClient(); @@ -41,6 +45,7 @@ private static void postMetrics( query = stepikApiClient.metrics() .post() + .timestamp(System.currentTimeMillis() / 1000L) .tags(metric.getTags()) .data(metric.getData()) .name("ide_plugin") @@ -74,7 +79,7 @@ private static void postMetrics( String message = String.format("Failed post metric: %s", query != null ? query.toString() : "null"); logger.warn(message, e); } - }).start(); + }, 500, TimeUnit.MILLISECONDS); } private static void postSimpleMetric( diff --git a/stepik-union/src/main/java/org/stepik/core/stepik/StepikConnectorLogin.java b/stepik-union/src/main/java/org/stepik/core/stepik/StepikConnectorLogin.java index 8aa537d7..50df8d1a 100644 --- a/stepik-union/src/main/java/org/stepik/core/stepik/StepikConnectorLogin.java +++ b/stepik-union/src/main/java/org/stepik/core/stepik/StepikConnectorLogin.java @@ -7,6 +7,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; import com.intellij.util.net.HttpConfigurable; import org.jetbrains.annotations.NotNull; import org.stepik.api.client.HttpTransportClient; @@ -15,6 +16,7 @@ import org.stepik.api.objects.auth.TokenInfo; import org.stepik.api.objects.users.User; import org.stepik.core.StepikProjectManager; +import org.stepik.core.courseFormat.StudyNode; import org.stepik.core.metrics.Metrics; import org.stepik.core.utils.PluginUtils; import org.stepik.core.utils.ProductGroup; @@ -26,6 +28,7 @@ import static org.stepik.core.metrics.MetricsStatus.SUCCESSFUL; import static org.stepik.core.utils.PluginUtils.PLUGIN_ID; +import static org.stepik.core.utils.Utils.getCurrentProject; public class StepikConnectorLogin { private static final Logger logger = Logger.getInstance(StepikConnectorLogin.class); @@ -41,7 +44,7 @@ public class StepikConnectorLogin { private static volatile boolean authenticated = true; private static User user; - private static synchronized long getLastUser() { + private static long getLastUser() { return PropertiesComponent.getInstance().getOrInitLong(LAST_USER_PROPERTY_NAME, 0); } @@ -50,7 +53,7 @@ private static void setLastUser(long userId) { } @NotNull - private static StepikApiClient initStepikApiClient() { + private static synchronized StepikApiClient initStepikApiClient() { HttpConfigurable instance = HttpConfigurable.getInstance(); StepikApiClient client; if (instance.USE_HTTP_PROXY) { @@ -81,8 +84,20 @@ private static StepikApiClient initStepikApiClient() { * */ public static synchronized void authentication(boolean showDialog) { - TokenInfo tokenInfo = getTokenInfo(getLastUser()); - authenticated = minorLogin(tokenInfo) || (showDialog && showAuthDialog(false)); + boolean value = minorLogin() || (showDialog && showAuthDialog(false)); + setAuthenticated(value); + } + + private static void stateChanged(boolean state) { + Project project = getCurrentProject(); + StepikProjectManager projectManager = StepikProjectManager.getInstance(project); + if (projectManager != null) { + StudyNode root = projectManager.getProjectRoot(); + if (root != null) { + root.resetStatus(); + } + projectManager.updateSelection(); + } } private static boolean showAuthDialog(boolean clear) { @@ -134,6 +149,7 @@ public static boolean isAuthenticated() { if (!authenticated) { return false; } + if (stepikApiClient.getTokenInfo().getAccessToken() != null) { User user = getCurrentUser(true); if (!user.isGuest()) { @@ -144,13 +160,21 @@ public static boolean isAuthenticated() { return false; } - private static boolean minorLogin(@NotNull TokenInfo tokenInfo) { + private static void setAuthenticated(boolean value) { + if (authenticated != value) { + authenticated = value; + stateChanged(authenticated); + } + } + + private static boolean minorLogin() { if (isAuthenticated()) { return true; } String refreshToken = stepikApiClient.getTokenInfo().getRefreshToken(); if (refreshToken == null) { + TokenInfo tokenInfo = getTokenInfo(getLastUser()); refreshToken = tokenInfo.getRefreshToken(); } @@ -175,7 +199,7 @@ private static TokenInfo getTokenInfo(long userId) { } @NotNull - private static synchronized TokenInfo getTokenInfo(long userId, StepikApiClient client) { + private static TokenInfo getTokenInfo(long userId, StepikApiClient client) { if (userId == 0) { return new TokenInfo(); } @@ -239,18 +263,18 @@ public static StepikApiClient authAndGetStepikApiClient() { return authAndGetStepikApiClient(false); } - public static StepikApiClient authAndGetStepikApiClient(boolean force) { - StepikConnectorLogin.authentication(force); + public static StepikApiClient authAndGetStepikApiClient(boolean showDialog) { + StepikConnectorLogin.authentication(showDialog); return stepikApiClient; } public static synchronized void logout() { stepikApiClient.setTokenInfo(null); - authenticated = false; user = null; long userId = getLastUser(); setTokenInfo(userId, new TokenInfo()); setLastUser(0); + setAuthenticated(false); logger.info("Logout successfully"); } diff --git a/stepik-union/src/main/java/org/stepik/core/ui/FormListener.java b/stepik-union/src/main/java/org/stepik/core/ui/FormListener.java index ffaaa0e6..d785ee07 100644 --- a/stepik-union/src/main/java/org/stepik/core/ui/FormListener.java +++ b/stepik-union/src/main/java/org/stepik/core/ui/FormListener.java @@ -94,18 +94,10 @@ public void handleEvent(Event event) { boolean isFromFile = elements.isFromFile(); String data = isFromFile ? getDataFromFile(stepNode) : null; long attemptId = elements.getAttemptId(); - - if (!isFromFile) { - sendStep(stepNode, elements, type, attemptId, null); - } else if (data != null) { - sendStep(stepNode, elements, type, attemptId, data); - } + sendStep(stepNode, elements, type, attemptId, data); break; case "need_login": - executor.execute(() -> { - StepikConnectorLogin.authentication(true); - StepikProjectManager.updateSelection(project); - }); + executor.execute(() -> StepikConnectorLogin.authentication(true)); break; default: return; diff --git a/stepik-union/src/main/java/org/stepik/core/utils/PresentationUtils.java b/stepik-union/src/main/java/org/stepik/core/utils/PresentationUtils.java index 13dcb356..5eb4501a 100644 --- a/stepik-union/src/main/java/org/stepik/core/utils/PresentationUtils.java +++ b/stepik-union/src/main/java/org/stepik/core/utils/PresentationUtils.java @@ -1,15 +1,15 @@ package org.stepik.core.utils; import com.intellij.ui.JBColor; +import icons.AllStepikIcons; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.stepik.core.courseFormat.CourseNode; import org.stepik.core.courseFormat.LessonNode; import org.stepik.core.courseFormat.SectionNode; import org.stepik.core.courseFormat.StepNode; import org.stepik.core.courseFormat.StudyNode; import org.stepik.core.courseFormat.StudyStatus; -import icons.AllStepikIcons; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; @@ -108,8 +108,6 @@ private static Icon[][] getIcons() { @NotNull public static JBColor getColor(@NotNull StudyStatus status) { switch (status) { - case UNCHECKED: - return JBColor.BLACK; case SOLVED: return SOLVED_COLOR; case FAILED: diff --git a/stepik-union/src/main/java/org/stepik/plugin/StepikPluginConfigurator.java b/stepik-union/src/main/java/org/stepik/plugin/StepikPluginConfigurator.java index 5374c35f..2ef3d007 100644 --- a/stepik-union/src/main/java/org/stepik/plugin/StepikPluginConfigurator.java +++ b/stepik-union/src/main/java/org/stepik/plugin/StepikPluginConfigurator.java @@ -9,7 +9,7 @@ import org.stepik.plugin.actions.navigation.StepikPreviousStepAction; import org.stepik.plugin.actions.step.DownloadSubmission; import org.stepik.plugin.actions.step.InsertStepikDirectives; -import org.stepik.plugin.actions.step.StepikJavaPostAction; +import org.stepik.plugin.actions.step.StepikSendAction; import org.stepik.plugin.actions.step.StepikResetStepAction; public class StepikPluginConfigurator extends StudyBasePluginConfigurator { @@ -18,7 +18,7 @@ public class StepikPluginConfigurator extends StudyBasePluginConfigurator { public DefaultActionGroup getActionGroup(Project project) { final DefaultActionGroup group = new DefaultActionGroup(); - group.add(new StepikJavaPostAction()); + group.add(new StepikSendAction()); group.add(new StepikPreviousStepAction()); group.add(new StepikNextStepAction()); group.add(new StepikResetStepAction()); diff --git a/stepik-union/src/main/java/org/stepik/plugin/projectWizard/pycharm/StepikPyProjectGenerator.java b/stepik-union/src/main/java/org/stepik/plugin/projectWizard/pycharm/StepikPyProjectGenerator.java index fc8a65eb..da7d533f 100644 --- a/stepik-union/src/main/java/org/stepik/plugin/projectWizard/pycharm/StepikPyProjectGenerator.java +++ b/stepik-union/src/main/java/org/stepik/plugin/projectWizard/pycharm/StepikPyProjectGenerator.java @@ -1,6 +1,7 @@ package org.stepik.plugin.projectWizard.pycharm; import com.intellij.facet.ui.ValidationResult; +import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; @@ -203,9 +204,10 @@ private void createCourseFromGenerator(@NotNull Project project) { VirtualFileManager.getInstance().syncRefresh(); } - ApplicationManager.getApplication().invokeLater( + Application application = ApplicationManager.getApplication(); + application.invokeLater( () -> DumbService.allowStartingDumbModeInside(DumbModePermission.MAY_START_BACKGROUND, - () -> ApplicationManager.getApplication().runWriteAction( + () -> application.runWriteAction( () -> StudyProjectComponent.getInstance(project) .registerStudyToolWindow()))); } diff --git a/stepik-union/src/main/java/org/stepik/plugin/utils/PresentationDataUtils.java b/stepik-union/src/main/java/org/stepik/plugin/utils/PresentationDataUtils.java index e5475ecc..2430eaf9 100644 --- a/stepik-union/src/main/java/org/stepik/plugin/utils/PresentationDataUtils.java +++ b/stepik-union/src/main/java/org/stepik/plugin/utils/PresentationDataUtils.java @@ -6,13 +6,13 @@ import com.intellij.psi.PsiFile; import com.intellij.ui.JBColor; import com.intellij.ui.SimpleTextAttributes; +import icons.AllStepikIcons; +import org.jetbrains.annotations.NotNull; import org.stepik.core.StepikProjectManager; import org.stepik.core.StudyUtils; import org.stepik.core.core.EduNames; import org.stepik.core.courseFormat.StudyNode; import org.stepik.core.courseFormat.StudyStatus; -import icons.AllStepikIcons; -import org.jetbrains.annotations.NotNull; import org.stepik.core.utils.PresentationUtils; import javax.swing.*; From ff5f3ada4f4a009a164e5a7afedc038d630a1f5e Mon Sep 17 00:00:00 2001 From: meanmail Date: Mon, 17 Apr 2017 02:45:50 +0700 Subject: [PATCH 12/22] Fixed a probably deadlock --- .../stepik/core/utils/ProjectFilesUtils.java | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/stepik-union/src/main/java/org/stepik/core/utils/ProjectFilesUtils.java b/stepik-union/src/main/java/org/stepik/core/utils/ProjectFilesUtils.java index 4b3e93cb..a424c853 100644 --- a/stepik-union/src/main/java/org/stepik/core/utils/ProjectFilesUtils.java +++ b/stepik-union/src/main/java/org/stepik/core/utils/ProjectFilesUtils.java @@ -177,10 +177,11 @@ static PsiDirectory getOrCreateSrcPsiDirectory(@NotNull Project project, @NotNul @Nullable private static VirtualFile getOrCreateDirectory(@NotNull VirtualFile baseDir, @NotNull String directoryPath) { - VirtualFile srcDir = baseDir.findFileByRelativePath(directoryPath); - if (srcDir == null) { - srcDir = ApplicationManager.getApplication() - .runWriteAction((Computable) () -> { + final VirtualFile[] srcDir = {baseDir.findFileByRelativePath(directoryPath)}; + if (srcDir[0] == null) { + Application application = ApplicationManager.getApplication(); + application.invokeAndWait(() -> + srcDir[0] = application.runWriteAction((Computable) () -> { VirtualFile dir; try { String[] paths = directoryPath.split("/"); @@ -198,22 +199,24 @@ private static VirtualFile getOrCreateDirectory(@NotNull VirtualFile baseDir, @N } return dir; - }); + }) + ); } - return srcDir; + return srcDir[0]; } static PsiDirectory getOrCreatePsiDirectory( @NotNull Project project, @NotNull PsiDirectory baseDir, @NotNull String relativePath) { + VirtualFile directory = getOrCreateDirectory(baseDir.getVirtualFile(), relativePath); + if (directory == null) { + return null; + } + Application application = ApplicationManager.getApplication(); - return application.runReadAction((Computable) () -> { - VirtualFile directory = getOrCreateDirectory(baseDir.getVirtualFile(), relativePath); - if (directory == null) { - return null; - } - return PsiManager.getInstance(project).findDirectory(directory); - }); + return application.runReadAction((Computable) () -> + PsiManager.getInstance(project).findDirectory(directory) + ); } } From bc22f16d3637f91f1d3b7d34ec113694411d45e2 Mon Sep 17 00:00:00 2001 From: meanmail Date: Mon, 17 Apr 2017 02:46:28 +0700 Subject: [PATCH 13/22] Fixed NPE --- .../core/courseFormat/stepHelpers/VideoTheoryHelper.java | 3 +++ stepik-union/src/main/resources/templates/quiz/video.ftl | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/stepik-union/src/main/java/org/stepik/core/courseFormat/stepHelpers/VideoTheoryHelper.java b/stepik-union/src/main/java/org/stepik/core/courseFormat/stepHelpers/VideoTheoryHelper.java index 3a9da93a..3d60f1ac 100644 --- a/stepik-union/src/main/java/org/stepik/core/courseFormat/stepHelpers/VideoTheoryHelper.java +++ b/stepik-union/src/main/java/org/stepik/core/courseFormat/stepHelpers/VideoTheoryHelper.java @@ -77,6 +77,9 @@ private List getVideoUrls() { } public Collection getQualitySet() { + if (urls == null) { + urls = getVideoUrls(); + } return urls.stream() .map(VideoUrl::getQuality) .collect(Collectors.toList()); diff --git a/stepik-union/src/main/resources/templates/quiz/video.ftl b/stepik-union/src/main/resources/templates/quiz/video.ftl index fa7f4db9..c8f81128 100644 --- a/stepik-union/src/main/resources/templates/quiz/video.ftl +++ b/stepik-union/src/main/resources/templates/quiz/video.ftl @@ -3,6 +3,10 @@ <@step_content> - + <#if stepNode.hasContent()> + + <#else> +

Not content

+ \ No newline at end of file From cf8317be08785b1fdb655a6b46c25cff0d04daed Mon Sep 17 00:00:00 2001 From: meanmail Date: Mon, 17 Apr 2017 13:56:37 +0700 Subject: [PATCH 14/22] Correct work a adaptive course-project if user is not authenticated --- .../courseFormat/stepHelpers/QuizHelper.java | 8 +--- .../courseFormat/stepHelpers/StepHelper.java | 21 +++++++++ .../core/stepik/StepikConnectorLogin.java | 22 ++++----- .../java/org/stepik/core/ui/FormListener.java | 9 +++- .../stepik/core/ui/StudyBrowserWindow.java | 14 +++++- .../main/resources/templates/quiz/base.ftl | 8 ++-- .../resources/templates/quiz/base_step.ftl | 46 +++++++++++++------ 7 files changed, 87 insertions(+), 41 deletions(-) diff --git a/stepik-union/src/main/java/org/stepik/core/courseFormat/stepHelpers/QuizHelper.java b/stepik-union/src/main/java/org/stepik/core/courseFormat/stepHelpers/QuizHelper.java index f7ca728f..e59c245f 100644 --- a/stepik-union/src/main/java/org/stepik/core/courseFormat/stepHelpers/QuizHelper.java +++ b/stepik-union/src/main/java/org/stepik/core/courseFormat/stepHelpers/QuizHelper.java @@ -34,7 +34,6 @@ public class QuizHelper extends StepHelper { private static final String GET_ATTEMPT = "get_attempt"; private static final String GET_FIRST_ATTEMPT = "get_first_attempt"; private static final String SUBMIT = "submit"; - private static final String NEED_LOGIN = "need_login"; private static final String UNCHECKED = "unchecked"; @NotNull Reply reply = new Reply(); @@ -99,17 +98,13 @@ private boolean loadSubmission(StepikApiClient stepikApiClient, long userId) { return false; } + @Override @NotNull public String getStatus() { initStepOptions(); return status; } - @NotNull - public String getPath() { - return getStepNode().getPath(); - } - public long getAttemptId() { initStepOptions(); return attempt.getId(); @@ -272,6 +267,7 @@ public int getMaxSubmissionsCount() { return data.getMaxSubmissionsCount(); } + @Override @NotNull public String getAction() { initStepOptions(); diff --git a/stepik-union/src/main/java/org/stepik/core/courseFormat/stepHelpers/StepHelper.java b/stepik-union/src/main/java/org/stepik/core/courseFormat/stepHelpers/StepHelper.java index a1dd1d85..37401ae5 100644 --- a/stepik-union/src/main/java/org/stepik/core/courseFormat/stepHelpers/StepHelper.java +++ b/stepik-union/src/main/java/org/stepik/core/courseFormat/stepHelpers/StepHelper.java @@ -6,10 +6,13 @@ import org.stepik.core.courseFormat.StepNode; import org.stepik.core.courseFormat.StudyNode; +import static org.stepik.core.stepik.StepikConnectorLogin.isAuthenticated; + /** * @author meanmail */ public class StepHelper { + static final String NEED_LOGIN = "need_login"; private final Project project; private final StepNode stepNode; @@ -18,6 +21,19 @@ public StepHelper(@NotNull Project project, @NotNull StepNode stepNode) { this.stepNode = stepNode; } + @NotNull + public String getStatus() { + return ""; + } + + @NotNull + public String getAction() { + if (!isAuthenticated()) { + return NEED_LOGIN; + } + return ""; + } + @NotNull StepNode getStepNode() { return stepNode; @@ -39,6 +55,11 @@ public String getLink() { return "https://stepik.org/"; } + @NotNull + public String getPath() { + return getStepNode().getPath(); + } + @NotNull public String getLinkTitle() { return String.format("This step can take place in the web version (%s)", getType()); diff --git a/stepik-union/src/main/java/org/stepik/core/stepik/StepikConnectorLogin.java b/stepik-union/src/main/java/org/stepik/core/stepik/StepikConnectorLogin.java index 50df8d1a..b87d3dd3 100644 --- a/stepik-union/src/main/java/org/stepik/core/stepik/StepikConnectorLogin.java +++ b/stepik-union/src/main/java/org/stepik/core/stepik/StepikConnectorLogin.java @@ -88,18 +88,6 @@ public static synchronized void authentication(boolean showDialog) { setAuthenticated(value); } - private static void stateChanged(boolean state) { - Project project = getCurrentProject(); - StepikProjectManager projectManager = StepikProjectManager.getInstance(project); - if (projectManager != null) { - StudyNode root = projectManager.getProjectRoot(); - if (root != null) { - root.resetStatus(); - } - projectManager.updateSelection(); - } - } - private static boolean showAuthDialog(boolean clear) { Application application = ApplicationManager.getApplication(); final boolean[] authenticated = new boolean[1]; @@ -163,7 +151,15 @@ public static boolean isAuthenticated() { private static void setAuthenticated(boolean value) { if (authenticated != value) { authenticated = value; - stateChanged(authenticated); + Project project = getCurrentProject(); + StepikProjectManager projectManager = StepikProjectManager.getInstance(project); + if (projectManager != null) { + StudyNode root = projectManager.getProjectRoot(); + if (root != null) { + root.resetStatus(); + } + projectManager.updateSelection(); + } } } diff --git a/stepik-union/src/main/java/org/stepik/core/ui/FormListener.java b/stepik-union/src/main/java/org/stepik/core/ui/FormListener.java index d785ee07..212ed409 100644 --- a/stepik-union/src/main/java/org/stepik/core/ui/FormListener.java +++ b/stepik-union/src/main/java/org/stepik/core/ui/FormListener.java @@ -55,9 +55,11 @@ class FormListener implements EventListener { private static final Logger logger = Logger.getInstance(FormListener.class); private static final ExecutorService executor = Executors.newSingleThreadExecutor(); private final Project project; + private final StudyBrowserWindow browser; - FormListener(@NotNull Project project) { + FormListener(@NotNull Project project, @NotNull StudyBrowserWindow browser) { this.project = project; + this.browser = browser; } @Override @@ -97,7 +99,10 @@ public void handleEvent(Event event) { sendStep(stepNode, elements, type, attemptId, data); break; case "need_login": - executor.execute(() -> StepikConnectorLogin.authentication(true)); + executor.execute(() -> { + StepikConnectorLogin.authentication(true); + browser.hideLoadAnimation(); + }); break; default: return; diff --git a/stepik-union/src/main/java/org/stepik/core/ui/StudyBrowserWindow.java b/stepik-union/src/main/java/org/stepik/core/ui/StudyBrowserWindow.java index 7d462a16..33785842 100644 --- a/stepik-union/src/main/java/org/stepik/core/ui/StudyBrowserWindow.java +++ b/stepik-union/src/main/java/org/stepik/core/ui/StudyBrowserWindow.java @@ -146,7 +146,7 @@ private void initConsoleListener() { "console.debug = function(message){java.debug(message);};" + "window.addEventListener('error', function (e) {" + " java.doError(e.filename, e.lineno, e.colno, e.message);" + - " return true;"+ + " return true;" + " }" + ");"; engine.executeScript(script); @@ -187,7 +187,7 @@ private void initHyperlinkListener() { final EventListener linkListener = makeHyperLinkListener(); addListenerToAllHyperlinkItems(linkListener); - final EventListener formListener = new FormListener(project); + final EventListener formListener = new FormListener(project, this); final Document doc = engine.getDocument(); ((EventTarget) doc).addEventListener(FormListener.EVENT_TYPE_SUBMIT, formListener, false); } @@ -433,6 +433,16 @@ void showLoadAnimation() { }); } + void hideLoadAnimation() { + Platform.runLater(() -> { + try { + engine.executeScript("if (window.hideLoadAnimation !== undefined) hideLoadAnimation();"); + } catch (JSException e) { + logger.error(e); + } + }); + } + private class StudyLafManagerListener implements LafManagerListener { @Override public void lookAndFeelChanged(LafManager manager) { diff --git a/stepik-union/src/main/resources/templates/quiz/base.ftl b/stepik-union/src/main/resources/templates/quiz/base.ftl index b3459f88..098c7674 100644 --- a/stepik-union/src/main/resources/templates/quiz/base.ftl +++ b/stepik-union/src/main/resources/templates/quiz/base.ftl @@ -1,3 +1,6 @@ +<#-- @ftlvariable name="action" type="java.lang.String" --> +<#-- @ftlvariable name="needLogin" type="boolean" --> +<#-- @ftlvariable name="status" type="java.lang.String" --> <#-- @ftlvariable name="stepNode" type="org.stepik.core.courseFormat.stepHelpers.QuizHelper" --> <#-- @ftlvariable name="text" type="java.lang.String" -->