Skip to content

Commit bf24cf2

Browse files
committed
Merge branch 'back-to-bgtask-and-cancellable' into core_integration
Conflicts: tmc-plugin/src/fi/helsinki/cs/tmc/actions/CheckForNewExercisesOrUpdates.java tmc-plugin/src/fi/helsinki/cs/tmc/actions/PastebinAction.java tmc-plugin/src/fi/helsinki/cs/tmc/actions/RefreshCoursesAction.java tmc-plugin/src/fi/helsinki/cs/tmc/actions/SubmitExerciseAction.java tmc-plugin/src/fi/helsinki/cs/tmc/runners/CheckstyleRunHandler.java tmc-plugin/src/fi/helsinki/cs/tmc/runners/TestRunHandler.java
2 parents 8991c69 + da72972 commit bf24cf2

32 files changed

+538
-649
lines changed

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

Lines changed: 67 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
package fi.helsinki.cs.tmc.actions;
22

3-
import com.google.common.util.concurrent.FutureCallback;
4-
import com.google.common.util.concurrent.Futures;
5-
import com.google.common.util.concurrent.ListenableFuture;
3+
import static java.util.logging.Level.INFO;
4+
65
import fi.helsinki.cs.tmc.core.domain.Course;
76
import fi.helsinki.cs.tmc.model.CourseDb;
87
import fi.helsinki.cs.tmc.model.LocalExerciseStatus;
98
import fi.helsinki.cs.tmc.model.ObsoleteClientException;
10-
import fi.helsinki.cs.tmc.model.NBTmcSettings;
11-
import fi.helsinki.cs.tmc.model.ServerAccess;
9+
import fi.helsinki.cs.tmc.model.NbTmcSettings;
1210
import fi.helsinki.cs.tmc.model.TmcCoreSingleton;
1311
import fi.helsinki.cs.tmc.ui.DownloadOrUpdateExercisesDialog;
1412
import fi.helsinki.cs.tmc.ui.ConvenientDialogDisplayer;
@@ -26,17 +24,28 @@
2624
import javax.swing.AbstractAction;
2725
import javax.swing.Icon;
2826
import javax.swing.SwingUtilities;
27+
import fi.helsinki.cs.tmc.utilities.BgTask;
28+
import fi.helsinki.cs.tmc.utilities.BgTaskListener;
29+
import fi.helsinki.cs.tmc.utilities.CancellableCallable;
30+
31+
import com.google.common.util.concurrent.ListenableFuture;
32+
2933
import org.apache.commons.lang3.StringUtils;
30-
import org.netbeans.api.progress.ProgressHandle;
31-
import org.netbeans.api.progress.ProgressHandleFactory;
34+
3235
import org.openide.awt.ActionID;
3336
import org.openide.awt.ActionReference;
3437
import org.openide.awt.ActionReferences;
3538
import org.openide.awt.ActionRegistration;
36-
import org.openide.util.Exceptions;
3739
import org.openide.util.ImageUtilities;
3840
import org.openide.util.NbBundle.Messages;
3941

42+
import java.util.logging.Logger;
43+
import java.awt.event.ActionEvent;
44+
import java.awt.event.ActionListener;
45+
import java.util.ArrayList;
46+
import javax.swing.AbstractAction;
47+
import javax.swing.Icon;
48+
4049
@ActionID(category = "TMC",
4150
id = "fi.helsinki.cs.tmc.actions.CheckForNewExercisesOrUpdates")
4251
@ActionRegistration(displayName = "#CTL_CheckForNewExercisesOrUpdates")
@@ -53,14 +62,16 @@ public static void startTimer() {
5362
timer.start();
5463
}
5564

65+
private static final Logger logger = Logger.getLogger(CheckForNewExercisesOrUpdates.class.getName());
66+
5667
private static final TmcNotificationDisplayer.SingletonToken notifierToken = TmcNotificationDisplayer.createSingletonToken();
5768

5869
private CourseDb courseDb;
5970
private TmcNotificationDisplayer notifier;
6071
private ConvenientDialogDisplayer dialogs;
6172
private boolean beQuiet;
6273
private boolean backgroundCheck;
63-
private TmcCore tmcCore;
74+
private final TmcCore tmcCore;
6475

6576
public CheckForNewExercisesOrUpdates() {
6677
this(false, false);
@@ -82,6 +93,7 @@ public void actionPerformed(ActionEvent e) {
8293

8394
public void run() {
8495
final Course currentCourseBeforeUpdate = courseDb.getCurrentCourse();
96+
<<<<<<< HEAD
8597
try {
8698
if (backgroundProcessingOrNoCurrentCourse(currentCourseBeforeUpdate)) {
8799
return;
@@ -112,87 +124,72 @@ private URI detailUrl(final Course currentCourseBeforeUpdate) throws URISyntaxEx
112124
* return true.
113125
*/
114126
private boolean backgroundProcessingOrNoCurrentCourse(final Course currentCourseBeforeUpdate) {
115-
if (backgroundCheck && !NBTmcSettings.getDefault().isCheckingForUpdatesInTheBackground()) {
116-
return true;
127+
if (backgroundCheck && !NbTmcSettings.getDefault().isCheckingForUpdatesInTheBackground()) {
128+
return;
117129
}
130+
118131
if (currentCourseBeforeUpdate == null) {
119132
if (!beQuiet) {
120133
dialogs.displayMessage("Please select a course in TMC -> Settings.");
121134
}
122-
return true;
135+
return;
123136
}
124-
return false;
125-
}
126137

127-
class UpdateCourseForExerciseUpdate implements FutureCallback<Course> {
138+
BgTaskListener bgTaskListener = new BgTaskListener<Course>() {
139+
@Override
140+
public void bgTaskReady(Course receivedCourse) {
141+
if (receivedCourse != null) {
128142

129-
private ProgressHandle lastAction;
143+
courseDb.putDetailedCourse(receivedCourse);
130144

131-
/**
132-
* This should be attached to listenableFuture. When future is ready,
133-
* receivedCourse will be saved to courseDb and view will be updated.
134-
*/
135-
public UpdateCourseForExerciseUpdate(ProgressHandle lastAction) {
136-
this.lastAction = lastAction;
137-
}
145+
final LocalExerciseStatus status = LocalExerciseStatus.get(receivedCourse.getExercises());
138146

139-
@Override
140-
public void onSuccess(final Course receivedCourse) {
141-
SwingUtilities.invokeLater(new Runnable() {
142-
143-
@Override
144-
public void run() {
145-
lastAction.finish();
146-
if (receivedCourse != null) {
147-
setCourseNameToAllExercises(receivedCourse);
148-
courseDb.putDetailedCourse(receivedCourse);
149-
final LocalExerciseStatus status = LocalExerciseStatus.get(receivedCourse.getExercises());
150-
updateGUI(status);
147+
if (status.thereIsSomethingToDownload(false)) {
148+
if (beQuiet) {
149+
displayNotification(status, new ActionListener() {
150+
@Override
151+
public void actionPerformed(ActionEvent e) {
152+
DownloadOrUpdateExercisesDialog.display(status.unlockable, status.downloadableUncompleted, status.updateable);
153+
}
154+
});
155+
} else {
156+
DownloadOrUpdateExercisesDialog.display(status.unlockable, status.downloadableUncompleted, status.updateable);
157+
}
158+
} else if (!beQuiet) {
159+
dialogs.displayMessage("No new exercises or updates to download.");
151160
}
152161
}
162+
}
153163

154-
});
155-
156-
}
157-
158-
private void setCourseNameToAllExercises(Course receivedCourse) {
159-
for (Exercise exercise : receivedCourse.getExercises()) {
160-
exercise.setCourseName(receivedCourse.getName());
164+
@Override
165+
public void bgTaskCancelled() {
161166
}
162-
}
163167

164-
private void updateGUI(final LocalExerciseStatus status) {
165-
boolean thereIsSomethingToDownload = status.thereIsSomethingToDownload(false);
166-
if (thereIsSomethingToDownload) {
167-
if (beQuiet) {
168-
displayNotification(status, new ActionListener() {
169-
@Override
170-
public void actionPerformed(ActionEvent e) {
171-
DownloadOrUpdateExercisesDialog.display(status.unlockable, status.downloadableUncompleted, status.updateable);
172-
}
173-
});
174-
} else {
175-
DownloadOrUpdateExercisesDialog.display(status.unlockable, status.downloadableUncompleted, status.updateable);
168+
@Override
169+
public void bgTaskFailed(Throwable ex) {
170+
if (!beQuiet || ex instanceof ObsoleteClientException) {
171+
dialogs.displayError("Failed to check for new exercises.\n" + ServerErrorHelper.getServerExceptionMsg(ex));
176172
}
177-
} else if (!beQuiet) {
178-
dialogs.displayMessage("No new exercises or updates to download.");
179173
}
180-
}
174+
};
181175

182-
@Override
183-
public void onFailure(final Throwable ex) {
184-
SwingUtilities.invokeLater(new Runnable() {
176+
BgTask.start("Checking for new exercises", new CancellableCallable<Course>() {
177+
ListenableFuture<Course> currentCourseFuture;
185178

186-
@Override
187-
public void run() {
188-
lastAction.finish();
189-
if (!beQuiet || ex instanceof ObsoleteClientException) {
190-
dialogs.displayError("Failed to check for new exercises.\n" + ServerErrorHelper.getServerExceptionMsg(ex));
191-
}
192-
}
179+
@Override
180+
public Course call() throws Exception {
181+
logger.info("Downloading course to refresh cache");
182+
currentCourseFuture = tmcCore.getCourse(currentCourseBeforeUpdate.getDetailsUrlAsUri());
183+
return currentCourseFuture.get();
184+
}
185+
186+
@Override
187+
public boolean cancel() {
188+
logger.log(INFO, "Get course (refresh list) cancelled.");
189+
return currentCourseFuture.cancel(true);
190+
}
191+
}, bgTaskListener);
193192

194-
});
195-
}
196193
}
197194

198195
private void displayNotification(LocalExerciseStatus status, ActionListener action) {

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

Lines changed: 34 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@
66
import fi.helsinki.cs.tmc.core.domain.Course;
77
import fi.helsinki.cs.tmc.core.domain.Review;
88
import fi.helsinki.cs.tmc.model.CourseDb;
9-
import fi.helsinki.cs.tmc.model.NBTmcSettings;
9+
import fi.helsinki.cs.tmc.model.NbTmcSettings;
1010
import fi.helsinki.cs.tmc.model.ReviewDb;
1111
import fi.helsinki.cs.tmc.model.TmcCoreSingleton;
1212
import fi.helsinki.cs.tmc.ui.ConvenientDialogDisplayer;
1313
import fi.helsinki.cs.tmc.core.exceptions.TmcCoreException;
14+
import fi.helsinki.cs.tmc.utilities.BgTask;
15+
import fi.helsinki.cs.tmc.utilities.BgTaskListener;
16+
import fi.helsinki.cs.tmc.utilities.CancellableCallable;
1417
import java.awt.event.ActionEvent;
1518
import java.awt.event.ActionListener;
1619
import java.util.List;
@@ -93,50 +96,40 @@ public void run() {
9396
if (course.getReviewsUrl() == null) {
9497
return;
9598
}
96-
getReviews(course);
97-
98-
}
99-
100-
private void getReviews(Course course){
101-
final ProgressHandle progress = ProgressHandleFactory.createHandle("Checking for code reviews");
102-
progress.start();
103-
try {
104-
ListenableFuture<List<Review>> reviews = TmcCoreSingleton.getInstance()
105-
.getNewReviews(course);
106-
Futures.addCallback(reviews, new FutureCallback<List<Review>>() {
107-
108-
@Override
109-
public void onSuccess(List<Review> v) {
110-
success(v);
111-
progress.finish();
112-
99+
BgTaskListener bgTaskListener = new BgTaskListener<List<Review>>() {
100+
@Override
101+
public void bgTaskReady(List<Review> result) {
102+
boolean newReviews = reviewDb.setReviews(result);
103+
if (!newReviews && notifyAboutNoNewReviews) {
104+
dialogs.displayMessage("You have no unread code reviews.");
113105
}
106+
}
114107

115-
@Override
116-
public void onFailure(Throwable thrwbl) {
117-
fail(thrwbl);
118-
progress.finish();
108+
@Override
109+
public void bgTaskFailed(final Throwable ex) {
110+
final String msg = "Failed to check for code reviews";
111+
log.log(Level.INFO, msg, ex);
112+
if (!beQuiet) {
113+
dialogs.displayError(msg, ex);
119114
}
115+
}
120116

121-
});
122-
} catch (TmcCoreException ex) {
123-
progress.finish();
124-
Exceptions.printStackTrace(ex);
125-
}
126-
}
127-
128-
private void success(List<Review> list) {
129-
boolean newReviews = reviewDb.setReviews(list);
130-
if (!newReviews && notifyAboutNoNewReviews) {
131-
dialogs.displayMessage("You have no unread code reviews.");
132-
}
133-
}
117+
@Override
118+
public void bgTaskCancelled() {
119+
}
120+
};
121+
BgTask.start("Checking for code reviews", new CancellableCallable<List<Review>>() {
122+
private ListenableFuture<List<Review>> lf;
123+
@Override
124+
public List<Review> call() throws Exception {
125+
lf = TmcCoreSingleton.getInstance().getNewReviews(courseDb.getCurrentCourse());
126+
return lf.get();
127+
}
134128

135-
private void fail(Throwable thrwbl) {
136-
final String msg = "Failed to check for code reviews";
137-
log.log(Level.INFO, msg, thrwbl);
138-
if (!beQuiet) {
139-
dialogs.displayError(msg, thrwbl);
140-
}
129+
@Override
130+
public boolean cancel() {
131+
return lf.cancel(true);
132+
}
133+
}, bgTaskListener);
141134
}
142135
}

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

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import fi.helsinki.cs.tmc.model.CourseDb;
55
import fi.helsinki.cs.tmc.model.ProjectMediator;
66
import fi.helsinki.cs.tmc.model.TmcProjectInfo;
7-
import fi.helsinki.cs.tmc.model.NBTmcSettings;
7+
import fi.helsinki.cs.tmc.model.NbTmcSettings;
88
import fi.helsinki.cs.tmc.ui.TmcNotificationDisplayer;
99
import java.awt.event.ActionEvent;
1010
import java.awt.event.ActionListener;
@@ -16,11 +16,12 @@
1616

1717
public class CheckForUnopenedExercises implements ActionListener {
1818
public static boolean shouldRunOnStartup() {
19-
return NBTmcSettings.getDefault().isCheckingForUnopenedAtStartup();
19+
return NbTmcSettings.getDefault().isCheckingForUnopenedAtStartup();
2020
}
21-
22-
private static final TmcNotificationDisplayer.SingletonToken notifierToken = TmcNotificationDisplayer.createSingletonToken();
23-
21+
22+
private static final TmcNotificationDisplayer.SingletonToken notifierToken =
23+
TmcNotificationDisplayer.createSingletonToken();
24+
2425
private ProjectMediator projects;
2526
private CourseDb courseDb;
2627
private TmcNotificationDisplayer notifier;
@@ -30,12 +31,12 @@ public CheckForUnopenedExercises() {
3031
this.courseDb = CourseDb.getInstance();
3132
this.notifier = TmcNotificationDisplayer.getDefault();
3233
}
33-
34+
3435
@Override
3536
public void actionPerformed(ActionEvent e) {
3637
run();
3738
}
38-
39+
3940
public void run() {
4041
projects.callWhenProjectsCompletelyOpened(new Runnable() {
4142
@Override
@@ -68,7 +69,7 @@ private void showNotification(List<Exercise> unopenedExercises) {
6869
}
6970
notifier.notify(notifierToken, msg, getNotificationIcon(), prompt, openAction(unopenedExercises), NotificationDisplayer.Priority.LOW);
7071
}
71-
72+
7273
private ActionListener openAction(final List<Exercise> exercises) {
7374
return new ActionListener() {
7475
@Override
@@ -82,8 +83,8 @@ public void actionPerformed(ActionEvent e) {
8283
}
8384
};
8485
}
85-
86+
8687
private Icon getNotificationIcon() {
8788
return ImageUtilities.loadImageIcon("fi/helsinki/cs/tmc/smile.gif", false);
8889
}
89-
}
90+
}

0 commit comments

Comments
 (0)