b37224e6a80fd402da6f12b4a6e0892d35b73045
[idea/community.git] / python / educational-core / student / src / com / jetbrains / edu / learning / ui / StudyNewProjectPanel.java
1 package com.jetbrains.edu.learning.ui;
2
3 import com.intellij.facet.ui.FacetValidatorsManager;
4 import com.intellij.facet.ui.ValidationResult;
5 import com.intellij.icons.AllIcons;
6 import com.intellij.openapi.fileChooser.FileChooser;
7 import com.intellij.openapi.fileChooser.FileChooserDescriptor;
8 import com.intellij.openapi.ui.DialogWrapper;
9 import com.intellij.openapi.ui.popup.JBPopupFactory;
10 import com.intellij.openapi.ui.popup.ListPopup;
11 import com.intellij.openapi.ui.popup.PopupStep;
12 import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
13 import com.intellij.openapi.util.text.StringUtil;
14 import com.intellij.openapi.vfs.VirtualFile;
15 import com.intellij.util.Consumer;
16 import com.jetbrains.edu.learning.courseFormat.Course;
17 import com.jetbrains.edu.learning.StudyUtils;
18 import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator;
19 import com.jetbrains.edu.learning.stepic.CourseInfo;
20 import com.jetbrains.edu.learning.stepic.EduStepicConnector;
21 import com.jetbrains.edu.learning.stepic.StudySettings;
22 import icons.InteractiveLearningIcons;
23 import org.jetbrains.annotations.NotNull;
24 import org.jetbrains.annotations.Nullable;
25
26 import javax.swing.*;
27 import java.awt.*;
28 import java.awt.event.ActionEvent;
29 import java.awt.event.ActionListener;
30 import java.util.ArrayList;
31 import java.util.List;
32
33 /**
34  * author: liana
35  * data: 7/31/14.
36  */
37 public class StudyNewProjectPanel{
38   private List<CourseInfo> myAvailableCourses = new ArrayList<CourseInfo>();
39   private JButton myBrowseButton;
40   private JComboBox myCoursesComboBox;
41   private JButton myRefreshButton;
42   private JPanel myContentPanel;
43   private JLabel myAuthorLabel;
44   private JLabel myLabel;
45   private JPanel myInfoPanel;
46   private JTextPane myDescriptionLabel;
47   private final StudyProjectGenerator myGenerator;
48   private static final String CONNECTION_ERROR = "<html>Failed to download courses.<br>Check your Internet connection.</html>";
49   private static final String INVALID_COURSE = "Selected course is invalid";
50   private FacetValidatorsManager myValidationManager;
51
52   public StudyNewProjectPanel(StudyProjectGenerator generator) {
53     myGenerator = generator;
54     myAvailableCourses = myGenerator.getCourses(false);
55     myBrowseButton.setPreferredSize(new Dimension(28, 28));
56     myRefreshButton.setPreferredSize(new Dimension(28, 28));
57     if (myAvailableCourses.isEmpty()) {
58       setError(CONNECTION_ERROR);
59     }
60     else {
61       for (CourseInfo courseInfo : myAvailableCourses) {
62         myCoursesComboBox.addItem(courseInfo);
63       }
64       final CourseInfo selectedCourse = StudyUtils.getFirst(myAvailableCourses);
65       final String authorsString = Course.getAuthorsString(selectedCourse.getAuthors());
66       myAuthorLabel.setText(!StringUtil.isEmptyOrSpaces(authorsString) ? "Author: " + authorsString : "");
67       myDescriptionLabel.setText(selectedCourse.getDescription());
68       myDescriptionLabel.setEditable(false);
69       //setting the first course in list as selected
70       myGenerator.setSelectedCourse(selectedCourse);
71       setOK();
72     }
73     initListeners();
74     myRefreshButton.setVisible(true);
75     myRefreshButton.putClientProperty("JButton.buttonType", "null");
76     myRefreshButton.setIcon(AllIcons.Actions.Refresh);
77
78     myLabel.setPreferredSize(new JLabel("Project name").getPreferredSize());
79
80   }
81
82   private void setupBrowseButton() {
83     myBrowseButton.putClientProperty("JButton.buttonType", "null");
84     myBrowseButton.setIcon(InteractiveLearningIcons.InterpreterGear);
85     final FileChooserDescriptor fileChooser = new FileChooserDescriptor(true, false, false, true, false, false) {
86       @Override
87       public boolean isFileVisible(VirtualFile file, boolean showHiddenFiles) {
88         return file.isDirectory() || StudyUtils.isZip(file.getName());
89       }
90
91       @Override
92       public boolean isFileSelectable(VirtualFile file) {
93         return StudyUtils.isZip(file.getName());
94       }
95     };
96     myBrowseButton.addActionListener(new ActionListener() {
97       public void actionPerformed(ActionEvent e) {
98         final BaseListPopupStep<String> popupStep = new BaseListPopupStep<String>("", "Add local course", "Load private courses") {
99           @Override
100           public PopupStep onChosen(final String selectedValue, boolean finalChoice) {
101             return doFinalStep(new Runnable() {
102               public void run() {
103                 if ("Add local course".equals(selectedValue)) {
104                   FileChooser.chooseFile(fileChooser, null, null,
105                                          new Consumer<VirtualFile>() {
106                                            @Override
107                                            public void consume(VirtualFile file) {
108                                              String fileName = file.getPath();
109                                              int oldSize = myAvailableCourses.size();
110                                              CourseInfo courseInfo = myGenerator.addLocalCourse(fileName);
111                                              if (courseInfo != null) {
112                                                if (oldSize != myAvailableCourses.size()) {
113                                                  myCoursesComboBox.addItem(courseInfo);
114                                                }
115                                                myCoursesComboBox.setSelectedItem(courseInfo);
116                                                setOK();
117                                              }
118                                              else {
119                                                setError(INVALID_COURSE);
120                                                myCoursesComboBox.removeAllItems();
121                                                myCoursesComboBox.addItem(CourseInfo.INVALID_COURSE);
122                                                for (CourseInfo course : myAvailableCourses) {
123                                                  myCoursesComboBox.addItem(course);
124                                                }
125                                                myCoursesComboBox.setSelectedItem(CourseInfo.INVALID_COURSE);
126                                              }
127                                            }
128                                          });
129                 }
130                 else if ("Load private courses".equals(selectedValue)) {
131                   final AddRemoteDialog dialog = new AddRemoteDialog();
132                   dialog.show();
133                 }
134               }
135             });
136           }
137         };
138         final ListPopup popup = JBPopupFactory.getInstance().createListPopup(popupStep);
139         popup.showInScreenCoordinates(myBrowseButton, myBrowseButton.getLocationOnScreen());
140       }
141     });
142   }
143
144   private void initListeners() {
145     myRefreshButton.addActionListener(new RefreshActionListener());
146     myCoursesComboBox.addActionListener(new CourseSelectedListener());
147     setupBrowseButton();
148   }
149
150   private void setError(@NotNull final String errorMessage) {
151     myGenerator.fireStateChanged(new ValidationResult(errorMessage));
152     if (myValidationManager != null) {
153       myValidationManager.validate();
154     }
155   }
156
157   private void setOK() {
158     myGenerator.fireStateChanged(ValidationResult.OK);
159     if (myValidationManager != null) {
160       myValidationManager.validate();
161     }
162   }
163
164   public JPanel getContentPanel() {
165     return myContentPanel;
166   }
167
168   public void registerValidators(final FacetValidatorsManager manager) {
169     myValidationManager = manager;
170   }
171
172
173   /**
174    * Handles refreshing courses
175    * Old courses added to new courses only if their
176    * meta file still exists in local file system
177    */
178   private class RefreshActionListener implements ActionListener {
179     @Override
180     public void actionPerformed(ActionEvent e) {
181       refreshCoursesList();
182     }
183   }
184
185   private void refreshCoursesList() {
186     final List<CourseInfo> courses = myGenerator.getCourses(true);
187     if (courses.isEmpty()) {
188       setError(CONNECTION_ERROR);
189       return;
190     }
191     myCoursesComboBox.removeAllItems();
192
193     for (CourseInfo courseInfo : courses) {
194       myCoursesComboBox.addItem(courseInfo);
195     }
196     myGenerator.setSelectedCourse(StudyUtils.getFirst(courses));
197
198     myGenerator.setCourses(courses);
199     myAvailableCourses = courses;
200     StudyProjectGenerator.flushCache(myAvailableCourses);
201   }
202
203
204   /**
205    * Handles selecting course in combo box
206    * Sets selected course in combo box as selected in
207    * {@link StudyNewProjectPanel#myGenerator}
208    */
209   private class CourseSelectedListener implements ActionListener {
210     @Override
211     public void actionPerformed(ActionEvent e) {
212       JComboBox cb = (JComboBox)e.getSource();
213       CourseInfo selectedCourse = (CourseInfo)cb.getSelectedItem();
214       if (selectedCourse == null || selectedCourse.equals(CourseInfo.INVALID_COURSE)) {
215         myAuthorLabel.setText("");
216         myDescriptionLabel.setText("");
217         return;
218       }
219       final String authorsString = Course.getAuthorsString(selectedCourse.getAuthors());
220       myAuthorLabel.setText(!StringUtil.isEmptyOrSpaces(authorsString) ?"Author: " + authorsString : "");
221       myCoursesComboBox.removeItem(CourseInfo.INVALID_COURSE);
222       myDescriptionLabel.setText(selectedCourse.getDescription());
223       myGenerator.setSelectedCourse(selectedCourse);
224       setOK();
225     }
226   }
227
228   public JComboBox getCoursesComboBox() {
229     return myCoursesComboBox;
230   }
231
232   public JPanel getInfoPanel() {
233     return myInfoPanel;
234   }
235
236   private class AddRemoteDialog extends DialogWrapper {
237
238     private final StudyAddRemoteCourse myRemoteCourse;
239
240     protected AddRemoteDialog() {
241       super(null);
242       myRemoteCourse = new StudyAddRemoteCourse();
243       init();
244     }
245
246     @Nullable
247     @Override
248     protected JComponent createCenterPanel() {
249       return myRemoteCourse.getContentPanel();
250     }
251
252     @Override
253     protected void doOKAction() {
254       if (StringUtil.isEmptyOrSpaces(myRemoteCourse.getLogin())) {
255         myRemoteCourse.setError("Please, enter your login");
256         return;
257       }
258       if (StringUtil.isEmptyOrSpaces(myRemoteCourse.getPassword())) {
259         myRemoteCourse.setError("Please, enter your password");
260         return;
261       }
262
263       super.doOKAction();
264       final boolean isSuccess = EduStepicConnector.login(myRemoteCourse.getLogin(), myRemoteCourse.getPassword());
265       if (!isSuccess) {
266         setError("Failed to log in");
267       }
268       StudySettings.getInstance().setLogin(myRemoteCourse.getLogin());
269       StudySettings.getInstance().setPassword(myRemoteCourse.getPassword());
270       refreshCoursesList();
271     }
272   }
273
274 }