Minor Refresh project view on adding new recommendation, fix NPE in postAttemptToStepic
[idea/community.git] / python / educational-core / student / src / com / jetbrains / edu / learning / ui / StudyToolWindow.java
1 /*
2  * Copyright 2000-2015 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.jetbrains.edu.learning.ui;
17
18 import com.intellij.openapi.Disposable;
19 import com.intellij.openapi.actionSystem.ActionManager;
20 import com.intellij.openapi.actionSystem.ActionToolbar;
21 import com.intellij.openapi.actionSystem.DataProvider;
22 import com.intellij.openapi.actionSystem.DefaultActionGroup;
23 import com.intellij.openapi.diagnostic.Logger;
24 import com.intellij.openapi.fileEditor.FileEditorManagerListener;
25 import com.intellij.openapi.progress.ProgressIndicator;
26 import com.intellij.openapi.progress.ProgressManager;
27 import com.intellij.openapi.progress.Task;
28 import com.intellij.openapi.progress.util.ProgressIndicatorBase;
29 import com.intellij.openapi.project.Project;
30 import com.intellij.openapi.project.ProjectUtil;
31 import com.intellij.openapi.ui.SimpleToolWindowPanel;
32 import com.intellij.ui.JBCardLayout;
33 import com.intellij.ui.JBColor;
34 import com.intellij.ui.OnePixelSplitter;
35 import com.intellij.util.ui.JBUI;
36 import com.intellij.util.ui.UIUtil;
37 import com.jetbrains.edu.learning.StudyBasePluginConfigurator;
38 import com.jetbrains.edu.learning.StudyPluginConfigurator;
39 import com.jetbrains.edu.learning.StudyTaskManager;
40 import com.jetbrains.edu.learning.StudyUtils;
41 import com.jetbrains.edu.learning.courseFormat.Course;
42 import com.jetbrains.edu.learning.stepic.EduAdaptiveStepicConnector;
43 import org.jetbrains.annotations.NotNull;
44
45 import javax.swing.*;
46 import java.awt.*;
47 import java.awt.event.MouseAdapter;
48 import java.awt.event.MouseEvent;
49 import java.util.Map;
50
51 public abstract class StudyToolWindow extends SimpleToolWindowPanel implements DataProvider, Disposable {
52   private static final Logger LOG = Logger.getInstance(StudyToolWindow.class);
53   private static final String TASK_INFO_ID = "taskInfo";
54   private final JBCardLayout myCardLayout;
55   private final JPanel myContentPanel;
56   private final OnePixelSplitter mySplitPane;
57
58   public StudyToolWindow() {
59     super(true, true);
60     myCardLayout = new JBCardLayout();
61     myContentPanel = new JPanel(myCardLayout);
62     mySplitPane = new OnePixelSplitter(myVertical=true);
63   }
64
65   public void init(Project project) {
66     String taskText = StudyUtils.getTaskText(project);
67     if (taskText == null) return;
68
69     JPanel toolbarPanel = createToolbarPanel(project);
70     setToolbar(toolbarPanel);
71
72     final JPanel panel = new JPanel(new BorderLayout());
73     final Course course = StudyTaskManager.getInstance(project).getCourse();
74     if (course != null && course.isAdaptive()) {
75       panel.add(createReactionPanel(), BorderLayout.NORTH);
76     }
77     JComponent taskInfoPanel = createTaskInfoPanel(taskText, project);
78     panel.add(taskInfoPanel, BorderLayout.CENTER);
79     myContentPanel.add(TASK_INFO_ID, panel);
80     mySplitPane.setFirstComponent(myContentPanel);
81     addAdditionalPanels(project);
82     myCardLayout.show(myContentPanel, TASK_INFO_ID);
83
84     setContent(mySplitPane);
85
86     StudyPluginConfigurator configurator = StudyUtils.getConfigurator(project);
87     if (configurator != null) {
88       final FileEditorManagerListener listener = configurator.getFileEditorManagerListener(project, this);
89       project.getMessageBus().connect().subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, listener);
90     }
91   }
92
93   private void addAdditionalPanels(Project project) {
94     StudyPluginConfigurator configurator = StudyUtils.getConfigurator(project);
95     if (configurator != null) {
96       Map<String, JPanel> panels = configurator.getAdditionalPanels(project);
97       for (Map.Entry<String, JPanel> entry : panels.entrySet()) {
98         myContentPanel.add(entry.getKey(), entry.getValue());
99       }
100     }
101   }
102   
103   public JPanel createReactionPanel() {
104     final JPanel panel = new JPanel(new GridBagLayout());
105     panel.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, JBColor.border()));
106     final JPanel hardPanel = new JPanel(new BorderLayout());
107     hardPanel.add(new JLabel("Too hard"), BorderLayout.CENTER);
108     hardPanel.setBorder(BorderFactory.createEtchedBorder());
109
110     final JPanel boringPanel = new JPanel(new BorderLayout());
111     boringPanel.setBorder(BorderFactory.createEtchedBorder());
112     boringPanel.add(new JLabel("Too boring"), BorderLayout.CENTER);
113
114     final GridBagConstraints c = new GridBagConstraints();
115     c.fill  = GridBagConstraints.HORIZONTAL;
116     c.gridx = 0;
117     c.gridy = 0;
118     c.weightx = 1;
119     panel.add(hardPanel, c);
120     c.gridx =  1;
121     panel.add(boringPanel, c);
122     c.gridy = 1;
123     c.weightx = 1;
124     panel.add(Box.createVerticalBox(), c);
125
126     final Project project = ProjectUtil.guessCurrentProject(myContentPanel);
127     addMouseListener(hardPanel, () -> EduAdaptiveStepicConnector.addNextRecommendedTask(project, 0));
128     addMouseListener(boringPanel, () -> EduAdaptiveStepicConnector.addNextRecommendedTask(project, -1));
129     
130     return panel;
131   }
132
133   private static void addMouseListener(@NotNull final JPanel panel, @NotNull Runnable onClickAction ) {
134     panel.addMouseListener(new MouseAdapter() {
135       @Override
136       public void mouseClicked(MouseEvent e) {
137         if (e.getClickCount() == 1) {
138           final ProgressIndicatorBase progress = new ProgressIndicatorBase();
139           progress.setText("Loading Next Recommendation");
140           ProgressManager.getInstance().run(new Task.Backgroundable(ProjectUtil.guessCurrentProject(panel),
141                                                                     "Loading Next Recommendation") {
142
143             @Override
144             public void run(@NotNull ProgressIndicator indicator) {
145               onClickAction.run();
146             }
147           });
148         }
149       }
150
151       @Override
152       public void mouseEntered(MouseEvent e) {
153         panel.setBackground(UIUtil.getTreeSelectionBackground());
154       }
155
156       @Override
157       public void mouseExited(MouseEvent e) {
158         panel.setBackground(UIUtil.getLabelBackground());
159       }
160     });
161   }
162   
163   public void dispose() {
164   }
165   
166   //used in checkiO plugin.
167   @SuppressWarnings("unused")
168   public void showPanelById(@NotNull final String panelId) {
169     myCardLayout.swipe(myContentPanel, panelId, JBCardLayout.SwipeDirection.AUTO);
170   }
171
172   //used in checkiO plugin.
173   @SuppressWarnings("unused")
174   public void setBottomComponent(JComponent component) {
175     mySplitPane.setSecondComponent(component);
176   }
177
178   //used in checkiO plugin.
179   @SuppressWarnings("unused")
180   public JComponent getBottomComponent() {
181     return mySplitPane.getSecondComponent();
182   }
183
184   //used in checkiO plugin.
185   @SuppressWarnings("unused")
186   public void setTopComponentPrefferedSize(@NotNull final Dimension dimension) {
187     myContentPanel.setPreferredSize(dimension);
188   }
189
190   //used in checkiO plugin.
191   @SuppressWarnings("unused")
192   public JPanel getContentPanel() {
193     return myContentPanel;
194   }
195
196
197   public abstract JComponent createTaskInfoPanel(String taskText, Project project);
198
199   private static JPanel createToolbarPanel(@NotNull final Project project) {
200     final DefaultActionGroup group = getActionGroup(project);
201
202     final ActionToolbar actionToolBar = ActionManager.getInstance().createActionToolbar("Study", group, true);
203     return JBUI.Panels.simplePanel(actionToolBar.getComponent());
204   }
205
206   private static DefaultActionGroup getActionGroup(@NotNull final Project project) {
207     Course course = StudyTaskManager.getInstance(project).getCourse();
208     if (course == null) {
209       LOG.warn("Course is null");
210       return new DefaultActionGroup();
211     }
212     StudyPluginConfigurator configurator = StudyUtils.getConfigurator(project);
213     if (configurator != null) {
214       return configurator.getActionGroup(project);
215     }
216     else {
217       LOG.warn("No configurator is provided for plugin");
218       return StudyBasePluginConfigurator.getDefaultActionGroup();
219     }
220   }
221
222   public abstract void setTaskText(@NotNull String text);
223 }