Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrey Loskutov2019-04-30 15:26:56 +0000
committerAndrey Loskutov2019-05-02 13:34:25 +0000
commitead7de4749a856cec4c830d7bd331961cc5dad27 (patch)
tree6bbebf330176a611232d1ca03094cedb3b6eb0a5
parent068e046d670c32868130280243b61cfdad2440a1 (diff)
downloadeclipse.platform.text-ead7de4749a856cec4c830d7bd331961cc5dad27.tar.gz
eclipse.platform.text-ead7de4749a856cec4c830d7bd331961cc5dad27.tar.xz
eclipse.platform.text-ead7de4749a856cec4c830d7bd331961cc5dad27.zip
Bug 546828 - Editors based on FileDocumentProvider /
TextFileDocumentProvider lock UI on attempt to edit while build is running The change modifies FileDocumentProvider.getValidateStateRule() and DocumentProviderOperation created in TextFileDocumentProvider.validateState() to return non-null rule (referenced IFile) for IFileEditorInput's if the IResourceRuleFactory.validateEditRule() has no rule for us. This prevents UI freeze on attempt to modify a file while build is running. Instead of a freeze, we get a progress dialog with a possibility to cancel the (blocking) attempt to modify the file. Change-Id: I23a6ddab2ca8f31b5ba134301356c34250f5087c Signed-off-by: Andrey Loskutov <loskutov@gmx.de>
-rw-r--r--org.eclipse.ui.editors.tests/META-INF/MANIFEST.MF2
-rw-r--r--org.eclipse.ui.editors.tests/pom.xml2
-rw-r--r--org.eclipse.ui.editors.tests/src/org/eclipse/ui/editors/tests/EditorsTestSuite.java1
-rw-r--r--org.eclipse.ui.editors.tests/src/org/eclipse/ui/editors/tests/FileDocumentProviderTest.java129
-rw-r--r--org.eclipse.ui.editors.tests/src/org/eclipse/ui/editors/tests/TextFileDocumentProviderTest.java251
-rw-r--r--org.eclipse.ui.editors/META-INF/MANIFEST.MF2
-rw-r--r--org.eclipse.ui.editors/pom.xml2
-rw-r--r--org.eclipse.ui.editors/src/org/eclipse/ui/editors/text/FileDocumentProvider.java14
-rw-r--r--org.eclipse.ui.editors/src/org/eclipse/ui/editors/text/TextFileDocumentProvider.java14
9 files changed, 406 insertions, 11 deletions
diff --git a/org.eclipse.ui.editors.tests/META-INF/MANIFEST.MF b/org.eclipse.ui.editors.tests/META-INF/MANIFEST.MF
index 110f4b4b036..c24a6dc9af6 100644
--- a/org.eclipse.ui.editors.tests/META-INF/MANIFEST.MF
+++ b/org.eclipse.ui.editors.tests/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %Plugin.name
Bundle-SymbolicName: org.eclipse.ui.editors.tests;singleton:=true
-Bundle-Version: 3.11.300.qualifier
+Bundle-Version: 3.11.400.qualifier
Bundle-Vendor: %Plugin.providerName
Bundle-Localization: plugin
Export-Package: org.eclipse.ui.editors.tests
diff --git a/org.eclipse.ui.editors.tests/pom.xml b/org.eclipse.ui.editors.tests/pom.xml
index c08e4931569..81b8a7a5c5c 100644
--- a/org.eclipse.ui.editors.tests/pom.xml
+++ b/org.eclipse.ui.editors.tests/pom.xml
@@ -19,7 +19,7 @@
</parent>
<groupId>org.eclipse.ui</groupId>
<artifactId>org.eclipse.ui.editors.tests</artifactId>
- <version>3.11.300-SNAPSHOT</version>
+ <version>3.11.400-SNAPSHOT</version>
<packaging>eclipse-test-plugin</packaging>
<properties>
<testSuite>${project.artifactId}</testSuite>
diff --git a/org.eclipse.ui.editors.tests/src/org/eclipse/ui/editors/tests/EditorsTestSuite.java b/org.eclipse.ui.editors.tests/src/org/eclipse/ui/editors/tests/EditorsTestSuite.java
index 98f79171182..adb8c5598f7 100644
--- a/org.eclipse.ui.editors.tests/src/org/eclipse/ui/editors/tests/EditorsTestSuite.java
+++ b/org.eclipse.ui.editors.tests/src/org/eclipse/ui/editors/tests/EditorsTestSuite.java
@@ -33,6 +33,7 @@ import org.junit.runners.Suite.SuiteClasses;
MarkerAnnotationOrderTest.class,
ZoomTest.class,
FileDocumentProviderTest.class,
+ TextFileDocumentProviderTest.class,
StatusEditorTest.class
})
public class EditorsTestSuite {
diff --git a/org.eclipse.ui.editors.tests/src/org/eclipse/ui/editors/tests/FileDocumentProviderTest.java b/org.eclipse.ui.editors.tests/src/org/eclipse/ui/editors/tests/FileDocumentProviderTest.java
index 9538e5c5578..91531f44a9e 100644
--- a/org.eclipse.ui.editors.tests/src/org/eclipse/ui/editors/tests/FileDocumentProviderTest.java
+++ b/org.eclipse.ui.editors.tests/src/org/eclipse/ui/editors/tests/FileDocumentProviderTest.java
@@ -30,6 +30,7 @@ import org.eclipse.swt.widgets.Display;
import org.eclipse.core.internal.localstore.FileSystemResourceManager;
import org.eclipse.core.internal.resources.File;
+import org.eclipse.core.internal.resources.Workspace;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.ILog;
@@ -56,9 +57,12 @@ import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.internal.dialogs.EventLoopProgressMonitor;
+import org.eclipse.ui.intro.IIntroManager;
+import org.eclipse.ui.intro.IIntroPart;
import org.eclipse.ui.editors.text.FileDocumentProvider;
@@ -74,6 +78,7 @@ public class FileDocumentProviderTest {
private AtomicBoolean stoppedByTest;
private AtomicBoolean stopLockingFlag;
private LockJob lockJob;
+ private LockJob2 lockJob2;
private FileDocumentProviderMock fileProvider;
private FileSystemResourceManager fsManager;
private IEditorPart editor;
@@ -81,6 +86,7 @@ public class FileDocumentProviderTest {
@Before
public void setUp() throws Exception {
+ closeIntro(PlatformUI.getWorkbench());
IFolder folder = ResourceHelper.createFolder("FileDocumentProviderTestProject/test");
file = (File) ResourceHelper.createFile(folder, "file.txt", "");
assertTrue(file.exists());
@@ -90,6 +96,7 @@ public class FileDocumentProviderTest {
stoppedByTest = new AtomicBoolean(false);
fileProvider = new FileDocumentProviderMock();
lockJob = new LockJob("Locking workspace", file, stopLockingFlag, stoppedByTest);
+ lockJob2 = new LockJob2("Locking workspace", file, stopLockingFlag, stoppedByTest);
// We need the editor only to get the default editor status line manager
IWorkbench workbench = PlatformUI.getWorkbench();
@@ -126,6 +133,7 @@ public class FileDocumentProviderTest {
public void tearDown() throws Exception {
stopLockingFlag.set(true);
lockJob.cancel();
+ lockJob2.cancel();
if (editor != null) {
page.closeEditor(editor, false);
}
@@ -199,6 +207,34 @@ public class FileDocumentProviderTest {
assertTrue(stopLockingFlag.get());
}
+ @Test
+ public void testValidateStateForFileWhileWorkspaceIsLocked() throws Exception {
+ assertNotNull("Test must run in UI thread", Display.getCurrent());
+
+ // Start workspace job which will lock workspace operations on file
+ lockJob2.schedule();
+
+ Thread.sleep(100);
+
+ // Put an UI event in the queue which will stop the workspace lock job
+ // after a delay
+ Display.getCurrent().timerExec(600, new Runnable() {
+ @Override
+ public void run() {
+ stopLockingFlag.set(true);
+ System.out.println("UI event dispatched, lock removed");
+ }
+ });
+
+ // Original code will lock UI thread here because it will try to acquire
+ // workspace lock and no one will process UI events anymore
+ fileProvider.validateState(editor.getEditorInput(), editor.getSite().getShell());
+
+ System.out.println("Busy wait terminated, UI thread is operable again!");
+ assertFalse("Test deadlocked while waiting on resource lock", stoppedByTest.get());
+ assertTrue(stopLockingFlag.get());
+ }
+
/*
* Set current time stamp via java.nio to make sure
* org.eclipse.core.internal.resources.File.refreshLocal(int,
@@ -227,6 +263,17 @@ public class FileDocumentProviderTest {
ILog log = Platform.getLog(Platform.getBundle(PLUGIN_ID));
log.log(new Status(IStatus.ERROR, PLUGIN_ID, IStatus.OK, message, ex));
}
+
+ static void closeIntro(final IWorkbench wb) {
+ IWorkbenchWindow window = wb.getActiveWorkbenchWindow();
+ if (window != null) {
+ IIntroManager im = wb.getIntroManager();
+ IIntroPart intro = im.getIntro();
+ if (intro != null) {
+ im.closeIntro(intro);
+ }
+ }
+ }
}
class FileDocumentProviderMock extends FileDocumentProvider {
@@ -253,9 +300,9 @@ class FileDocumentProviderMock extends FileDocumentProvider {
/** Emulates what SVN plugin jobs are doing */
class LockJob extends WorkspaceJob {
- private final IResource resource;
- private AtomicBoolean stopFlag;
- private AtomicBoolean stoppedByTest;
+ final IResource resource;
+ AtomicBoolean stopFlag;
+ AtomicBoolean stoppedByTest;
public LockJob(String name, IResource resource, AtomicBoolean stopFlag, AtomicBoolean stoppedByTest) {
super(name);
@@ -266,7 +313,7 @@ class LockJob extends WorkspaceJob {
this.resource = resource;
}
- public IStatus run2(IProgressMonitor monitor) {
+ public IStatus run2() {
long startTime = System.currentTimeMillis();
// Wait maximum 5 minutes
int maxWaitTime = 5 * 60 * 1000;
@@ -312,7 +359,7 @@ class LockJob extends WorkspaceJob {
@Override
public void run(IProgressMonitor pm) throws CoreException {
try {
- run2(pm);
+ run2();
} catch (Exception e) {
// Re-throw as OperationCanceledException, which will be
// caught and re-thrown as InterruptedException below.
@@ -328,3 +375,75 @@ class LockJob extends WorkspaceJob {
}
}
+
+/** Emulates what AutoBuildJob is doing */
+class LockJob2 extends Job {
+
+ final IResource resource;
+ AtomicBoolean stopFlag;
+ AtomicBoolean stoppedByTest;
+
+ public LockJob2(String name, IResource resource, AtomicBoolean stopFlag, AtomicBoolean stoppedByTest) {
+ super(name);
+ this.stopFlag = stopFlag;
+ this.stoppedByTest = stoppedByTest;
+ setUser(true);
+ setSystem(true);
+ this.resource = resource;
+ setRule(ResourcesPlugin.getWorkspace().getRoot());
+ }
+
+ @Override
+ public boolean belongsTo(Object family) {
+ return super.belongsTo(family) || LockJob2.class == family;
+ }
+
+ @Override
+ public IStatus run(IProgressMonitor monitor) {
+ Workspace workspace = (Workspace) ResourcesPlugin.getWorkspace();
+ try {
+ workspace.prepareOperation(getRule(), monitor);
+ workspace.beginOperation(true);
+ run2();
+ } catch (CoreException e) {
+ FileDocumentProviderTest.logError(e.getMessage(), e);
+ } finally {
+ try {
+ workspace.endOperation(getRule(), false);
+ } catch (CoreException e) {
+ FileDocumentProviderTest.logError(e.getMessage(), e);
+ }
+ }
+ return monitor.isCanceled() ? Status.CANCEL_STATUS : Status.OK_STATUS;
+ }
+
+ public IStatus run2() {
+ long startTime = System.currentTimeMillis();
+ // Wait maximum 5 minutes
+ int maxWaitTime = 5 * 60 * 1000;
+ long stopTime = startTime + maxWaitTime;
+
+ System.out.println("Starting the busy wait while holding lock on: " + resource.getFullPath());
+ try {
+ while (!stopFlag.get()) {
+ try {
+ if (System.currentTimeMillis() > stopTime) {
+ FileDocumentProviderTest.logError("Tiemout occured while waiting on test to finish",
+ new IllegalStateException());
+ stoppedByTest.set(true);
+ return Status.CANCEL_STATUS;
+ }
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ stoppedByTest.set(true);
+ FileDocumentProviderTest.logError("Lock job was interrupted while waiting on test to finish", e);
+ e.printStackTrace();
+ return Status.CANCEL_STATUS;
+ }
+ }
+ } finally {
+ System.out.println("Lock task terminated");
+ }
+ return Status.OK_STATUS;
+ }
+}
diff --git a/org.eclipse.ui.editors.tests/src/org/eclipse/ui/editors/tests/TextFileDocumentProviderTest.java b/org.eclipse.ui.editors.tests/src/org/eclipse/ui/editors/tests/TextFileDocumentProviderTest.java
new file mode 100644
index 00000000000..dde68474e1b
--- /dev/null
+++ b/org.eclipse.ui.editors.tests/src/org/eclipse/ui/editors/tests/TextFileDocumentProviderTest.java
@@ -0,0 +1,251 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Andrey Loskutov.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Andrey Loskutov <loskutov@gmx.de> - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.editors.tests;
+
+import static org.eclipse.ui.editors.tests.FileDocumentProviderTest.closeIntro;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.nio.file.Files;
+import java.nio.file.attribute.FileTime;
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.eclipse.swt.widgets.Display;
+
+import org.eclipse.core.internal.localstore.FileSystemResourceManager;
+import org.eclipse.core.internal.resources.File;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IProgressMonitorWithBlocking;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.jobs.Job;
+
+import org.eclipse.core.resources.IFolder;
+
+import org.eclipse.core.filebuffers.tests.ResourceHelper;
+
+import org.eclipse.jface.action.IStatusLineManager;
+
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.ide.IDE;
+import org.eclipse.ui.internal.dialogs.EventLoopProgressMonitor;
+
+import org.eclipse.ui.editors.text.TextFileDocumentProvider;
+
+/**
+ * Test checking UI deadlock on modifying the TextFileDocumentProvider's
+ * underlined file.
+ */
+public class TextFileDocumentProviderTest {
+
+ private File file;
+ private AtomicBoolean stoppedByTest;
+ private AtomicBoolean stopLockingFlag;
+ private LockJob lockJob;
+ private LockJob2 lockJob2;
+ private TextFileDocumentProvider fileProvider;
+ private FileSystemResourceManager fsManager;
+ private IEditorPart editor;
+ private IWorkbenchPage page;
+
+ @Before
+ public void setUp() throws Exception {
+ closeIntro(PlatformUI.getWorkbench());
+ IFolder folder = ResourceHelper.createFolder("FileDocumentProviderTestProject/test");
+ file = (File) ResourceHelper.createFile(folder, "file.txt", "");
+ assertTrue(file.exists());
+ fsManager = file.getLocalManager();
+ assertTrue(fsManager.fastIsSynchronized(file));
+ stopLockingFlag = new AtomicBoolean(false);
+ stoppedByTest = new AtomicBoolean(false);
+ fileProvider = new TextFileDocumentProvider();
+ lockJob = new LockJob("Locking workspace", file, stopLockingFlag, stoppedByTest);
+ lockJob2 = new LockJob2("Locking workspace", file, stopLockingFlag, stoppedByTest);
+
+ // We need the editor only to get the default editor status line manager
+ IWorkbench workbench = PlatformUI.getWorkbench();
+ page = workbench.getActiveWorkbenchWindow().getActivePage();
+ editor = IDE.openEditor(page, file);
+ TestUtil.runEventLoop();
+
+ IStatusLineManager statusLineManager = editor.getEditorSite().getActionBars().getStatusLineManager();
+ // This is default monitor which almost all editors are using
+ IProgressMonitor progressMonitor = statusLineManager.getProgressMonitor();
+ assertNotNull(progressMonitor);
+ assertFalse(progressMonitor instanceof NullProgressMonitor);
+ assertFalse(progressMonitor instanceof EventLoopProgressMonitor);
+ assertTrue(progressMonitor instanceof IProgressMonitorWithBlocking);
+
+ // Because this monitor is not EventLoopProgressMonitor, it will not
+ // process UI events while waiting on workspace lock
+ fileProvider.setProgressMonitor(progressMonitor);
+
+ TestUtil.waitForJobs(500, 5000);
+ Job[] jobs = Job.getJobManager().find(null);
+ String jobsList = Arrays.toString(jobs);
+ System.out.println("Still running jobs: " + jobsList);
+ if (!Job.getJobManager().isIdle()) {
+ jobs = Job.getJobManager().find(null);
+ for (Job job : jobs) {
+ System.out.println("Going to cancel: " + job.getName() + " / " + job);
+ job.cancel();
+ }
+ }
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ stopLockingFlag.set(true);
+ lockJob.cancel();
+ lockJob2.cancel();
+ if (editor != null) {
+ page.closeEditor(editor, false);
+ }
+ ResourceHelper.deleteProject(file.getProject().getName());
+ TestUtil.runEventLoop();
+ TestUtil.cleanUp();
+ }
+
+ @Test
+ public void testSynchronizeInputWhileWorkspaceIsLocked1() throws Exception {
+ // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=482354
+ assertNotNull("Test must run in UI thread", Display.getCurrent());
+ fileProvider.connect(editor.getEditorInput());
+
+ // Start workspace job which will lock workspace operations on file via
+ // rule
+ lockJob.schedule();
+
+ // touch the file of the editor
+ makeSureResourceIsOutOfDate();
+
+ // Put an UI event in the queue which will stop the workspace lock job
+ // after a delay so that we can verify the UI events are still
+ // dispatched after the call to refreshFile() below
+ Display.getCurrent().timerExec(500, new Runnable() {
+ @Override
+ public void run() {
+ stopLockingFlag.set(true);
+ System.out.println("UI event dispatched, lock removed");
+ }
+ });
+
+ // Original code will lock UI thread here because it will try to acquire
+ // resource lock and no one will process UI events anymore
+ fileProvider.synchronize(editor.getEditorInput());
+
+ System.out.println("Busy wait terminated, UI thread is operable again!");
+ assertFalse("Test deadlocked while waiting on resource lock", stoppedByTest.get());
+ assertTrue(stopLockingFlag.get());
+ }
+
+ @Test
+ public void testSynchronizeInputWhileWorkspaceIsLocked2() throws Exception {
+ // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=482354
+ assertNotNull("Test must run in UI thread", Display.getCurrent());
+
+ fileProvider.connect(editor.getEditorInput());
+
+ // Start workspace job which will lock workspace operations on file via
+ // rule
+ lockJob.schedule();
+
+ // touch the file of the editor
+ makeSureResourceIsOutOfDate();
+
+ // Put an UI event in the queue which will stop the workspace lock job
+ // after a delay so that we can verify the UI events are still
+ // dispatched after the call to refreshFile() below
+ Display.getCurrent().timerExec(500, new Runnable() {
+ @Override
+ public void run() {
+ stopLockingFlag.set(true);
+ System.out.println("UI event dispatched, lock removed");
+ }
+ });
+
+ // Original code will lock UI thread here because it will try to acquire
+ // resource lock and no one will process UI events anymore
+ fileProvider.synchronize(editor.getEditorInput());
+
+ System.out.println("Busy wait terminated, UI thread is operable again!");
+ assertFalse("Test deadlocked while waiting on resource lock", stoppedByTest.get());
+ assertTrue(stopLockingFlag.get());
+ }
+
+ @Test
+ public void testValidateStateForFileWhileWorkspaceIsLocked() throws Exception {
+ assertNotNull("Test must run in UI thread", Display.getCurrent());
+
+ fileProvider.connect(editor.getEditorInput());
+
+ // Start workspace job which will lock workspace operations on file
+ lockJob2.schedule();
+
+ Thread.sleep(100);
+
+ // Put an UI event in the queue which will stop the workspace lock job
+ // after a delay
+ Display.getCurrent().timerExec(600, new Runnable() {
+ @Override
+ public void run() {
+ stopLockingFlag.set(true);
+ System.out.println("UI event dispatched, lock removed");
+ }
+ });
+
+ // Original code will lock UI thread here because it will try to acquire
+ // workspace lock and no one will process UI events anymore
+ fileProvider.validateState(editor.getEditorInput(), editor.getSite().getShell());
+
+ System.out.println("Busy wait terminated, UI thread is operable again!");
+ assertFalse("Test deadlocked while waiting on resource lock", stoppedByTest.get());
+ assertTrue(stopLockingFlag.get());
+ }
+
+ /*
+ * Set current time stamp via java.nio to make sure
+ * org.eclipse.core.internal.resources.File.refreshLocal(int,
+ * IProgressMonitor) will call super.refreshLocal(IResource.DEPTH_ZERO,
+ * monitor) and so lock the UI by trying to access resource locked by the
+ * job
+ */
+ private void makeSureResourceIsOutOfDate() throws Exception {
+ int count = 0;
+ Files.setLastModifiedTime(file.getLocation().toFile().toPath(),
+ FileTime.fromMillis(System.currentTimeMillis()));
+ // Give the file system a chance to have a *different* timestamp
+ Thread.sleep(100);
+ while (fsManager.fastIsSynchronized(file) && count < 1000) {
+ Files.setLastModifiedTime(file.getLocation().toFile().toPath(),
+ FileTime.fromMillis(System.currentTimeMillis()));
+ Thread.sleep(10);
+ count++;
+ }
+ System.out.println("Managed to update file after " + count + " attempts");
+ assertFalse(fsManager.fastIsSynchronized(file));
+ }
+
+}
+
+
diff --git a/org.eclipse.ui.editors/META-INF/MANIFEST.MF b/org.eclipse.ui.editors/META-INF/MANIFEST.MF
index e9aeb5d8dd9..46b6cfdc3f4 100644
--- a/org.eclipse.ui.editors/META-INF/MANIFEST.MF
+++ b/org.eclipse.ui.editors/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.ui.editors; singleton:=true
-Bundle-Version: 3.11.400.qualifier
+Bundle-Version: 3.11.500.qualifier
Bundle-Activator: org.eclipse.ui.internal.editors.text.EditorsPlugin
Bundle-ActivationPolicy: lazy
Bundle-Vendor: %providerName
diff --git a/org.eclipse.ui.editors/pom.xml b/org.eclipse.ui.editors/pom.xml
index 8adf7a15989..3179a966059 100644
--- a/org.eclipse.ui.editors/pom.xml
+++ b/org.eclipse.ui.editors/pom.xml
@@ -18,6 +18,6 @@
</parent>
<groupId>org.eclipse.ui</groupId>
<artifactId>org.eclipse.ui.editors</artifactId>
- <version>3.11.400-SNAPSHOT</version>
+ <version>3.11.500-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
diff --git a/org.eclipse.ui.editors/src/org/eclipse/ui/editors/text/FileDocumentProvider.java b/org.eclipse.ui.editors/src/org/eclipse/ui/editors/text/FileDocumentProvider.java
index c7351d7bb38..a61d0616988 100644
--- a/org.eclipse.ui.editors/src/org/eclipse/ui/editors/text/FileDocumentProvider.java
+++ b/org.eclipse.ui.editors/src/org/eclipse/ui/editors/text/FileDocumentProvider.java
@@ -1128,7 +1128,19 @@ public class FileDocumentProvider extends StorageDocumentProvider {
protected ISchedulingRule getValidateStateRule(Object element) {
if (element instanceof IFileEditorInput) {
IFileEditorInput input= (IFileEditorInput) element;
- return fResourceRuleFactory.validateEditRule(new IResource[] { input.getFile() });
+ IFile file= input.getFile();
+ ISchedulingRule validateEditRule= fResourceRuleFactory.validateEditRule(new IResource[] { file });
+ if (validateEditRule == null) {
+ // Note that factory decides to provide a null rule for modifiable files (not read-only).
+ // Null rule means, that org.eclipse.core.internal.resources.WorkManager.checkIn(ISchedulingRule, IProgressMonitor)
+ // will run jobManager.beginRule(null, monitor); which will NOT show any progress dialog
+ // and will *immediately* lock UI thread via lock.acquire(); while the workspace is locked
+ // Providing here a file we enforce the progress dialog, where this operation can be cancelled by user,
+ // so that an occasional "Modify" or "Save" of the editor will NOT block UI forever.
+ return file;
+ } else {
+ return validateEditRule;
+ }
}
return null;
}
diff --git a/org.eclipse.ui.editors/src/org/eclipse/ui/editors/text/TextFileDocumentProvider.java b/org.eclipse.ui.editors/src/org/eclipse/ui/editors/text/TextFileDocumentProvider.java
index 5088a986e55..b00bcfd1748 100644
--- a/org.eclipse.ui.editors/src/org/eclipse/ui/editors/text/TextFileDocumentProvider.java
+++ b/org.eclipse.ui.editors/src/org/eclipse/ui/editors/text/TextFileDocumentProvider.java
@@ -1017,7 +1017,19 @@ public class TextFileDocumentProvider implements IDocumentProvider, IDocumentPro
public ISchedulingRule getSchedulingRule() {
if (info.fElement instanceof IFileEditorInput) {
IFileEditorInput input= (IFileEditorInput) info.fElement;
- return fResourceRuleFactory.validateEditRule(new IResource[] { input.getFile() });
+ IFile file= input.getFile();
+ ISchedulingRule validateEditRule= fResourceRuleFactory.validateEditRule(new IResource[] { file });
+ if (validateEditRule == null) {
+ // Note that factory decides to provide a null rule for modifiable files (not read-only).
+ // Null rule means, that org.eclipse.core.internal.resources.WorkManager.checkIn(ISchedulingRule, IProgressMonitor)
+ // will run jobManager.beginRule(null, monitor); which will NOT show any progress dialog
+ // and will *immediately* lock UI thread via lock.acquire(); while the workspace is locked
+ // Providing here a file we enforce the progress dialog, where this operation can be cancelled by user,
+ // so that an occasional "Modify" or "Save" of the editor will NOT block UI forever.
+ return file;
+ } else {
+ return validateEditRule;
+ }
}
return null;
}

Back to the top