c9e625ea237059e95382e53b35ea1547d00b6ddd
[idea/community.git] / python / educational-core / student / src / com / jetbrains / edu / learning / stepic / StepicAdaptiveReactionsPanel.java
1 package com.jetbrains.edu.learning.stepic;
2
3 import com.intellij.openapi.application.ApplicationManager;
4 import com.intellij.openapi.fileEditor.FileEditorManager;
5 import com.intellij.openapi.fileEditor.FileEditorManagerEvent;
6 import com.intellij.openapi.fileEditor.FileEditorManagerListener;
7 import com.intellij.openapi.progress.ProgressIndicator;
8 import com.intellij.openapi.progress.ProgressManager;
9 import com.intellij.openapi.progress.Task;
10 import com.intellij.openapi.progress.util.ProgressIndicatorBase;
11 import com.intellij.openapi.project.Project;
12 import com.intellij.openapi.vfs.VirtualFile;
13 import com.intellij.ui.JBColor;
14 import com.intellij.util.ui.UIUtil;
15 import com.jetbrains.edu.learning.StudyUtils;
16 import com.jetbrains.edu.learning.courseFormat.StudyStatus;
17 import org.jetbrains.annotations.NotNull;
18
19 import javax.swing.*;
20 import java.awt.*;
21 import java.awt.event.MouseAdapter;
22 import java.awt.event.MouseEvent;
23
24
25 public class StepicAdaptiveReactionsPanel extends JPanel {
26   private final ReactionButtonPanel myHardPanel;
27   private final ReactionButtonPanel myBoringPanel;
28   @NotNull private final Project myProject;
29   private static final int TOO_HARD_REACTION = 0;
30   private static final int TOO_BORING_REACTION = -1;
31   private static final String HARD_REACTION = "Too Hard";
32   private static final String BORING_REACTION = "Too Boring";
33   private static final String SOLVED_TASK_TOOLTIP = "Reaction Disabled Due To Task Is Solved";
34   private static final String HARD_LABEL_TOOLTIP = "Click To Get An Easier Task";
35   private static final String BORING_LABEL_TOOLTIP = "Click To Get A More Challenging Task";
36
37   public StepicAdaptiveReactionsPanel(@NotNull final Project project) {
38     myProject = project;
39     setLayout(new GridBagLayout());
40     setBackground(UIUtil.getTextFieldBackground());
41
42     myHardPanel = new ReactionButtonPanel(HARD_REACTION, HARD_LABEL_TOOLTIP, TOO_HARD_REACTION);
43     myBoringPanel = new ReactionButtonPanel(BORING_REACTION, BORING_LABEL_TOOLTIP, TOO_BORING_REACTION);
44     addFileListener();
45
46     final GridBagConstraints c = new GridBagConstraints();
47     c.fill = GridBagConstraints.HORIZONTAL;
48     c.gridx = 0;
49     c.gridy = 0;
50     add(Box.createVerticalStrut(3), c);
51     c.gridx = 1;
52     c.gridy = 1;
53     add(Box.createHorizontalStrut(3), c);
54     c.weightx = 1;
55     c.gridx = 2;
56     add(myHardPanel, c);
57     c.gridx = 3;
58     c.weightx = 0;
59     add(Box.createHorizontalStrut(3), c);
60     c.weightx = 1;
61     c.gridx = 4;
62     add(myBoringPanel, c);
63     c.gridx = 5;
64     c.weightx = 0;
65     add(Box.createHorizontalStrut(3), c);
66   }
67
68   public void setEnabledRecursive(final boolean isEnabled) {
69     ApplicationManager.getApplication().invokeLater(() -> {
70       super.setEnabled(isEnabled);
71       myHardPanel.setEnabledRecursive(isEnabled);
72       myBoringPanel.setEnabledRecursive(isEnabled);
73     });
74   }
75
76   private void addFileListener() {
77     final FileEditorManagerListener editorManagerListener = new FileEditorManagerListener() {
78       @Override
79       public void fileOpened(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
80       }
81
82       @Override
83       public void fileClosed(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
84
85       }
86
87       @Override
88       public void selectionChanged(@NotNull FileEditorManagerEvent event) {
89         final com.jetbrains.edu.learning.courseFormat.Task task = StudyUtils.getTaskFromSelectedEditor(myProject);
90         final boolean isEnabled = task != null && task.getStatus() != StudyStatus.Solved;
91         StepicAdaptiveReactionsPanel.this.setEnabledRecursive(isEnabled);
92       }
93     };
94     myProject.getMessageBus().connect().subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, editorManagerListener);
95   }
96
97   private class ReactionButtonPanel extends JPanel {
98     private final JPanel myButtonPanel;
99     private final JLabel myLabel;
100
101     public ReactionButtonPanel(@NotNull final String text,
102                                @NotNull final String enabledTooltip,
103                                int reaction) {
104       com.jetbrains.edu.learning.courseFormat.Task task = StudyUtils.getTaskFromSelectedEditor(myProject);
105       final boolean isEnabled = task != null && task.getStatus() != StudyStatus.Solved;
106
107       myLabel = new JLabel(text);
108
109       myButtonPanel = new JPanel();
110       myButtonPanel.setLayout(new BoxLayout(myButtonPanel, BoxLayout.PAGE_AXIS));
111       myButtonPanel.setToolTipText(isEnabled && task.getStatus() == StudyStatus.Solved ? enabledTooltip : SOLVED_TASK_TOOLTIP);
112       myButtonPanel.add(Box.createVerticalStrut(5));
113       myButtonPanel.add(myLabel);
114       myButtonPanel.add(Box.createVerticalStrut(5));
115
116       setEnabledRecursive(isEnabled);
117
118       setLayout(new GridBagLayout());
119       setBorder(BorderFactory.createEtchedBorder());
120       add(myButtonPanel);
121       addMouseListener(reaction);
122     }
123
124     private void addMouseListener(int reaction) {
125       final ReactionMouseAdapter mouseAdapter = new ReactionMouseAdapter(this, reaction);
126       this.addMouseListener(mouseAdapter);
127       myButtonPanel.addMouseListener(mouseAdapter);
128       myLabel.addMouseListener(mouseAdapter);
129     }
130
131     public void setEnabledRecursive(final boolean isEnabled) {
132       ApplicationManager.getApplication().invokeLater(() -> {
133         super.setEnabled(isEnabled);
134         myButtonPanel.setEnabled(isEnabled);
135         myLabel.setEnabled(isEnabled);
136       });
137     }
138
139     private class ReactionMouseAdapter extends MouseAdapter {
140       private final ReactionButtonPanel myPanel;
141       private final int myReaction;
142
143       public ReactionMouseAdapter(@NotNull final ReactionButtonPanel mainPanel, int reaction) {
144         myReaction = reaction;
145         myPanel = mainPanel;
146       }
147
148       @Override
149       public void mouseClicked(MouseEvent e) {
150         if (e.getClickCount() == 1 && isEnabled()) {
151           final com.jetbrains.edu.learning.courseFormat.Task task = StudyUtils.getCurrentTask(myProject);
152           if (task != null && task.getStatus() != StudyStatus.Solved) {
153             final ProgressIndicatorBase progress = new ProgressIndicatorBase();
154             progress.setText("Loading Next Recommendation");
155             ProgressManager.getInstance().run(new Task.Backgroundable(myProject,
156                                                                       "Loading Next Recommendation") {
157               @Override
158               public void run(@NotNull ProgressIndicator indicator) {
159                 StepicAdaptiveReactionsPanel.this.setEnabledRecursive(false);
160                 ApplicationManager.getApplication().invokeLater(()->setBackground(UIUtil.getLabelBackground()));
161                 EduAdaptiveStepicConnector.addNextRecommendedTask(myProject, myReaction, indicator);
162                 StepicAdaptiveReactionsPanel.this.setEnabledRecursive(true);
163               }
164             });
165           }
166         }
167       }
168
169       @Override
170       public void mouseEntered(MouseEvent e) {
171         final com.jetbrains.edu.learning.courseFormat.Task task = StudyUtils.getCurrentTask(myProject);
172         if (task != null && task.getStatus() != StudyStatus.Solved && myPanel.isEnabled()) {
173           setBackground(JBColor.GRAY);
174         }
175       }
176
177       @Override
178       public void mouseExited(MouseEvent e) {
179         setBackground(UIUtil.getLabelBackground());
180       }
181
182       private void setBackground(Color color) {
183         myPanel.setBackground(color);
184         myButtonPanel.setBackground(color);
185       }
186     }
187   }
188 }
189