Skip to content

Commit f361f4b

Browse files
committed
Perform element changes always in a non UI thread
Currently PackageExplorerContentProvider receives events for changed elements from different threads and already has handling to perform only certain actions in the UI thread. But it does not really account for the case when the event itself is triggered from the UI thread in which case lengthy operation can take place in the UI. This now checks if the change is using the UI and otherwise schedules a job to perform the required actions in the background.
1 parent 642cdca commit f361f4b

2 files changed

Lines changed: 63 additions & 4 deletions

File tree

org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/packageview/ContentProviderTests3.java

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import static org.junit.jupiter.api.Assertions.fail;
2222

2323
import java.io.File;
24+
import java.util.concurrent.CountDownLatch;
25+
import java.util.concurrent.TimeUnit;
2426

2527
import org.junit.jupiter.api.AfterEach;
2628
import org.junit.jupiter.api.BeforeEach;
@@ -29,7 +31,10 @@
2931
import org.eclipse.jdt.testplugin.JavaProjectHelper;
3032
import org.eclipse.jdt.testplugin.JavaTestPlugin;
3133

34+
import org.eclipse.core.runtime.NullProgressMonitor;
35+
import org.eclipse.core.runtime.OperationCanceledException;
3236
import org.eclipse.core.runtime.Path;
37+
import org.eclipse.core.runtime.jobs.Job;
3338

3439
import org.eclipse.core.resources.IFile;
3540
import org.eclipse.core.resources.IFolder;
@@ -54,6 +59,7 @@
5459
import org.eclipse.jdt.core.IPackageFragment;
5560
import org.eclipse.jdt.core.IPackageFragmentRoot;
5661

62+
import org.eclipse.jdt.internal.ui.packageview.PackageExplorerContentProvider;
5763
import org.eclipse.jdt.internal.ui.util.CoreUtility;
5864

5965

@@ -212,9 +218,25 @@ public void testDeleteBottomLevelFragmentFolding() throws Exception {
212218
protected void sendEvent(IJavaElementDelta delta) {
213219
IElementChangedListener listener= (IElementChangedListener) fProvider;
214220
listener.elementChanged(new ElementChangedEvent(delta, ElementChangedEvent.POST_CHANGE));
215-
216-
//force events from dispaly
217-
while(fMyPart.getTreeViewer().getControl().getDisplay().readAndDispatch()) {
221+
CountDownLatch latch = new CountDownLatch(1);
222+
new Thread(new Runnable() {
223+
224+
@Override
225+
public void run() {
226+
try {
227+
Job.getJobManager().join(PackageExplorerContentProvider.class, new NullProgressMonitor());
228+
} catch (OperationCanceledException | InterruptedException e) {
229+
}
230+
latch.countDown();
231+
}
232+
}).start();
233+
//force events from display
234+
try {
235+
while(!latch.await(10, TimeUnit.MILLISECONDS)) {
236+
while(fMyPart.getTreeViewer().getControl().getDisplay().readAndDispatch()) {
237+
}
238+
}
239+
} catch (InterruptedException e) {
218240
}
219241
}
220242

org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/packageview/PackageExplorerContentProvider.java

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import java.util.Collection;
1919
import java.util.Iterator;
2020
import java.util.List;
21+
import java.util.Queue;
22+
import java.util.concurrent.ConcurrentLinkedQueue;
2123

2224
import org.eclipse.swt.widgets.Control;
2325
import org.eclipse.swt.widgets.Display;
@@ -28,6 +30,7 @@
2830
import org.eclipse.core.runtime.IProgressMonitor;
2931
import org.eclipse.core.runtime.IStatus;
3032
import org.eclipse.core.runtime.Status;
33+
import org.eclipse.core.runtime.jobs.Job;
3134

3235
import org.eclipse.core.resources.IFolder;
3336
import org.eclipse.core.resources.IProject;
@@ -93,6 +96,8 @@ public class PackageExplorerContentProvider extends StandardJavaElementContentPr
9396

9497
private UIJob fUpdateJob;
9598

99+
private final DeltaJob fdeltaJob;
100+
96101
/**
97102
* We use a cache to know whether a package has a single child for the hierarchical representation.
98103
* This avoids looping over all packages for each call to
@@ -107,6 +112,7 @@ public class PackageExplorerContentProvider extends StandardJavaElementContentPr
107112
*/
108113
public PackageExplorerContentProvider(boolean provideMembers) {
109114
super(provideMembers);
115+
fdeltaJob= new DeltaJob();
110116
fShowLibrariesNode= false;
111117
fIsFlatLayout= false;
112118
fFoldPackages= arePackagesFoldedInHierarchicalLayout();
@@ -127,6 +133,12 @@ protected Object getViewerInput() {
127133

128134
@Override
129135
public void elementChanged(final ElementChangedEvent event) {
136+
IJavaElementDelta delta= event.getDelta();
137+
fdeltaJob.queue.add(delta);
138+
fdeltaJob.schedule();
139+
}
140+
141+
protected void processDelta(IJavaElementDelta delta) {
130142
final ArrayList<Runnable> runnables= new ArrayList<>();
131143
try {
132144
clearPackageCache();
@@ -136,7 +148,7 @@ public void elementChanged(final ElementChangedEvent event) {
136148
if (inputDeleted(runnables))
137149
return;
138150

139-
processDelta(event.getDelta(), runnables);
151+
processDelta(delta, runnables);
140152
} catch (JavaModelException e) {
141153
JavaPlugin.log(e);
142154
} finally {
@@ -1006,4 +1018,29 @@ public void propertyChange(PropertyChangeEvent event) {
10061018
}
10071019
}
10081020
}
1021+
1022+
private final class DeltaJob extends Job {
1023+
private Queue<IJavaElementDelta> queue= new ConcurrentLinkedQueue<>();
1024+
1025+
DeltaJob() {
1026+
super(PackagesMessages.PackageExplorerContentProvider_update_job_description);
1027+
setSystem(true);
1028+
}
1029+
1030+
@Override
1031+
public boolean belongsTo(Object family) {
1032+
return family == PackageExplorerContentProvider.class;
1033+
}
1034+
1035+
@Override
1036+
protected IStatus run(IProgressMonitor monitor) {
1037+
1038+
IJavaElementDelta delta;
1039+
while ((delta= queue.poll()) != null) {
1040+
processDelta(delta);
1041+
}
1042+
return Status.OK_STATUS;
1043+
}
1044+
1045+
}
10091046
}

0 commit comments

Comments
 (0)