Fix according to review IDEA-CR-11509: make adaptive courses more discoverable
authorValentina Kiryushkina <valentina.kiryushkina@jetbrains.com>
Fri, 17 Jun 2016 12:49:24 +0000 (15:49 +0300)
committerValentina Kiryushkina <valentina.kiryushkina@jetbrains.com>
Fri, 17 Jun 2016 12:56:42 +0000 (15:56 +0300)
1) Always show public adaptive courses in combobox
2) If adaptive course is selected force user to login on Stepic
3) If user creates adaptive course and doesn't enrolled in it enroll him silently
4) Login dialogs minor ui improvements

python/educational-core/student/src/com/jetbrains/edu/learning/courseGeneration/StudyProjectGenerator.java
python/educational-core/student/src/com/jetbrains/edu/learning/stepic/CourseInfo.java
python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java
python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduStepicNames.java
python/educational-core/student/src/com/jetbrains/edu/learning/stepic/LoginPanel.form
python/educational-core/student/src/com/jetbrains/edu/learning/stepic/LoginPanel.java
python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StepicWrappers.java
python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyAddRemoteCourse.form
python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyAddRemoteCourse.java
python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyNewProjectPanel.java
python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyDirectoryProjectGenerator.java

index 1062a90897f4c2a86c937abc5929b2d7916f3abe..2cff3f89318dd393cd925e29a2384b4f57363c1c 100644 (file)
@@ -15,6 +15,7 @@ import com.intellij.openapi.project.Project;
 import com.intellij.openapi.ui.Messages;
 import com.intellij.openapi.util.ThrowableComputable;
 import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.openapi.vfs.LocalFileSystem;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.openapi.vfs.VirtualFileManager;
@@ -41,7 +42,10 @@ import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.io.*;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
 
 import static com.jetbrains.edu.learning.StudyUtils.execCancelable;
 
@@ -57,12 +61,26 @@ public class StudyProjectGenerator {
   private final List<SettingsListener> myListeners = ContainerUtil.newArrayList();
   public StepicUser myUser;
   private List<CourseInfo> myCourses = new ArrayList<>();
+  private List<Integer> myEnrolledCoursesIds = new ArrayList<>(); 
   protected CourseInfo mySelectedCourseInfo;
 
   public void setCourses(List<CourseInfo> courses) {
     myCourses = courses;
   }
 
+  public boolean isLoggedIn() {
+    return myUser != null && !StringUtil.isEmptyOrSpaces(myUser.getPassword()) && !StringUtil.isEmptyOrSpaces(myUser.getEmail());
+  }
+  
+  public void setEnrolledCoursesIds(@NotNull final List<Integer> coursesIds) {
+    myEnrolledCoursesIds = coursesIds;
+  }
+
+  @NotNull
+  public List<Integer> getEnrolledCoursesIds() {
+    return myEnrolledCoursesIds;
+  }
+
   public void setSelectedCourse(@NotNull final CourseInfo courseName) {
     mySelectedCourseInfo = courseName;
   }
@@ -403,9 +421,7 @@ public class StudyProjectGenerator {
           while ((line = reader.readLine()) != null) {
             Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
             final CourseInfo courseInfo = gson.fromJson(line, CourseInfo.class);
-            if (!courseInfo.isAdaptive()) {
-              courses.add(courseInfo);
-            }
+            courses.add(courseInfo);
           }
         }
         catch (IOException | JsonSyntaxException e) {
index b56d7a66485c919d6ae7d29c59df4802983c6a0c..50f6c4119e8e4d1bf47b65be231bf27e3309c90d 100644 (file)
@@ -117,4 +117,12 @@ public class CourseInfo {
   public void setPublic(boolean aPublic) {
     isPublic = aPublic;
   }
+
+  public int getId() {
+    return id;
+  }
+
+  public void setId(int id) {
+    this.id = id;
+  }
 }
index acfc2c0bfdb4db846e291133a0e3fb4e266b959f..a335fc48b768cf765f45dac240cb76bd5449217d 100644 (file)
@@ -27,6 +27,7 @@ import org.apache.commons.codec.binary.Base64;
 import org.apache.http.*;
 import org.apache.http.client.entity.UrlEncodedFormEntity;
 import org.apache.http.client.methods.*;
+import org.apache.http.client.utils.URIBuilder;
 import org.apache.http.cookie.Cookie;
 import org.apache.http.entity.ContentType;
 import org.apache.http.entity.StringEntity;
@@ -45,6 +46,8 @@ import javax.net.ssl.SSLContext;
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.X509TrustManager;
 import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.security.KeyManagementException;
 import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
@@ -74,6 +77,26 @@ public class EduStepicConnector {
     }
     return null;
   }
+  
+  @NotNull
+  public static List<Integer> getEnrolledCoursesIds() {
+    try {
+      final URI enrolledCoursesUri = new URIBuilder(EduStepicNames.COURSES).addParameter("enrolled", "true").build();
+      final List<CourseInfo> courses = getFromStepic(enrolledCoursesUri.toString(), StepicWrappers.CoursesContainer.class).courses;
+      final ArrayList<Integer> ids = new ArrayList<>();
+      for (CourseInfo course : courses) {
+        ids.add(course.getId());
+      }
+      return ids;
+    }
+    catch (IOException e) {
+      LOG.warn(e.getMessage());
+    }
+    catch (URISyntaxException e) {
+      LOG.warn(e.getMessage());
+    }
+    return Collections.emptyList();
+  }
 
   @Nullable
   public static StepicWrappers.AuthorWrapper getCurrentUser() {
@@ -203,7 +226,7 @@ public class EduStepicConnector {
     if (ourClient == null) {
       initializeClient();
     }
-    setHeaders(request, "application/json");
+    setHeaders(request, EduStepicNames.CONTENT_TYPE_APPL_JSON);
 
     final CloseableHttpResponse response = ourClient.execute(request);
     final StatusLine statusLine = response.getStatusLine();
@@ -225,6 +248,25 @@ public class EduStepicConnector {
     return ourClient;
   }
 
+  public static boolean enrollToCourse(final int courseId) {
+    HttpPost post = new HttpPost(EduStepicNames.STEPIC_API_URL + EduStepicNames.ENROLLMENTS);
+    try {
+      final StepicWrappers.EnrollmentWrapper enrollment = new StepicWrappers.EnrollmentWrapper(String.valueOf(courseId));
+      post.setEntity(new StringEntity(new GsonBuilder().create().toJson(enrollment)));
+      setHeaders(post, EduStepicNames.CONTENT_TYPE_APPL_JSON);
+      if (ourClient == null) {
+        initializeClient();
+      }
+      CloseableHttpResponse response = ourClient.execute(post);
+      StatusLine line = response.getStatusLine();
+      return line.getStatusCode() == HttpStatus.SC_CREATED;
+    }
+    catch (IOException e) {
+      LOG.warn(e.getMessage());
+    }
+    return false;
+  }
+
   @NotNull
   public static List<CourseInfo> getCourses() {
     try {
index f8e93fd596310a3b220497ca06d8cddb27a34a21..5ece7fe02284bc8a2e5cd98722b590f67e6829cd 100644 (file)
@@ -1,24 +1,26 @@
 package com.jetbrains.edu.learning.stepic;
 
 public class EduStepicNames {
-  static final String STEPIC_URL = "https://stepic.org";
-  static final String STEPIC_API_URL = STEPIC_URL + "/api";
-  static final String RECOMMENDATIONS_URL = "/recommendations";
-  static final String CONTENT_TYPE_APPL_JSON = "application/json";
-  static final String LESSONS = "/lessons/";
-  static final String RECOMMENDATION_REACTIONS_URL = "/recommendation-reactions";
-  static final String ATTEMPTS = "/attempts";
-  static final String SUBMISSIONS = "/submissions";
-  static final String ASSIGNMENT = "/assignments";
-  static final String VIEWS_URL = "/views";
-  static final String UNITS = "/units";
-  static final String DEFAULT_TASKFILE_NAME = "code.py";
-  static final String USERS = "/users";
-  static final String LOGIN = "/accounts/login/";
-  static final String STEP_SOURCES = "/step-sources/";
-  static final String CURRENT_USER = "/stepics/1";
-  static final String COURSES = "/courses";
-  static final String COURSES_FROM_PAGE = COURSES + "?page=";
+  public static final String STEPIC_URL = "https://stepic.org";
+  public static final String STEPIC_API_URL = STEPIC_URL + "/api";
+  public static final String RECOMMENDATIONS_URL = "/recommendations";
+  public static final String CONTENT_TYPE_APPL_JSON = "application/json";
+  public static final String LESSONS = "/lessons/";
+  public static final String RECOMMENDATION_REACTIONS_URL = "/recommendation-reactions";
+  public static final String ATTEMPTS = "/attempts";
+  public static final String SUBMISSIONS = "/submissions";
+  public static final String ASSIGNMENT = "/assignments";
+  public static final String VIEWS_URL = "/views";
+  public static final String UNITS = "/units";
+  public static final String DEFAULT_TASKFILE_NAME = "code.py";
+  public static final String USERS = "/users";
+  public static final String LOGIN = "/accounts/login/";
+  public static final String STEP_SOURCES = "/step-sources/";
+  public static final String CURRENT_USER = "/stepics/1";
+  public static final String COURSES = "/courses";
+  public static final String COURSES_FROM_PAGE = COURSES + "?page=";
   public static final String STEPS = "/steps";
-  static final String SECTIONS = "/sections/";
+  public static final String SECTIONS = "/sections/";
+  public static final String ENROLLMENTS = "/enrollments";
+  public static String STEPIC_SIGN_IN_LINK = "https://stepic.org/accounts/signup/?next=/users/16516293/learn";
 }
index 33b848ad22b9a8f7c2c05751895c9854ec444878..a298738c9fddfee997f672f88f24cd5607d0826e 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.LoginPanel">
-  <grid id="27dc6" binding="myPane" layout-manager="GridLayoutManager" row-count="3" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+  <grid id="27dc6" binding="myPane" layout-manager="GridLayoutManager" row-count="4" 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="174"/>
     </properties>
     <border type="none"/>
     <children>
-      <vspacer id="9b306">
-        <constraints>
-          <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
-        </constraints>
-      </vspacer>
       <component id="9edbd" class="javax.swing.JPasswordField" binding="myPasswordField">
         <constraints>
-          <grid row="1" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
+          <grid row="1" column="1" row-span="1" col-span="3" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
             <preferred-size width="300" height="-1"/>
           </grid>
         </constraints>
@@ -33,7 +28,7 @@
       </component>
       <component id="e76ec" class="javax.swing.JTextField" binding="myLoginTextField">
         <constraints>
-          <grid row="0" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
+          <grid row="0" column="1" row-span="1" col-span="3" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
             <preferred-size width="150" height="-1"/>
           </grid>
         </constraints>
           <text value="E-mail:"/>
         </properties>
       </component>
+      <component id="e74c1" class="com.intellij.ui.components.JBLabel" binding="mySignUpLabel">
+        <constraints>
+          <grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <text value="&lt;html&gt;&lt;a href=&quot;https://stepic.org/accounts/signup/?next=/users/16516293/learn&quot;&gt;Not a user?&lt;/a&gt;&lt;/html&gt;" noi18n="true"/>
+          <toolTipText value="Click To Sign Up To Stepic"/>
+          <visible value="true"/>
+        </properties>
+      </component>
+      <hspacer id="1f1a7">
+        <constraints>
+          <grid row="2" 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>
+      <vspacer id="5765c">
+        <constraints>
+          <grid row="3" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
+        </constraints>
+      </vspacer>
     </children>
   </grid>
 </form>
index 393e12ad6f523992547887abf26a196e65f4827b..bc480b0ae117dcd6e34a12cf43fbc952431364ca 100644 (file)
  */
 package com.jetbrains.edu.learning.stepic;
 
+import com.intellij.ide.BrowserUtil;
 import com.intellij.ui.DocumentAdapter;
+import com.intellij.ui.components.JBLabel;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import javax.swing.*;
 import javax.swing.event.DocumentEvent;
 import javax.swing.event.DocumentListener;
+import java.awt.*;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
 
 public class LoginPanel {
   private JPanel myPane;
   private JTextField myLoginTextField;
   private JPasswordField myPasswordField;
+  private JBLabel mySignUpLabel;
 
   public LoginPanel(final LoginDialog dialog) {
     DocumentListener listener = new DocumentAdapter() {
@@ -37,6 +43,23 @@ public class LoginPanel {
     };
     myLoginTextField.getDocument().addDocumentListener(listener);
     myPasswordField.getDocument().addDocumentListener(listener);
+
+    mySignUpLabel.addMouseListener(new MouseAdapter() {
+      @Override
+      public void mouseClicked(MouseEvent e) {
+        BrowserUtil.browse(EduStepicNames.STEPIC_SIGN_IN_LINK);
+      }
+
+      @Override
+      public void mouseEntered(MouseEvent e) {
+        e.getComponent().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+      }
+
+      @Override
+      public void mouseExited(MouseEvent e) {
+        e.getComponent().setCursor(Cursor.getDefaultCursor());
+      }
+    });
   }
 
   public JComponent getPanel() {
index c8e970fdb07f971d2270c3eae7933a5121ad76ff..c44d8c1b4fae5c7b7c1907e11920c0fea9ec052d 100644 (file)
@@ -418,4 +418,19 @@ public class StepicWrappers {
       this.step = step;
     }
   }
+  
+  static class Enrollment {
+    String course;
+
+    public Enrollment(String courseId) {
+      course = courseId;
+    }
+  }
+  static class EnrollmentWrapper {
+    Enrollment enrollment;
+
+    public EnrollmentWrapper(@NotNull final String courseId) {
+      enrollment = new Enrollment(courseId);
+    }
+  }
 }
index e1384d46bfdc4e113f6bdfac852dd055b8259709..8808ea19c93bbd94eb7c5ab525496f4504c1f5f6 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.ui.StudyAddRemoteCourse">
-  <grid id="27dc6" binding="myContentPanel" layout-manager="GridLayoutManager" row-count="3" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+  <grid id="27dc6" binding="myContentPanel" layout-manager="GridLayoutManager" row-count="4" 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="600" height="414"/>
           <text value="E-mail:"/>
         </properties>
       </component>
+      <component id="8d976" class="javax.swing.JLabel">
+        <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="Password:"/>
+        </properties>
+      </component>
+      <component id="a7a1a" class="com.intellij.ui.components.JBLabel" binding="mySignUpLabel">
+        <constraints>
+          <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <text value="&lt;html&gt;&lt;a href=&quot;https://stepic.org/accounts/signup/?next=/users/16516293/learn&quot;&gt;Not a user?&lt;/a&gt;&lt;/html&gt;"/>
+          <toolTipText value="Click To Sign Up To Stepic"/>
+        </properties>
+      </component>
+      <vspacer id="287e">
+        <constraints>
+          <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
+        </constraints>
+      </vspacer>
       <grid id="d7036" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
         <margin top="0" left="0" bottom="0" right="0"/>
         <constraints>
-          <grid row="2" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+          <grid row="2" column="1" row-span="2" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
         </constraints>
         <properties/>
         <border type="none"/>
           </component>
         </children>
       </grid>
-      <component id="8d976" class="javax.swing.JLabel">
-        <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="Password:"/>
-        </properties>
-      </component>
     </children>
   </grid>
 </form>
index f61e12f93599a3857d83f18327b3dd240beda61a..686071a470e75cb91163c97a271247e496b97e5c 100644 (file)
@@ -1,18 +1,25 @@
 package com.jetbrains.edu.learning.ui;
 
+import com.intellij.ide.BrowserUtil;
 import com.intellij.ui.JBColor;
 import com.intellij.ui.components.JBLabel;
+import com.jetbrains.edu.learning.stepic.EduStepicNames;
 import org.jetbrains.annotations.NotNull;
 
 import javax.swing.*;
 import javax.swing.event.DocumentEvent;
 import javax.swing.event.DocumentListener;
+import java.awt.*;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
 
 public class StudyAddRemoteCourse {
+  
   private JPanel myContentPanel;
   private JPasswordField myPasswordField;
   private JTextField myLoginField;
   private JBLabel myErrorLabel;
+  private JBLabel mySignUpLabel;
 
   public StudyAddRemoteCourse() {
     myErrorLabel.setText("");
@@ -34,6 +41,23 @@ public class StudyAddRemoteCourse {
     };
     myLoginField.getDocument().addDocumentListener(documentListener);
     myPasswordField.getDocument().addDocumentListener(documentListener);
+    
+    mySignUpLabel.addMouseListener(new MouseAdapter() {
+      @Override
+      public void mouseClicked(MouseEvent e) {
+        BrowserUtil.browse(EduStepicNames.STEPIC_SIGN_IN_LINK);
+      }
+
+      @Override
+      public void mouseEntered(MouseEvent e) {
+        e.getComponent().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+      }
+
+      @Override
+      public void mouseExited(MouseEvent e) {
+        e.getComponent().setCursor(Cursor.getDefaultCursor());
+      }
+    });
   }
 
   public JPanel getContentPanel() {
index 18633c8a7b579c038f047b5cb07c2a290736d4a8..05706e84fa71e704e6ebaa48fdeed4ce10706572 100644 (file)
@@ -44,6 +44,7 @@ import java.util.List;
  */
 public class StudyNewProjectPanel {
   private static final Logger LOG = Logger.getInstance(StudyNewProjectPanel.class);
+  private final String LOGIN_TO_STEPIC = "Login to Stepic";
   private List<CourseInfo> myAvailableCourses = new ArrayList<CourseInfo>();
   private JButton myBrowseButton;
   private JComboBox<CourseInfo> myCoursesComboBox;
@@ -58,6 +59,7 @@ public class StudyNewProjectPanel {
   private static final String INVALID_COURSE = "Selected course is invalid";
   private FacetValidatorsManager myValidationManager;
   private boolean isComboboxInitialized;
+  private String LOGIN_TO_STEPIC_MESSAGE = "<html><u>Login to Stepic</u> to open the adaptive course </html>";;
 
   public StudyNewProjectPanel(@NotNull final StudyProjectGenerator generator) {
     myGenerator = generator;
@@ -95,7 +97,13 @@ public class StudyNewProjectPanel {
       myDescriptionLabel.setEditable(false);
       //setting the first course in list as selected
       myGenerator.setSelectedCourse(selectedCourse);
-      setOK();
+      
+      if (selectedCourse.isAdaptive() && !myGenerator.isLoggedIn()) {
+        setError(LOGIN_TO_STEPIC_MESSAGE);
+      }
+      else {
+        setOK();
+      }
     }
   }
 
@@ -115,7 +123,7 @@ public class StudyNewProjectPanel {
     };
     myBrowseButton.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent e) {
-        final BaseListPopupStep<String> popupStep = new BaseListPopupStep<String>("", "Add local course", "Load private courses") {
+        final BaseListPopupStep<String> popupStep = new BaseListPopupStep<String>("", "Add local course", LOGIN_TO_STEPIC) {
           @Override
           public PopupStep onChosen(final String selectedValue, boolean finalChoice) {
             return doFinalStep(() -> {
@@ -145,9 +153,8 @@ public class StudyNewProjectPanel {
                                          }
                                        });
               }
-              else if ("Load private courses".equals(selectedValue)) {
-                final AddRemoteDialog dialog = new AddRemoteDialog();
-                dialog.show();
+              else if (LOGIN_TO_STEPIC.equals(selectedValue)) {
+                showLoginDialog();
               }
             });
           }
@@ -158,6 +165,11 @@ public class StudyNewProjectPanel {
     });
   }
 
+  public void showLoginDialog() {
+    final AddRemoteDialog dialog = new AddRemoteDialog();
+    dialog.show();
+  }
+
   private void initListeners() {
     myRefreshButton.addActionListener(new RefreshActionListener());
     myCoursesComboBox.addActionListener(new CourseSelectedListener());
@@ -220,15 +232,7 @@ public class StudyNewProjectPanel {
 
   private void addCoursesToCombobox(@NotNull List<CourseInfo> courses) {
     for (CourseInfo courseInfo : courses) {
-      if (!courseInfo.isAdaptive()) {
-        myCoursesComboBox.addItem(courseInfo);
-      }
-      else {
-        final boolean isLoggedIn = myGenerator.myUser != null;
-        if (isLoggedIn) {
-          myCoursesComboBox.addItem(courseInfo);
-        }
-      }
+      myCoursesComboBox.addItem(courseInfo);
     }
   }
 
@@ -254,11 +258,17 @@ public class StudyNewProjectPanel {
       myCoursesComboBox.removeItem(CourseInfo.INVALID_COURSE);
       myDescriptionLabel.setText(selectedCourse.getDescription());
       myGenerator.setSelectedCourse(selectedCourse);
+
       setOK();
+      if (selectedCourse.isAdaptive()) {
+        if(!myGenerator.isLoggedIn()) {
+          setError(LOGIN_TO_STEPIC_MESSAGE);
+        }
+      }
     }
   }
 
-  public JComboBox getCoursesComboBox() {
+  public JComboBox<CourseInfo> getCoursesComboBox() {
     return myCoursesComboBox;
   }
 
@@ -310,7 +320,7 @@ public class StudyNewProjectPanel {
           stepicUser.setEmail(myRemoteCourse.getLogin());
           stepicUser.setPassword(myRemoteCourse.getPassword());
           myGenerator.myUser = stepicUser;
-
+          myGenerator.setEnrolledCoursesIds(EduStepicConnector.getEnrolledCoursesIds());
 
           final List<CourseInfo> courses = myGenerator.getCourses(true);
           if (courses != null) {
index a3492b7247b266502831e624a86ba9b9cb4f8299..be783451faab56a0f1e402ff598cdb44fd8a6272 100644 (file)
@@ -10,14 +10,19 @@ import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.module.Module;
 import com.intellij.openapi.progress.ProcessCanceledException;
+import com.intellij.openapi.progress.ProgressManager;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.project.ProjectManager;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.util.ThrowableComputable;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.platform.DirectoryProjectGenerator;
 import com.intellij.psi.PsiDirectory;
 import com.intellij.psi.PsiManager;
+import com.intellij.util.BooleanFunction;
 import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator;
 import com.jetbrains.edu.learning.stepic.CourseInfo;
+import com.jetbrains.edu.learning.stepic.EduStepicConnector;
 import com.jetbrains.edu.learning.ui.StudyNewProjectPanel;
 import com.jetbrains.python.newProject.PythonProjectGenerator;
 import icons.InteractiveLearningPythonIcons;
@@ -26,6 +31,9 @@ import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import javax.swing.*;
+import java.awt.*;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
 import java.util.List;
 
 
@@ -33,6 +41,7 @@ public class PyStudyDirectoryProjectGenerator extends PythonProjectGenerator imp
   private static final Logger LOG = Logger.getInstance(PyStudyDirectoryProjectGenerator.class.getName());
   private final StudyProjectGenerator myGenerator;
   public ValidationResult myValidationResult = new ValidationResult("selected course is not valid");
+  private StudyNewProjectPanel mySettingsPanel;
 
   public PyStudyDirectoryProjectGenerator() {
     myGenerator = new StudyProjectGenerator();
@@ -42,6 +51,40 @@ public class PyStudyDirectoryProjectGenerator extends PythonProjectGenerator imp
         setValidationResult(result);
       }
     });
+
+    mySettingsPanel = new StudyNewProjectPanel(myGenerator);
+    mySettingsPanel.registerValidators(new FacetValidatorsManager() {
+      public void registerValidator(FacetEditorValidator validator, JComponent... componentsToWatch) {
+        throw new UnsupportedOperationException();
+      }
+
+      public void validate() {
+        ApplicationManager.getApplication().invokeLater(() -> fireStateChanged());
+      }
+    });
+
+    addErrorLabelMouseListener(new MouseAdapter() {
+      @Override
+      public void mouseClicked(MouseEvent e) {
+        if (((CourseInfo)mySettingsPanel.getCoursesComboBox().getSelectedItem()).isAdaptive() && !myGenerator.isLoggedIn()) {
+          mySettingsPanel.showLoginDialog();
+        }
+      }
+
+      @Override
+      public void mouseEntered(MouseEvent e) {
+        if (((CourseInfo)mySettingsPanel.getCoursesComboBox().getSelectedItem()).isAdaptive() && !myGenerator.isLoggedIn()) {
+          e.getComponent().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+        }
+      }
+
+      @Override
+      public void mouseExited(MouseEvent e) {
+        if (((CourseInfo)mySettingsPanel.getCoursesComboBox().getSelectedItem()).isAdaptive() && !myGenerator.isLoggedIn()) {
+          e.getComponent().setCursor(Cursor.getDefaultCursor());
+        }
+      }
+    });
   }
 
   @Nls
@@ -72,6 +115,7 @@ public class PyStudyDirectoryProjectGenerator extends PythonProjectGenerator imp
       LOG.error("Can't copy test_helper.py " + exception.getMessage());
     }
   }
+  
   @NotNull
   @Override
   public ValidationResult validate(@NotNull String s) {
@@ -85,16 +129,7 @@ public class PyStudyDirectoryProjectGenerator extends PythonProjectGenerator imp
   @Nullable
   @Override
   public JPanel extendBasePanel() throws ProcessCanceledException {
-    StudyNewProjectPanel settingsPanel = new StudyNewProjectPanel(myGenerator);
-    settingsPanel.registerValidators(new FacetValidatorsManager() {
-      public void registerValidator(FacetEditorValidator validator, JComponent... componentsToWatch) {
-        throw new UnsupportedOperationException();
-      }
-      public void validate() {
-        ApplicationManager.getApplication().invokeLater(()->fireStateChanged());
-      }
-    });
-    return settingsPanel.getContentPanel();
+    return mySettingsPanel.getContentPanel();
   }
 
   public List<CourseInfo> getCourses() {
@@ -108,4 +143,27 @@ public class PyStudyDirectoryProjectGenerator extends PythonProjectGenerator imp
   public StudyProjectGenerator getGenerator() {
     return myGenerator;
   }
+
+  @Nullable
+  @Override
+  public BooleanFunction<PythonProjectGenerator> beforeProjectGenerated(@NotNull Sdk sdk) {
+    return new BooleanFunction<PythonProjectGenerator>() {
+      @Override
+      public boolean fun(PythonProjectGenerator generator) {
+        final List<Integer> enrolledCoursesIds = myGenerator.getEnrolledCoursesIds();
+        final CourseInfo course = (CourseInfo)mySettingsPanel.getCoursesComboBox().getSelectedItem();
+        if (course.isAdaptive() && !enrolledCoursesIds.contains(course.getId())) {
+          ProgressManager.getInstance().runProcessWithProgressSynchronously(new ThrowableComputable<Boolean, RuntimeException>() {
+            @Override
+            public Boolean compute() throws RuntimeException {
+              ProgressManager.getInstance().getProgressIndicator().setIndeterminate(true);
+              return StudyUtils.execCancelable(() -> EduStepicConnector.enrollToCourse(course.getId()));
+            }
+          }, "Creating Course", true, ProjectManager.getInstance().getDefaultProject());
+          
+        }
+        return true;
+      }
+    };
+  }
 }