* 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
<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"/>
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) {
}
};
}
+
+ @Nullable
+ @Override
+ public StudyAfterCheckAction[] getAfterCheckActions() {
+ return null;
+ }
}
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.
* @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();
}
}
@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;
}
--- /dev/null
+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);
+}
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;
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) {
--- /dev/null
+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();
+}
<?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>
* 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;
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) {
public void focusLost(FocusEvent e) {
}
});
-
+ myPane.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, UIUtil.getBoundsColor()));
reset();
}
myCredentialsModified = true;
}
+ @NotNull
+ @Override
public JComponent getPanel() {
return myPane;
}
myPasswordField.setText(StringUtil.isEmpty(password) ? null : password);
}
+ @Override
public void reset() {
final StudySettings studySettings = StudySettings.getInstance();
setLogin(studySettings.getLogin());
resetCredentialsModification();
}
+ @Override
public void apply() {
if (myCredentialsModified) {
final StudySettings studySettings = StudySettings.getInstance();
resetCredentialsModification();
}
+ @Override
public boolean isModified() {
return myCredentialsModified;
}
+ @Override
public void resetCredentialsModification() {
myCredentialsModified = false;
}
--- /dev/null
+/*
+ * 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;
+ }
+}
+
+++ /dev/null
-/*
- * 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;
- }
-}
-
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;
});
}
- 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();
}
@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 {
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.*;
@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);
}
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;
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()) {
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);
<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"
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
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);
Course course = taskManager.getCourse();
return course != null && "Python".equals(course.getLanguage()) && "PyCharm".equals(course.getCourseType());
}
+
+ @Nullable
+ @Override
+ public ModifiableSettingsPanel getSettingsPanel() {
+ return new PySettingsPanel();
+ }
}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.edu.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>
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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