Skip to content

Commit 2824fa5

Browse files
committed
Merge pull request #19 from rage/listCourses
List courses
2 parents 0533b6c + 9834db0 commit 2824fa5

File tree

8 files changed

+145
-132
lines changed

8 files changed

+145
-132
lines changed

tmc-application/manifest.mf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ OpenIDE-Module: fi.helsinki.cs.tmc.application
44
OpenIDE-Module-Localizing-Bundle: fi/helsinki/cs/tmc/application/Bundle.properties
55
OpenIDE-Module-Specification-Version: 1.0
66
OpenIDE-Module-Install: fi/helsinki/cs/tmc/application/TmcAppModuleInstall.class
7+
OpenIDE-Module-Needs: org.openide.filesystems.FileUtil.toFileObject

tmc-plugin/src/fi/helsinki/cs/tmc/actions/CheckForNewExercisesOrUpdates.java

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,25 @@
77
import fi.helsinki.cs.tmc.model.CourseDb;
88
import fi.helsinki.cs.tmc.model.LocalExerciseStatus;
99
import fi.helsinki.cs.tmc.model.ObsoleteClientException;
10-
import fi.helsinki.cs.tmc.model.ServerAccess;
1110
import fi.helsinki.cs.tmc.model.NBTmcSettings;
11+
import fi.helsinki.cs.tmc.model.ServerAccess;
1212
import fi.helsinki.cs.tmc.model.TmcCoreSingleton;
1313
import fi.helsinki.cs.tmc.ui.DownloadOrUpdateExercisesDialog;
1414
import fi.helsinki.cs.tmc.ui.ConvenientDialogDisplayer;
1515
import fi.helsinki.cs.tmc.ui.TmcNotificationDisplayer;
1616
import fi.helsinki.cs.tmc.utilities.Inflector;
1717
import fi.helsinki.cs.tmc.utilities.TmcStringUtils;
1818
import hy.tmc.core.TmcCore;
19+
import hy.tmc.core.domain.Exercise;
1920
import hy.tmc.core.exceptions.TmcCoreException;
2021
import java.awt.event.ActionEvent;
2122
import java.awt.event.ActionListener;
2223
import java.util.ArrayList;
2324
import javax.swing.AbstractAction;
2425
import javax.swing.Icon;
2526
import org.apache.commons.lang3.StringUtils;
27+
import org.netbeans.api.progress.ProgressHandle;
28+
import org.netbeans.api.progress.ProgressHandleFactory;
2629
import org.openide.awt.ActionID;
2730
import org.openide.awt.ActionReference;
2831
import org.openide.awt.ActionReferences;
@@ -50,7 +53,6 @@ public static void startTimer() {
5053
private static final TmcNotificationDisplayer.SingletonToken notifierToken = TmcNotificationDisplayer.createSingletonToken();
5154

5255
private CourseDb courseDb;
53-
private ServerAccess serverAccess;
5456
private TmcNotificationDisplayer notifier;
5557
private ConvenientDialogDisplayer dialogs;
5658
private boolean beQuiet;
@@ -63,7 +65,6 @@ public CheckForNewExercisesOrUpdates() {
6365

6466
public CheckForNewExercisesOrUpdates(boolean beQuiet, boolean backgroundCheck) {
6567
this.courseDb = CourseDb.getInstance();
66-
this.serverAccess = new ServerAccess();
6768
this.notifier = TmcNotificationDisplayer.getDefault();
6869
this.dialogs = ConvenientDialogDisplayer.getDefault();
6970
this.beQuiet = beQuiet;
@@ -76,25 +77,30 @@ public void actionPerformed(ActionEvent e) {
7677
run();
7778
}
7879

79-
//"Checking for new exercises" päivitä tämä näkymään progressHandleen myöhemmin
80-
/**
81-
*
82-
*/
8380
public void run() {
8481
try {
8582
final Course currentCourseBeforeUpdate = courseDb.getCurrentCourse();
8683
if (backgroundProcessingOrNoCurrentCourse(currentCourseBeforeUpdate)) {
8784
return;
8885
}
86+
ProgressHandle exerciseRefresh = ProgressHandleFactory.createSystemHandle(
87+
"Checking for new exercises");
88+
exerciseRefresh.start();
8989
ListenableFuture<Course> currentCourseFuture = this.tmcCore.getCourse(
90-
NBTmcSettings.getDefault(), currentCourseBeforeUpdate.getDetailsUrl()
90+
NBTmcSettings.getDefault(), detailUrl(currentCourseBeforeUpdate)
9191
);
92-
Futures.addCallback(currentCourseFuture, new UpdateCourseForExerciseUpdate());
92+
Futures.addCallback(currentCourseFuture, new UpdateCourseForExerciseUpdate(exerciseRefresh));
9393
} catch (TmcCoreException ex) {
9494
Exceptions.printStackTrace(ex);
9595
}
9696
}
9797

98+
private String detailUrl(final Course currentCourseBeforeUpdate) {
99+
return ServerAccess.addApiCallQueryParameters(
100+
currentCourseBeforeUpdate.getDetailsUrl()
101+
);
102+
}
103+
98104
/**
99105
* If there is something at background or no current course is chosen,
100106
* return true.
@@ -113,25 +119,37 @@ private boolean backgroundProcessingOrNoCurrentCourse(final Course currentCourse
113119
}
114120

115121
class UpdateCourseForExerciseUpdate implements FutureCallback<Course> {
122+
123+
private ProgressHandle lastAction;
116124

117125
/**
118126
* This should be attached to listenableFuture. When future is ready,
119127
* receivedCourse will be saved to courseDb and view will be updated.
120128
*/
121-
public UpdateCourseForExerciseUpdate() {
129+
public UpdateCourseForExerciseUpdate(ProgressHandle lastAction) {
130+
this.lastAction = lastAction;
122131
}
123132

124133
@Override
125134
public void onSuccess(Course receivedCourse) {
135+
lastAction.finish();
126136
if (receivedCourse != null) {
137+
setCourseNameToAllExercises(receivedCourse);
127138
courseDb.putDetailedCourse(receivedCourse);
128139
final LocalExerciseStatus status = LocalExerciseStatus.get(receivedCourse.getExercises());
129140
updateGUI(status);
130141
}
131142
}
132143

144+
private void setCourseNameToAllExercises(Course receivedCourse) {
145+
for (Exercise exercise : receivedCourse.getExercises()) {
146+
exercise.setCourseName(receivedCourse.getName());
147+
}
148+
}
149+
133150
private void updateGUI(final LocalExerciseStatus status) {
134-
if (status.thereIsSomethingToDownload(false)) {
151+
boolean thereIsSomethingToDownload = status.thereIsSomethingToDownload(false);
152+
if (thereIsSomethingToDownload) {
135153
if (beQuiet) {
136154
displayNotification(status, new ActionListener() {
137155
@Override
@@ -149,6 +167,7 @@ public void actionPerformed(ActionEvent e) {
149167

150168
@Override
151169
public void onFailure(Throwable ex) {
170+
lastAction.finish();
152171
if (!beQuiet || ex instanceof ObsoleteClientException) {
153172
dialogs.displayError("Failed to check for new exercises.\n" + ServerErrorHelper.getServerExceptionMsg(ex));
154173
}

tmc-plugin/src/fi/helsinki/cs/tmc/actions/DownloadExercisesAction.java

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.google.common.util.concurrent.FutureCallback;
44
import com.google.common.util.concurrent.Futures;
55
import com.google.common.util.concurrent.ListenableFuture;
6+
import fi.helsinki.cs.tmc.model.CourseDb;
67
import hy.tmc.core.domain.Exercise;
78
import fi.helsinki.cs.tmc.model.NBTmcSettings;
89
import fi.helsinki.cs.tmc.model.ProjectMediator;
@@ -11,10 +12,15 @@
1112
import fi.helsinki.cs.tmc.ui.ConvenientDialogDisplayer;
1213
import hy.tmc.core.TmcCore;
1314
import hy.tmc.core.exceptions.TmcCoreException;
15+
import java.lang.reflect.InvocationTargetException;
1416
import java.util.ArrayList;
1517
import java.util.List;
1618
import java.util.logging.Level;
1719
import java.util.logging.Logger;
20+
import javax.swing.SwingUtilities;
21+
import org.netbeans.api.progress.ProgressHandle;
22+
import org.netbeans.api.progress.ProgressHandleFactory;
23+
import org.openide.util.Exceptions;
1824

1925
/**
2026
* Downloads and opens the given exercises in the background.
@@ -30,6 +36,10 @@ public class DownloadExercisesAction {
3036
private TmcCore tmcCore;
3137
private NBTmcSettings settings;
3238

39+
/**
40+
* Downloads all exercises of the list from TmcServer, unzips and opens them and
41+
* saves the checksums of each Exercise to courseDb.
42+
*/
3343
public DownloadExercisesAction(List<Exercise> exercisesToOpen) {
3444
this.projectMediator = ProjectMediator.getInstance();
3545
this.dialogs = ConvenientDialogDisplayer.getDefault();
@@ -40,18 +50,30 @@ public DownloadExercisesAction(List<Exercise> exercisesToOpen) {
4050
}
4151

4252
public void run() throws TmcCoreException {
43-
// final AggregatingBgTaskListener<TmcProjectInfo> aggregator
44-
// = new AggregatingBgTaskListener<TmcProjectInfo>(exercisesToDownload.size(), whenAllDownloadsFinished);
45-
53+
ProgressHandle exerciseDownload = ProgressHandleFactory.createSystemHandle(
54+
"Downloading " + exercisesToDownload.size() + " exercises.");
55+
exerciseDownload.start();
4656
ListenableFuture<List<Exercise>> dlFuture = tmcCore.downloadExercises(exercisesToDownload, settings);
4757

48-
Futures.addCallback(dlFuture, new ProjectOpener());
58+
Futures.addCallback(dlFuture, new ProjectOpener(exerciseDownload));
4959
}
5060

5161
private class ProjectOpener implements FutureCallback<List<Exercise>> {
5262

63+
private ProgressHandle lastAction;
64+
65+
/**
66+
* Converts Exercise objects to TmcProjectInfo objects.
67+
* Saves them to CourseDb and opens them.
68+
* @param lastAction
69+
*/
70+
public ProjectOpener(ProgressHandle lastAction) {
71+
this.lastAction = lastAction;
72+
}
73+
5374
@Override
5475
public void onSuccess(List<Exercise> downloadedExercises) {
76+
lastAction.finish();
5577
List<TmcProjectInfo> projects = new ArrayList<TmcProjectInfo>();
5678
for (Exercise exercise : downloadedExercises) {
5779
TmcProjectInfo info = projectMediator.tryGetProjectForExercise(exercise);
@@ -60,14 +82,30 @@ public void onSuccess(List<Exercise> downloadedExercises) {
6082
}
6183
projects.add(info);
6284
}
85+
saveDownloadedExercisesToCourseDb(downloadedExercises);
6386
projectMediator.openProjects(projects);
6487
}
6588

89+
private void saveDownloadedExercisesToCourseDb(final List<Exercise> downloadedExercises) {
90+
try {
91+
SwingUtilities.invokeAndWait(new Runnable() {
92+
@Override
93+
public void run() {
94+
CourseDb.getInstance().multipleExerciseDownloaded(downloadedExercises);
95+
}
96+
});
97+
} catch (InterruptedException ex) {
98+
Exceptions.printStackTrace(ex);
99+
} catch (InvocationTargetException ex) {
100+
Exceptions.printStackTrace(ex);
101+
}
102+
}
103+
66104
@Override
67105
public void onFailure(Throwable thrwbl) {
106+
lastAction.finish();
68107
logger.log(Level.INFO, "Failed to download exercise file.", thrwbl);
69108
dialogs.displayError("Failed to download exercises.\n" + ServerErrorHelper.getServerExceptionMsg(thrwbl));
70-
71109
}
72110
}
73111
}

tmc-plugin/src/fi/helsinki/cs/tmc/actions/RefreshCoursesAction.java

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
import java.util.List;
1818
import java.util.logging.Level;
1919
import java.util.logging.Logger;
20+
import org.netbeans.api.progress.ProgressHandle;
21+
import org.netbeans.api.progress.ProgressHandleFactory;
2022
import org.openide.util.Exceptions;
2123

2224
/**
@@ -37,14 +39,14 @@ public final class RefreshCoursesAction {
3739
public RefreshCoursesAction() {
3840
this(NBTmcSettings.getDefault());
3941
}
40-
42+
4143
/**
4244
* Default constructor.
4345
*/
4446
public RefreshCoursesAction(NBTmcSettings settings) {
4547
this(settings, TmcCoreSingleton.getInstance());
4648
}
47-
49+
4850
/**
4951
* Dependency inject TmcCore for tests.
5052
*/
@@ -69,34 +71,54 @@ public RefreshCoursesAction addListener(FutureCallback<List<Course>> callback) {
6971
}
7072

7173
/**
72-
* Starts downloading course-jsons from TMC-server.
73-
* Url of TMC-server is defined in TmcSettings object.
74-
* TmcCore includes all logic, callbacks here are run after core-futures are ready.
74+
* Starts downloading course-jsons from TMC-server. Url of TMC-server is
75+
* defined in TmcSettings object. TmcCore includes all logic, callbacks here
76+
* are run after core-futures are ready.
7577
*/
7678
public void run() {
7779
try {
80+
ProgressHandle courseRefresh = ProgressHandleFactory.createSystemHandle(
81+
"Refreshing course list");
82+
courseRefresh.start();
7883
ListenableFuture<List<Course>> listCourses = this.tmcCore.listCourses(tmcSettings);
79-
Futures.addCallback(listCourses, new LoadCourses());
84+
Futures.addCallback(listCourses, new LoadCourses(courseRefresh));
8085
} catch (TmcCoreException ex) {
8186
Exceptions.printStackTrace(ex);
8287
callbacks.onFailure(ex);
8388
}
8489
}
8590

86-
/**
87-
* This callBack is run when ListenableFuture (to witch this is attached) is done.
88-
* On success method takes list of Course-objects, searches the current course and starts uploading
89-
* the details of the course.
90-
* If no currentCourse found, no need to update details.
91-
*/
9291
class LoadCourses implements FutureCallback<List<Course>> {
92+
93+
private ProgressHandle lastAction;
94+
95+
/**
96+
* This callBack is run when ListenableFuture (to witch this is
97+
* attached) is done. On success method takes list of Course-objects,
98+
* searches the current course and starts uploading the details of the
99+
* course. If no currentCourse found, no need to update details.
100+
*
101+
* @param ProgressHandle shows to user that action is processing.
102+
*/
103+
public LoadCourses(ProgressHandle lastAction) {
104+
this.lastAction = lastAction;
105+
}
106+
93107
@Override
94108
public void onSuccess(final List<Course> courses) {
95-
Course currentCourse = CourseListUtils.getCourseByName(courses, courseDb.getCurrentCourseName());
109+
lastAction.finish();
110+
Course currentCourse = CourseListUtils.getCourseByName(
111+
courses, courseDb.getCurrentCourseName()
112+
);
96113
if (currentCourse != null) {
97114
try {
98-
ListenableFuture<Course> courseFuture = tmcCore.getCourse(tmcSettings, currentCourse.getDetailsUrl());
99-
Futures.addCallback(courseFuture, new UpdateCourse(courses));
115+
ProgressHandle loadingCourse = ProgressHandleFactory.
116+
createSystemHandle("Loading course");
117+
loadingCourse.start();
118+
ListenableFuture<Course> courseFuture = tmcCore.getCourse(
119+
tmcSettings, currentCourse.getDetailsUrl()
120+
);
121+
Futures.addCallback(courseFuture, new UpdateCourse(courses, loadingCourse));
100122
} catch (TmcCoreException ex) {
101123
Exceptions.printStackTrace(ex);
102124
callbacks.onFailure(ex);
@@ -108,24 +130,30 @@ public void onSuccess(final List<Course> courses) {
108130

109131
@Override
110132
public void onFailure(Throwable ex) {
133+
lastAction.finish();
111134
log.log(Level.INFO, "Failed to download current course info.", ex);
112135
callbacks.onFailure(ex);
113136
}
114137
}
115138

116139
/**
117-
* When detailed current course is present, courses will be given to FutureCallbackList,
118-
* that shares the result to every callback that is attached to that list.
140+
* When detailed current course is present, courses will be given to
141+
* FutureCallbackList, that shares the result to every callback that is
142+
* attached to that list.
119143
*/
120144
class UpdateCourse implements FutureCallback<Course> {
121-
List<Course> courses;
122-
123-
public UpdateCourse(List<Course> courses) {
145+
146+
private List<Course> courses;
147+
private ProgressHandle lastAction;
148+
149+
public UpdateCourse(List<Course> courses, ProgressHandle lastAction) {
124150
this.courses = courses;
151+
this.lastAction = lastAction;
125152
}
126153

127154
@Override
128155
public void onSuccess(Course detailedCourse) {
156+
lastAction.finish();
129157
detailedCourse.setExercisesLoaded(true);
130158
ArrayList<Course> finalCourses = new ArrayList<Course>();
131159
for (Course course : courses) {
@@ -140,6 +168,7 @@ public void onSuccess(Course detailedCourse) {
140168

141169
@Override
142170
public void onFailure(Throwable ex) {
171+
lastAction.finish();
143172
log.log(Level.INFO, "Failed to download current course info.", ex);
144173
callbacks.onFailure(ex);
145174
}

0 commit comments

Comments
 (0)