Add ability for educational plugins to provide additional settings panel Add ability...
authorValentina Kiryushkina <valentina.kiryushkina@jetbrains.com>
Fri, 12 Feb 2016 16:33:32 +0000 (19:33 +0300)
committerValentina Kiryushkina <valentina.kiryushkina@jetbrains.com>
Tue, 15 Mar 2016 16:41:51 +0000 (19:41 +0300)
* Rename StudyToolWindowConfigurator to StudyPluginConfigurator. Now configurator provides plugin's settings panel and post-check actions
* In StudyConfigurable main panel is constructed from StudyBaseSettingPanel and plugins panels provided by StudyPluginConfigurator

19 files changed:
python/educational-core/student/resources/META-INF/plugin.xml
python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java [moved from python/educational-core/student/src/com/jetbrains/edu/learning/StudyBaseToolWindowConfigurator.java with 93% similarity]
python/educational-core/student/src/com/jetbrains/edu/learning/StudyPluginConfigurator.java [moved from python/educational-core/student/src/com/jetbrains/edu/learning/StudyToolWindowConfigurator.java with 73% similarity]
python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java
python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyAfterCheckAction.java [new file with mode: 0644]
python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java
python/educational-core/student/src/com/jetbrains/edu/learning/settings/ModifiableSettingsPanel.java [new file with mode: 0644]
python/educational-core/student/src/com/jetbrains/edu/learning/settings/StudyBaseSettingsPanel.form [moved from python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StudySettingsPanel.form with 84% similarity]
python/educational-core/student/src/com/jetbrains/edu/learning/settings/StudyBaseSettingsPanel.java [moved from python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StudySettingsPanel.java with 88% similarity]
python/educational-core/student/src/com/jetbrains/edu/learning/settings/StudyConfigurable.java [new file with mode: 0644]
python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StudyConfigurable.java [deleted file]
python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyBrowserWindow.java
python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyJavaFxToolWindow.java
python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindow.java
python/educational-python/student-python/resources/META-INF/plugin.xml
python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyPluginConfigurator.java [moved from python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyToolWindowConfigurator.java with 63% similarity]
python/educational-python/student-python/src/com/jetbrains/edu/learning/settings/PySettingsPanel.form [new file with mode: 0644]
python/educational-python/student-python/src/com/jetbrains/edu/learning/settings/PySettingsPanel.java [new file with mode: 0644]
python/educational-python/student-python/src/com/jetbrains/edu/learning/settings/PyStudySettings.java [new file with mode: 0644]

index f29b7e7a1c1af0a2f0d7bdf16663fb14300aa901..3e10b6a2bb2e8b3b19ea75d56b2e4e8eccea0caa 100644 (file)
@@ -35,7 +35,7 @@
     <extensionPoint qualifiedName="Edu.StudyLanguageManager" beanClass="com.intellij.lang.LanguageExtensionPoint">
       <with attribute="implementationClass" implements="com.jetbrains.edu.learning.StudyLanguageManager"/>
     </extensionPoint>
-    <extensionPoint qualifiedName="Edu.studyToolWindowConfigurator" interface="com.jetbrains.edu.learning.StudyToolWindowConfigurator"/>
+    <extensionPoint qualifiedName="Edu.studyPluginConfigurator" interface="com.jetbrains.edu.learning.StudyPluginConfigurator"/>
   </extensionPoints>
 
   <actions>
                       serviceImplementation="com.jetbrains.edu.learning.StudyDocumentationManager" overrides="true"/>
     <postStartupActivity implementation="com.jetbrains.edu.learning.stepic.StudyCoursesUpdater"/>
 
-    <applicationConfigurable groupId="tools" instance="com.jetbrains.edu.learning.stepic.StudyConfigurable"
-                             id="com.jetbrains.edu.learning.stepic.StudyConfigurable"
+    <applicationConfigurable groupId="tools" instance="com.jetbrains.edu.learning.settings.StudyConfigurable"
+                             id="com.jetbrains.edu.learning.settings.StudyConfigurable"
                              displayName="Educational"/>
     <applicationService serviceInterface="com.jetbrains.edu.learning.stepic.StudySettings"
                         serviceImplementation="com.jetbrains.edu.learning.stepic.StudySettings"/>
+    <projectService serviceInterface="com.jetbrains.edu.learning.settings.PyStudySettings"
+                    serviceImplementation="com.jetbrains.edu.learning.settings.PyStudySettings"/>
 
     <toolWindow id="Task Description" anchor="right" factoryClass="com.jetbrains.edu.learning.ui.StudyToolWindowFactory" conditionClass="com.jetbrains.edu.learning.ui.StudyCondition"/>
     <toolWindow id="Course Progress" anchor="left" factoryClass="com.jetbrains.edu.learning.ui.StudyProgressToolWindowFactory" conditionClass="com.jetbrains.edu.learning.ui.StudyCondition"/>
similarity index 93%
rename from python/educational-core/student/src/com/jetbrains/edu/learning/StudyBaseToolWindowConfigurator.java
rename to python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java
index 7c118af5bccf6131cc7ff944e50fffc936282fe4..e1900e133df5a9aca738e08fb6c4ca476212031e 100644 (file)
@@ -17,7 +17,7 @@ import javax.swing.*;
 import java.util.Collections;
 import java.util.Map;
 
-public abstract class StudyBaseToolWindowConfigurator implements StudyToolWindowConfigurator {
+public abstract class StudyBasePluginConfigurator implements StudyPluginConfigurator {
   @NotNull
   @Override
   public DefaultActionGroup getActionGroup(Project project) {
@@ -87,4 +87,10 @@ public abstract class StudyBaseToolWindowConfigurator implements StudyToolWindow
       }
     };
   }
+
+  @Nullable
+  @Override
+  public StudyAfterCheckAction[] getAfterCheckActions() {
+    return null;
+  }
 }
similarity index 73%
rename from python/educational-core/student/src/com/jetbrains/edu/learning/StudyToolWindowConfigurator.java
rename to python/educational-core/student/src/com/jetbrains/edu/learning/StudyPluginConfigurator.java
index 9757d4dd0a56397b1e984abee4c72fed4e541ef2..4561c2b903aa59b2787e308e35035facddc816d1 100644 (file)
@@ -4,14 +4,17 @@ import com.intellij.openapi.actionSystem.DefaultActionGroup;
 import com.intellij.openapi.extensions.ExtensionPointName;
 import com.intellij.openapi.fileEditor.FileEditorManagerListener;
 import com.intellij.openapi.project.Project;
+import com.jetbrains.edu.learning.actions.StudyAfterCheckAction;
+import com.jetbrains.edu.learning.settings.ModifiableSettingsPanel;
 import com.jetbrains.edu.learning.ui.StudyToolWindow;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import javax.swing.*;
 import java.util.Map;
 
-public interface StudyToolWindowConfigurator {
-  ExtensionPointName<StudyToolWindowConfigurator> EP_NAME = ExtensionPointName.create("Edu.studyToolWindowConfigurator");
+public interface StudyPluginConfigurator {
+  ExtensionPointName<StudyPluginConfigurator> EP_NAME = ExtensionPointName.create("Edu.studyPluginConfigurator");
 
   /**
    * Provide action group that should be placed on the tool window toolbar.
@@ -37,9 +40,14 @@ public interface StudyToolWindowConfigurator {
    * @return parameter for CodeMirror script. Available languages: @see <@linktourl http://codemirror.net/mode/>
    */
   @NotNull String getDefaultHighlightingMode();
+
+  @Nullable
+  StudyAfterCheckAction[] getAfterCheckActions();
   
   @NotNull String getLanguageScriptUrl();
   
   boolean accept(@NotNull final Project project);
-  
+
+  @Nullable
+  ModifiableSettingsPanel getSettingsPanel();
 }
index 00c3518c529bf1a1ed21f96803fab89c94a2e7e1..940d94ce6b539e5bfdd4f415be3374aa82dc5592 100644 (file)
@@ -450,9 +450,9 @@ public class StudyUtils {
   }
   
   @Nullable
-  public static StudyToolWindowConfigurator getConfigurator(@NotNull final Project project) {
-    StudyToolWindowConfigurator[] extensions = StudyToolWindowConfigurator.EP_NAME.getExtensions();
-    for (StudyToolWindowConfigurator extension: extensions) {
+  public static StudyPluginConfigurator getConfigurator(@NotNull final Project project) {
+    StudyPluginConfigurator[] extensions = StudyPluginConfigurator.EP_NAME.getExtensions();
+    for (StudyPluginConfigurator extension: extensions) {
       if (extension.accept(project)) {
         return extension;
       }
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyAfterCheckAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyAfterCheckAction.java
new file mode 100644 (file)
index 0000000..a112e43
--- /dev/null
@@ -0,0 +1,10 @@
+package com.jetbrains.edu.learning.actions;
+
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.project.Project;
+import com.jetbrains.edu.courseFormat.Task;
+import org.jetbrains.annotations.NotNull;
+
+public abstract class StudyAfterCheckAction extends AnAction {
+  public abstract void run(@NotNull final Project project, @NotNull final Task solvedTask);
+}
index 5d332ef3ce31b617d7d848810567748ce77f3bba..5de1e25b6725224e46f9647f552b7cc0716e427f 100644 (file)
@@ -14,10 +14,12 @@ import com.intellij.openapi.vfs.VirtualFile;
 import com.jetbrains.edu.learning.core.EduUtils;
 import com.jetbrains.edu.learning.courseFormat.StudyStatus;
 import com.jetbrains.edu.learning.courseFormat.Task;
+import com.jetbrains.edu.learning.StudyPluginConfigurator;
 import com.jetbrains.edu.learning.StudyState;
 import com.jetbrains.edu.learning.StudyTaskManager;
 import com.jetbrains.edu.learning.StudyUtils;
-import com.jetbrains.edu.learning.stepic.EduStepicConnector;
+import com.jetbrains.edu.learning.actions.StudyAfterCheckAction;
+import com.jetbrains.edu.learning.EduStepicConnector;
 import com.jetbrains.edu.learning.stepic.StudySettings;
 import org.jetbrains.annotations.NotNull;
 
@@ -110,6 +112,19 @@ public class StudyCheckTask extends com.intellij.openapi.progress.Task.Backgroun
     myTaskManger.setStatus(myTask, StudyStatus.Solved);
     ApplicationManager.getApplication().invokeLater(
       () -> StudyCheckUtils.showTestResultPopUp(testsOutput.getMessage(), MessageType.INFO.getPopupBackground(), myProject));
+    runAfterTaskActions();
+  }
+
+  private void runAfterTaskActions() {
+    StudyPluginConfigurator configurator = StudyUtils.getConfigurator(myProject);
+    if (configurator != null) {
+      StudyAfterCheckAction[] checkActions = configurator.getAfterCheckActions();
+      if (checkActions != null) {
+        for (StudyAfterCheckAction action: checkActions) {
+          action.run(myProject, myTask);
+        }
+      }
+    }
   }
 
   protected void postAttemptToStepic(StudyTestsOutputParser.TestsOutput testsOutput) {
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/settings/ModifiableSettingsPanel.java b/python/educational-core/student/src/com/jetbrains/edu/learning/settings/ModifiableSettingsPanel.java
new file mode 100644 (file)
index 0000000..101fcb4
--- /dev/null
@@ -0,0 +1,19 @@
+package com.jetbrains.edu.learning.settings;
+
+
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+
+public interface ModifiableSettingsPanel {
+  void apply();
+
+  void reset();
+
+  void resetCredentialsModification();
+
+  boolean isModified();
+
+  @NotNull
+  JComponent getPanel();
+}
similarity index 84%
rename from python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StudySettingsPanel.form
rename to python/educational-core/student/src/com/jetbrains/edu/learning/settings/StudyBaseSettingsPanel.form
index d6e802b93d127d452a0c015d6536b6079ae54cb7..5ee9dc51246670685ee3b98c9eace39a4adb3196 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.edu.learning.stepic.StudySettingsPanel">
-  <grid id="27dc6" binding="myPane" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.edu.learning.settings.StudyBaseSettingsPanel">
+  <grid id="27dc6" binding="myPane" layout-manager="GridLayoutManager" row-count="3" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
     <margin top="0" left="0" bottom="0" right="0"/>
     <constraints>
       <xy x="20" y="20" width="646" height="400"/>
     <children>
       <vspacer id="6ace">
         <constraints>
-          <grid row="1" column="0" row-span="1" col-span="2" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
+          <grid row="2" column="0" row-span="1" col-span="2" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
         </constraints>
       </vspacer>
-      <grid id="bda15" binding="myCardPanel" layout-manager="CardLayout" hgap="0" vgap="0">
+      <grid id="bda15" layout-manager="CardLayout" hgap="0" vgap="0">
         <constraints>
-          <grid row="0" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+          <grid row="1" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
         </constraints>
         <properties/>
         <border type="none"/>
           </grid>
         </children>
       </grid>
+      <component id="811c0" class="com.intellij.ui.TitledSeparator">
+        <constraints>
+          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <text value="Stepic"/>
+          <titleFont size="14" style="1"/>
+        </properties>
+      </component>
     </children>
   </grid>
 </form>
similarity index 88%
rename from python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StudySettingsPanel.java
rename to python/educational-core/student/src/com/jetbrains/edu/learning/settings/StudyBaseSettingsPanel.java
index e559463c8cfdfd61d9c962460a957dcc8e3c9729..2b3135c9e65b4834c77361c7b68b508807fa63cb 100644 (file)
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.jetbrains.edu.learning.stepic;
+package com.jetbrains.edu.learning.settings;
 
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.ui.DocumentAdapter;
+import com.intellij.util.ui.UIUtil;
+import com.jetbrains.edu.learning.stepic.EduStepicConnector;
+import com.jetbrains.edu.learning.stepic.StudySettings;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -28,16 +31,15 @@ import javax.swing.text.PlainDocument;
 import java.awt.event.FocusEvent;
 import java.awt.event.FocusListener;
 
-public class StudySettingsPanel {
+public class StudyBaseSettingsPanel implements ModifiableSettingsPanel{
   private static final String DEFAULT_PASSWORD_TEXT = "************";
   private JTextField myLoginTextField;
   private JPasswordField myPasswordField;
   private JPanel myPane;
-  private JPanel myCardPanel;
 
   private boolean myCredentialsModified;
 
-  public StudySettingsPanel() {
+  public StudyBaseSettingsPanel() {
     myPasswordField.getDocument().addDocumentListener(new DocumentAdapter() {
       @Override
       protected void textChanged(DocumentEvent e) {
@@ -67,7 +69,7 @@ public class StudySettingsPanel {
       public void focusLost(FocusEvent e) {
       }
     });
-
+    myPane.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, UIUtil.getBoundsColor()));
     reset();
   }
 
@@ -76,6 +78,8 @@ public class StudySettingsPanel {
     myCredentialsModified = true;
   }
 
+  @NotNull
+  @Override
   public JComponent getPanel() {
     return myPane;
   }
@@ -98,6 +102,7 @@ public class StudySettingsPanel {
     myPasswordField.setText(StringUtil.isEmpty(password) ? null : password);
   }
 
+  @Override
   public void reset() {
     final StudySettings studySettings = StudySettings.getInstance();
     setLogin(studySettings.getLogin());
@@ -106,6 +111,7 @@ public class StudySettingsPanel {
     resetCredentialsModification();
   }
 
+  @Override
   public void apply() {
     if (myCredentialsModified) {
       final StudySettings studySettings = StudySettings.getInstance();
@@ -118,10 +124,12 @@ public class StudySettingsPanel {
     resetCredentialsModification();
   }
 
+  @Override
   public boolean isModified() {
     return myCredentialsModified;
   }
 
+  @Override
   public void resetCredentialsModification() {
     myCredentialsModified = false;
   }
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/settings/StudyConfigurable.java b/python/educational-core/student/src/com/jetbrains/edu/learning/settings/StudyConfigurable.java
new file mode 100644 (file)
index 0000000..eff51e5
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2000-2015 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.settings;
+
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.openapi.options.SearchableConfigurable;
+import com.intellij.openapi.ui.VerticalFlowLayout;
+import com.jetbrains.edu.learning.StudyPluginConfigurator;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.util.ArrayList;
+
+public class StudyConfigurable implements SearchableConfigurable {
+  public static final String ID = "com.jetbrains.edu.learning.stepic.EduConfigurable";
+  private JPanel myMainPanel;
+  private ArrayList<ModifiableSettingsPanel> myPluginsSettingsPanels;
+  private StudyBaseSettingsPanel mySettingsPanel;
+
+  public StudyConfigurable() {
+  }
+
+  @NotNull
+  @Override
+  public String getId() {
+    return ID;
+  }
+
+  @Nullable
+  @Override
+  public Runnable enableSearch(String option) {
+    return null;
+  }
+
+  @Nls
+  @Override
+  public String getDisplayName() {
+    return "Educational";
+  }
+
+  @NotNull
+  @Override
+  public String getHelpTopic() {
+    return ID;
+  }
+
+  @Nullable
+  @Override
+  public JComponent createComponent() {
+    if (myMainPanel == null) {
+      myMainPanel = new JPanel(new VerticalFlowLayout());
+    }
+    mySettingsPanel = new StudyBaseSettingsPanel();
+    myMainPanel.add(mySettingsPanel.getPanel());
+
+    myPluginsSettingsPanels = new ArrayList<>();
+    StudyPluginConfigurator[] extensions = StudyPluginConfigurator.EP_NAME.getExtensions();
+    for (StudyPluginConfigurator configurator: extensions) {
+      final ModifiableSettingsPanel settingsPanel = configurator.getSettingsPanel();
+      if (settingsPanel != null) {
+        myPluginsSettingsPanels.add(settingsPanel);
+        myMainPanel.add(settingsPanel.getPanel());
+      }
+    }
+    return myMainPanel;
+  }
+
+  @Override
+  public boolean isModified() {
+    if (mySettingsPanel != null) {
+      boolean isModified = mySettingsPanel.isModified();
+      if (myPluginsSettingsPanels != null && !myPluginsSettingsPanels.isEmpty()) {
+        for (ModifiableSettingsPanel settingsPanel: myPluginsSettingsPanels) {
+          isModified &= settingsPanel.isModified();
+        }
+      }
+      return isModified;
+    }
+    return false;
+  }
+
+  public void apply() throws ConfigurationException {
+    if (myMainPanel != null) {
+      mySettingsPanel.apply();
+      if (myPluginsSettingsPanels != null && !myPluginsSettingsPanels.isEmpty()) {
+        for (ModifiableSettingsPanel settingsPanel: myPluginsSettingsPanels) {
+          settingsPanel.apply();
+        }
+      }
+    }
+  }
+
+  public void reset() {
+    if (myMainPanel != null) {
+      mySettingsPanel.apply();
+      if (myPluginsSettingsPanels != null && !myPluginsSettingsPanels.isEmpty()) {
+        for (ModifiableSettingsPanel settingsPanel: myPluginsSettingsPanels) {
+          settingsPanel.reset();
+        }
+      }
+    }
+  }
+
+  @Override
+  public void disposeUIResources() {
+    myMainPanel = null;
+  }
+}
+
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StudyConfigurable.java b/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StudyConfigurable.java
deleted file mode 100644 (file)
index f75dc40..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright 2000-2015 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.stepic;
-
-import com.intellij.openapi.options.ConfigurationException;
-import com.intellij.openapi.options.SearchableConfigurable;
-import org.jetbrains.annotations.Nls;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-
-public class StudyConfigurable implements SearchableConfigurable {
-  public static final String ID = "com.jetbrains.edu.learning.stepic.EduConfigurable";
-  private StudySettingsPanel mySettingsPane;
-
-  public StudyConfigurable() {
-  }
-
-  @NotNull
-  @Override
-  public String getId() {
-    return ID;
-  }
-
-  @Nullable
-  @Override
-  public Runnable enableSearch(String option) {
-    return null;
-  }
-
-  @Nls
-  @Override
-  public String getDisplayName() {
-    return "Educational";
-  }
-
-  @NotNull
-  @Override
-  public String getHelpTopic() {
-    return ID;
-  }
-
-  @Nullable
-  @Override
-  public JComponent createComponent() {
-    if (mySettingsPane == null) {
-      mySettingsPane = new StudySettingsPanel();
-    }
-    return mySettingsPane.getPanel();
-  }
-
-  @Override
-  public boolean isModified() {
-    return mySettingsPane != null && mySettingsPane.isModified();
-  }
-
-  public void apply() throws ConfigurationException {
-    if (mySettingsPane != null) {
-      mySettingsPane.apply();
-    }
-  }
-
-  public void reset() {
-    if (mySettingsPane != null) {
-      mySettingsPane.reset();
-    }
-  }
-
-  @Override
-  public void disposeUIResources() {
-    mySettingsPane = null;
-  }
-}
-
index 76ad74a86f262d99a99d44be6823e6e280e5705f..c0999d9cbae699755453238fd5c51bd72ac4878f 100644 (file)
@@ -10,7 +10,7 @@ import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.editor.colors.EditorColorsManager;
 import com.intellij.openapi.editor.colors.EditorColorsScheme;
 import com.intellij.openapi.util.io.StreamUtil;
-import com.jetbrains.edu.learning.StudyToolWindowConfigurator;
+import com.jetbrains.edu.learning.StudyPluginConfigurator;
 import javafx.application.Platform;
 import javafx.concurrent.Worker;
 import javafx.embed.swing.JFXPanel;
@@ -124,7 +124,7 @@ class StudyBrowserWindow extends JFrame {
     });
   }
 
-  public void loadContent(@NotNull final String content, StudyToolWindowConfigurator configurator) {
+  public void loadContent(@NotNull final String content, StudyPluginConfigurator configurator) {
     String withCodeHighlighting = createHtmlWithCodeHighlighting(content, configurator);
     Platform.runLater(()-> {
         updateLookWithProgressBarIfNeeded();
@@ -133,7 +133,7 @@ class StudyBrowserWindow extends JFrame {
   }
 
   @Nullable
-  private String createHtmlWithCodeHighlighting(@NotNull final String content, @NotNull StudyToolWindowConfigurator configurator) {
+  private String createHtmlWithCodeHighlighting(@NotNull final String content, @NotNull StudyPluginConfigurator configurator) {
     String template = null;
     InputStream stream = getClass().getResourceAsStream("/code-mirror/template.html");
     try {
index 873c987da77dc652e89fc6af9b5efebcbe69592f..c215dc86eed4152d4151b4c59fd1732245e4301c 100644 (file)
@@ -16,7 +16,7 @@
 package com.jetbrains.edu.learning.ui;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.project.ProjectUtil;
-import com.jetbrains.edu.learning.StudyToolWindowConfigurator;
+import com.jetbrains.edu.learning.StudyPluginConfigurator;
 import com.jetbrains.edu.learning.StudyUtils;
 
 import javax.swing.*;
@@ -41,7 +41,7 @@ public class StudyJavaFxToolWindow extends StudyToolWindow {
 
   @Override
   public void setTaskText(String text) {
-    StudyToolWindowConfigurator configurator = StudyUtils.getConfigurator(ProjectUtil.guessCurrentProject(this));
+    StudyPluginConfigurator configurator = StudyUtils.getConfigurator(ProjectUtil.guessCurrentProject(this));
     if (configurator != null) {
       myBrowserWindow.loadContent(text, configurator);
     }
index 0230fa10c5af514e7ac4abd3587bd83db4156e7b..28671186339ab9fb3587bad03ac091c334290006 100644 (file)
@@ -28,8 +28,10 @@ import com.intellij.ui.JBCardLayout;
 import com.intellij.ui.OnePixelSplitter;
 import com.intellij.util.ui.JBUI;
 import com.jetbrains.edu.learning.courseFormat.Course;
+import com.jetbrains.edu.learning.courseFormat.Task;
+import com.jetbrains.edu.learning.courseFormat.TaskFile;
+import com.jetbrains.edu.learning.StudyPluginConfigurator;
 import com.jetbrains.edu.learning.StudyTaskManager;
-import com.jetbrains.edu.learning.StudyToolWindowConfigurator;
 import com.jetbrains.edu.learning.StudyUtils;
 import org.jetbrains.annotations.NotNull;
 
@@ -65,14 +67,14 @@ public abstract class StudyToolWindow extends SimpleToolWindowPanel implements D
 
     setContent(mySplitPane);
 
-    StudyToolWindowConfigurator configurator = StudyUtils.getConfigurator(project);
+    StudyPluginConfigurator configurator = StudyUtils.getConfigurator(project);
     assert configurator != null;
     final FileEditorManagerListener listener = configurator.getFileEditorManagerListener(project, this);
     project.getMessageBus().connect().subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, listener);
   }
 
   private void addAdditionalPanels(Project project) {
-    StudyToolWindowConfigurator configurator = StudyUtils.getConfigurator(project);
+    StudyPluginConfigurator configurator = StudyUtils.getConfigurator(project);
     assert configurator != null;
     Map<String, JPanel> panels = configurator.getAdditionalPanels(project);
     for (Map.Entry<String, JPanel> entry: panels.entrySet()) {
@@ -129,7 +131,7 @@ public abstract class StudyToolWindow extends SimpleToolWindowPanel implements D
       LOG.warn("Course is null");
       return new DefaultActionGroup();
     }
-    StudyToolWindowConfigurator configurator = StudyUtils.getConfigurator(project);
+    StudyPluginConfigurator configurator = StudyUtils.getConfigurator(project);
     assert configurator != null;
 
     return configurator.getActionGroup(project);
index a6c07367a4598d4333c053ca821db1be428338be..3828c747c81ba1fa361964a18964a8d7c2ab9e09 100644 (file)
@@ -33,7 +33,7 @@
   <extensions defaultExtensionNs="Edu">
     <StudyExecutor implementationClass="com.jetbrains.edu.learning.PyStudyExecutor" language="Python"/>
     <StudyLanguageManager implementationClass="com.jetbrains.edu.learning.PyStudyLanguageManager" language="Python"/>
-    <studyToolWindowConfigurator implementation="com.jetbrains.edu.learning.PyStudyToolWindowConfigurator" />
+    <studyPluginConfigurator implementation="com.jetbrains.edu.learning.PyStudyPluginConfigurator" />
   </extensions>
   <actions>
     <action id="WelcomeScreen.PythonIntro" class="com.jetbrains.edu.learning.actions.PyStudyIntroductionCourseAction"
similarity index 63%
rename from python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyToolWindowConfigurator.java
rename to python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyPluginConfigurator.java
index 70fd8ba7faf6017892f896be0b22603c9152a524..e5e6dbec1dafce27064308760904361f1c96f8a9 100644 (file)
@@ -3,9 +3,14 @@ package com.jetbrains.edu.learning;
 import com.intellij.openapi.actionSystem.DefaultActionGroup;
 import com.intellij.openapi.project.Project;
 import com.jetbrains.edu.learning.courseFormat.Course;
+import com.jetbrains.edu.learning.actions.PyTwitterAction;
+import com.jetbrains.edu.learning.actions.StudyAfterCheckAction;
+import com.jetbrains.edu.learning.settings.ModifiableSettingsPanel;
+import com.jetbrains.edu.learning.settings.PySettingsPanel;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
-public class PyStudyToolWindowConfigurator extends StudyBaseToolWindowConfigurator {
+public class PyStudyPluginConfigurator extends StudyBasePluginConfigurator {
   
   @NotNull
   @Override
@@ -29,6 +34,12 @@ public class PyStudyToolWindowConfigurator extends StudyBaseToolWindowConfigurat
     return getClass().getResource("/python.js").toExternalForm();
   }
 
+  @Nullable
+  @Override
+  public StudyAfterCheckAction[] getAfterCheckActions() {
+    return new StudyAfterCheckAction[]{new PyTwitterAction()};
+  }
+
   @Override
   public boolean accept(@NotNull Project project) {
     StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
@@ -36,4 +47,10 @@ public class PyStudyToolWindowConfigurator extends StudyBaseToolWindowConfigurat
     Course course = taskManager.getCourse();
     return course != null && "Python".equals(course.getLanguage()) && "PyCharm".equals(course.getCourseType());
   }
+
+  @Nullable
+  @Override
+  public ModifiableSettingsPanel getSettingsPanel() {
+    return new PySettingsPanel();
+  }
 }
diff --git a/python/educational-python/student-python/src/com/jetbrains/edu/learning/settings/PySettingsPanel.form b/python/educational-python/student-python/src/com/jetbrains/edu/learning/settings/PySettingsPanel.form
new file mode 100644 (file)
index 0000000..a51a16c
--- /dev/null
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.edu.learning.settings.PySettingsPanel">
+  <grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="3" column-count="4" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+    <margin top="0" left="0" bottom="0" right="0"/>
+    <constraints>
+      <xy x="20" y="20" width="500" height="400"/>
+    </constraints>
+    <properties/>
+    <border type="none"/>
+    <children>
+      <vspacer id="d7660">
+        <constraints>
+          <grid row="2" column="0" row-span="1" col-span="4" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
+        </constraints>
+      </vspacer>
+      <component id="62464" class="com.intellij.ui.components.JBLabel">
+        <constraints>
+          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <text value="Ask to tweet after lesson completion"/>
+        </properties>
+      </component>
+      <component id="ba733" class="com.intellij.ui.TitledSeparator">
+        <constraints>
+          <grid row="0" column="0" row-span="1" col-span="4" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <text value="Python"/>
+          <titleFont size="14" style="1"/>
+        </properties>
+        <clientProperties>
+          <BorderFactoryClass class="java.lang.String" value=""/>
+          <html.disable class="java.lang.Boolean" value="false"/>
+        </clientProperties>
+      </component>
+      <component id="1740e" class="com.intellij.ui.components.JBCheckBox" binding="myAskToTweetCheckBox">
+        <constraints>
+          <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <selected value="true"/>
+        </properties>
+      </component>
+      <hspacer id="d7ecb">
+        <constraints>
+          <grid row="1" column="2" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+        </constraints>
+      </hspacer>
+    </children>
+  </grid>
+</form>
diff --git a/python/educational-python/student-python/src/com/jetbrains/edu/learning/settings/PySettingsPanel.java b/python/educational-python/student-python/src/com/jetbrains/edu/learning/settings/PySettingsPanel.java
new file mode 100644 (file)
index 0000000..240b567
--- /dev/null
@@ -0,0 +1,48 @@
+package com.jetbrains.edu.learning.settings;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ProjectUtil;
+import com.intellij.ui.components.JBCheckBox;
+import com.intellij.util.ui.UIUtil;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+
+
+public class PySettingsPanel implements ModifiableSettingsPanel{
+  private JBCheckBox myAskToTweetCheckBox;
+  private JPanel myPanel;
+  private boolean myIsModified = false;
+
+  public PySettingsPanel() {
+    myAskToTweetCheckBox.addActionListener(e -> myIsModified = true);
+    myAskToTweetCheckBox.setSelected(PyStudySettings.getInstance(ProjectUtil.guessCurrentProject(myPanel)).askToTweet());
+    myPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, UIUtil.getBoundsColor()));
+  }
+
+  @Override
+  public void apply() {
+    Project project = ProjectUtil.guessCurrentProject(myPanel);
+    PyStudySettings.getInstance(project).setAskToTweet(myAskToTweetCheckBox.isSelected());
+  }
+
+  @Override
+  public void reset() {
+    Project project = ProjectUtil.guessCurrentProject(myPanel);
+    PyStudySettings.getInstance(project).setAskToTweet(true);
+  }
+
+  @Override
+  public void resetCredentialsModification() {
+    myIsModified = false;
+  }
+
+  @Override
+  public boolean isModified() {
+    return myIsModified;
+  }
+
+  @NotNull
+  public JPanel getPanel() {
+    return myPanel;
+  }
+}
diff --git a/python/educational-python/student-python/src/com/jetbrains/edu/learning/settings/PyStudySettings.java b/python/educational-python/student-python/src/com/jetbrains/edu/learning/settings/PyStudySettings.java
new file mode 100644 (file)
index 0000000..b2bc22b
--- /dev/null
@@ -0,0 +1,43 @@
+package com.jetbrains.edu.learning.settings;
+
+import com.intellij.openapi.components.PersistentStateComponent;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.components.State;
+import com.intellij.openapi.components.Storage;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+@SuppressWarnings("MethodMayBeStatic")
+@State(name = "PyStudySettings", storages = @Storage("py_study_settings.xml"))
+public class PyStudySettings implements PersistentStateComponent<PyStudySettings.State> {
+
+  private State myState = new State();
+
+
+  public static class State {
+    public boolean askToTweet = true;
+  }
+
+  public static PyStudySettings getInstance(@NotNull final Project project) {
+    return ServiceManager.getService(project, PyStudySettings.class);
+  }
+  @Nullable
+  @Override
+  public State getState() {
+    return myState;
+  }
+
+  @Override
+  public void loadState(State state) {
+    myState = state;
+  }
+  
+  public boolean askToTweet() {
+    return myState.askToTweet;
+  }
+  
+  public void setAskToTweet(final boolean askToTweet) {
+    myState.askToTweet = askToTweet;
+  }
+}
\ No newline at end of file