Fix for Bug 59899 Encoding changes need to notify clients
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Container.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Container.java
index 362608e..8dcfe18 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Container.java
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Container.java
@@ -12,8 +12,10 @@
 
 import java.util.*;
 import org.eclipse.core.internal.localstore.HistoryStore;
+import org.eclipse.core.internal.utils.Policy;
 import org.eclipse.core.resources.*;
 import org.eclipse.core.runtime.*;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
 
 public abstract class Container extends Resource implements IContainer {
 	protected Container(IPath path, Workspace container) {
@@ -239,10 +241,43 @@
 
 	/* (non-Javadoc)
 	 * @see IContainer#setDefaultCharset(String)
+	 * @deprecated Replaced by {@link #setDefaultCharset(String, IProgressMonitor)} which 
+	 * 	is a workspace operation and reports changes in resource deltas.
 	 */
 	public void setDefaultCharset(String charset) throws CoreException {
 		ResourceInfo info = getResourceInfo(false, false);
 		checkAccessible(getFlags(info));
 		workspace.getCharsetManager().setCharsetFor(getFullPath(), charset);
 	}
+
+	/* (non-Javadoc)
+	 * @see IContainer#setDefaultCharset(String, IProgressMonitor)
+	 */
+	public void setDefaultCharset(String charset, IProgressMonitor monitor) throws CoreException {
+		monitor = Policy.monitorFor(monitor);
+		try {
+			String message = Policy.bind("resources.settingDefaultCharsetContainer", getFullPath().toString()); //$NON-NLS-1$
+			monitor.beginTask(message, Policy.totalWork);
+			// need to get the project as a scheduling rule because we might be 
+			// creating a new folder/file to hold the project settings
+			final ISchedulingRule rule = workspace.getRuleFactory().modifyRule(getProject());
+			try {
+				workspace.prepareOperation(rule, monitor);
+				ResourceInfo info = getResourceInfo(false, false);
+				checkAccessible(getFlags(info));
+				workspace.beginOperation(true);
+				// TODO: https://bugs.eclipse.org/bugs/show_bug.cgi?id=59899
+				// Changing the encoding needs to notify clients.
+				workspace.getCharsetManager().setCharsetFor(getFullPath(), charset);
+				monitor.worked(Policy.opWork);
+			} catch (OperationCanceledException e) {
+				workspace.getWorkManager().operationCanceled();
+				throw e;
+			} finally {
+				workspace.endOperation(rule, true, Policy.subMonitorFor(monitor, Policy.buildWork));
+			}
+		} finally {
+			monitor.done();
+		}
+	}
 }
\ No newline at end of file
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/File.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/File.java
index e4b0152..6d2d804 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/File.java
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/File.java
@@ -373,6 +373,8 @@
 
 	/* (non-Javadoc)
 	 * @see IFile#setCharset(String)
+	 * @deprecated Replaced by {@link #setCharset(String, IProgressMonitor)} which 
+	 * 	is a workspace operation and reports changes in resource deltas.
 	 */
 	public void setCharset(String newCharset) throws CoreException {
 		ResourceInfo info = getResourceInfo(false, false);
@@ -381,6 +383,37 @@
 	}
 
 	/* (non-Javadoc)
+	 * @see IFile#setCharset(String, IProgressMonitor)
+	 */
+	public void setCharset(String newCharset, IProgressMonitor monitor) throws CoreException {
+		monitor = Policy.monitorFor(monitor);
+		try {
+			String message = Policy.bind("resources.settingCharset", getFullPath().toString()); //$NON-NLS-1$
+			monitor.beginTask(message, Policy.totalWork);
+			// need to get the project as a scheduling rule because we might be creating a new folder/file to
+			// hold the project settings
+			final ISchedulingRule rule = workspace.getRuleFactory().modifyRule(getProject());
+			try {
+				workspace.prepareOperation(rule, monitor);
+				ResourceInfo info = getResourceInfo(false, false);
+				checkAccessible(getFlags(info));
+				workspace.beginOperation(true);
+				// TODO: https://bugs.eclipse.org/bugs/show_bug.cgi?id=59899
+				// Changing the encoding needs to notify clients.
+				workspace.getCharsetManager().setCharsetFor(getFullPath(), newCharset);
+				monitor.worked(Policy.opWork);
+			} catch (OperationCanceledException e) {
+				workspace.getWorkManager().operationCanceled();
+				throw e;
+			} finally {
+				workspace.endOperation(rule, true, Policy.subMonitorFor(monitor, Policy.buildWork));
+			}
+		} finally {
+			monitor.done();
+		}
+	}
+
+	/* (non-Javadoc)
 	 * @see IFile#setContents(InputStream, boolean, boolean, IProgressMonitor)
 	 */
 	public void setContents(InputStream content, boolean force, boolean keepHistory, IProgressMonitor monitor) throws CoreException {
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/WorkspaceRoot.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/WorkspaceRoot.java
index 2239c57..a3c8d97 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/WorkspaceRoot.java
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/WorkspaceRoot.java
@@ -12,8 +12,10 @@
 
 import java.util.HashMap;
 import org.eclipse.core.internal.utils.Assert;
+import org.eclipse.core.internal.utils.Policy;
 import org.eclipse.core.resources.*;
 import org.eclipse.core.runtime.*;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
 
 public class WorkspaceRoot extends Container implements IWorkspaceRoot {
 	/**
@@ -216,6 +218,8 @@
 
 	/**
 	 * @see IContainer#setDefaultCharset(String)
+	 * @deprecated Replaced by {@link #setDefaultCharset(String, IProgressMonitor)} which 
+	 * 	is a workspace operation and reports changes in resource deltas.
 	 */
 	public void setDefaultCharset(String charset) throws CoreException {
 		// directly change the Resource plugin's preference for encoding
@@ -227,6 +231,42 @@
 	}
 
 	/**
+	 * @see IContainer#setDefaultCharset(String, IProgressMonitor)
+	 */
+	public void setDefaultCharset(String charset, IProgressMonitor monitor) throws CoreException {
+		monitor = Policy.monitorFor(monitor);
+		try {
+			String message = Policy.bind("resources.settingDefaultCharsetWorkspace"); //$NON-NLS-1$
+			monitor.beginTask(message, Policy.totalWork);
+			final ISchedulingRule rule = workspace.getRuleFactory().modifyRule(this);
+			try {
+				workspace.prepareOperation(rule, monitor);
+				ResourceInfo info = getResourceInfo(false, false);
+				checkAccessible(getFlags(info));
+				workspace.beginOperation(true);
+
+				// TODO: https://bugs.eclipse.org/bugs/show_bug.cgi?id=59899
+				// Changing the encoding needs to notify clients.
+				// directly change the Resource plugin's preference for encoding
+				Preferences resourcesPreferences = ResourcesPlugin.getPlugin().getPluginPreferences();
+				if (charset != null)
+					resourcesPreferences.setValue(ResourcesPlugin.PREF_ENCODING, charset);
+				else
+					resourcesPreferences.setToDefault(ResourcesPlugin.PREF_ENCODING);
+
+				monitor.worked(Policy.opWork);
+			} catch (OperationCanceledException e) {
+				workspace.getWorkManager().operationCanceled();
+				throw e;
+			} finally {
+				workspace.endOperation(rule, true, Policy.subMonitorFor(monitor, Policy.buildWork));
+			}
+		} finally {
+			monitor.done();
+		}
+	}
+
+	/**
 	 * @see IResource#setLocalTimeStamp(long)
 	 */
 	public long setLocalTimeStamp(long value) throws CoreException {
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/messages.properties b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/messages.properties
index 17a5ea4..867f559 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/messages.properties
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/messages.properties
@@ -236,6 +236,9 @@
 resources.savingEncoding = Could not save encoding settings.
 resources.setDesc = Setting project description.
 resources.setLocal = Setting resource local flag.
+resources.settingCharset = Setting charset for resource: {0}.
+resources.settingDefaultCharsetContainer = Setting default charset for resource: {0}.
+resources.settingDefaultCharsetWorkspace = Setting the default charset for the workspace.
 resources.settingContents = Setting contents: {0}.
 resources.shutdown = Workspace was not properly initialized or has already shutdown.
 resources.shutdownProblems = Problem on shutdown.
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/resources/IContainer.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/resources/IContainer.java
index ecc1f50..a932608 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/resources/IContainer.java
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/resources/IContainer.java
@@ -389,16 +389,49 @@
 	public IFile[] findDeletedMembersWithHistory(int depth, IProgressMonitor monitor) throws CoreException;
 
 	/**
-	 * Sets the default charset for this container.
+	 * Sets the default charset for this container. Passing a value of <code>null</code>
+	 * will remove the default charset setting for this resource.
 	 *
 	 * @param charset a charset string, or <code>null</code>
-	 * @throws CoreException if this method fails Reasons include:
+	 * @exception CoreException if this method fails Reasons include:
 	 * <ul>
 	 * <li> This resource does not exist.</li>
-	 * <li> An error happened while persisting this setting .</li>
+	 * <li> An error happened while persisting this setting.</li>
+	 * </ul>
+	 * @see IContainer#getDefaultCharset()
+	 * @since 3.0
+	 * @deprecated Replaced by {@link #setDefaultCharset(String, IProgressMonitor)} which 
+	 * 	is a workspace operation and reports changes in resource deltas.
+	 */
+	public void setDefaultCharset(String charset) throws CoreException;
+
+	/**
+	 * Sets the default charset for this container. Passing a value of <code>null</code>
+	 * will remove the default charset setting for this resource.
+	 * <p>
+	 * This method changes resources; these changes will be reported
+	 * in a subsequent resource change event, including an indication 
+	 * that the encoding of affected resources has been changed.
+	 * </p>
+	 * <p>
+	 * This method is long-running; progress and cancellation are provided
+	 * by the given progress monitor. 
+	 * </p>
+	 *
+	 * @param charset a charset string, or <code>null</code>
+	 * @param monitor a progress monitor, or <code>null</code> if progress
+	 *    reporting is not desired
+	 * @exception OperationCanceledException if the operation is canceled. 
+	 * Cancelation can occur even if no progress monitor is provided.
+	 * @exception CoreException if this method fails Reasons include:
+	 * <ul>
+	 * <li> This resource is not accessible.</li>
+	 * <li> An error happened while persisting this setting.</li>
+	 * <li> Resource changes are disallowed during certain types of resource change 
+	 *       event notification. See {@link IResourceChangeEvent} for more details.</li>
 	 * </ul>
 	 * @see IContainer#getDefaultCharset()
 	 * @since 3.0
 	 */
-	public void setDefaultCharset(String charset) throws CoreException;
+	public void setDefaultCharset(String charset, IProgressMonitor monitor) throws CoreException;
 }
\ No newline at end of file
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/resources/IFile.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/resources/IFile.java
index 826e146..8852b86 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/resources/IFile.java
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/resources/IFile.java
@@ -680,18 +680,51 @@
 	public void move(IPath destination, boolean force, boolean keepHistory, IProgressMonitor monitor) throws CoreException;
 
 	/**
-	 * Sets the charset for this file.
+	 * Sets the charset for this file. Passing a value of <code>null</code>
+	 * will remove the charset setting for this resource.
 	 * 
 	 * @param newCharset a charset name, or <code>null</code>
-	 * @throws CoreException if this method fails. Reasons include:
+	 * @exception CoreException if this method fails. Reasons include:
 	 * <ul>
 	 * <li> This resource does not exist.</li>
-	 * <li> An error happened while persisting this setting .</li> 
+	 * <li> An error happened while persisting this setting.</li> 
+	 * </ul>
+	 * @see #getCharset()
+	 * @since 3.0
+	 * @deprecated Replaced by {@link #setCharset(String, IProgressMonitor)} which 
+	 * 	is a workspace operation and reports changes in resource deltas.
+	 */
+	public void setCharset(String newCharset) throws CoreException;
+
+	/**
+	 * Sets the charset for this file. Passing a value of <code>null</code>
+	 * will remove the charset setting for this resource.
+	 * <p>
+	 * This method changes resources; these changes will be reported
+	 * in a subsequent resource change event, including an indication 
+	 * that this file's encoding has changed.
+	 * </p>
+	 * <p>
+	 * This method is long-running; progress and cancellation are provided
+	 * by the given progress monitor. 
+	 * </p>
+	 * 
+	 * @param newCharset a charset name, or <code>null</code>
+	 * @param monitor a progress monitor, or <code>null</code> if progress
+	 *    reporting is not desired
+	 * @exception OperationCanceledException if the operation is canceled. 
+	 * Cancelation can occur even if no progress monitor is provided.
+	 * @exception CoreException if this method fails. Reasons include:
+	 * <ul>
+	 * <li> This resource does not exist.</li>
+	 * <li> An error happened while persisting this setting.</li> 
+	 * <li> Resource changes are disallowed during certain types of resource change 
+	 *       event notification. See {@link IResourceChangeEvent} for more details.</li>
 	 * </ul>
 	 * @see #getCharset()
 	 * @since 3.0
 	 */
-	public void setCharset(String newCharset) throws CoreException;
+	public void setCharset(String newCharset, IProgressMonitor monitor) throws CoreException;
 
 	/**
 	 * Sets the contents of this file to the bytes in the given input stream.
@@ -704,7 +737,7 @@
 	 * <p>
 	 * This method changes resources; these changes will be reported
 	 * in a subsequent resource change event, including an indication 
-	 * that this file's content have been changed.
+	 * that this file's contents have been changed.
 	 * </p>
 	 * <p>
 	 * This method is long-running; progress and cancellation are provided
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/resources/IResourceDelta.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/resources/IResourceDelta.java
index 7cef864..4745867 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/resources/IResourceDelta.java
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/resources/IResourceDelta.java
@@ -166,6 +166,14 @@
 	public static final int DESCRIPTION = 0x80000;
 
 	/**
+	 * Change constant (bit mask) indicating that the encoding of the resource has changed.
+	 * 
+	 * @see IResourceDelta#getFlags() 
+	 * @since 3.0
+	 */
+	public static final int ENCODING = 0x100000;
+
+	/**
 	 * Accepts the given visitor.
 	 * The only kinds of resource deltas visited 
 	 * are <code>ADDED</code>, <code>REMOVED</code>, 
@@ -360,6 +368,7 @@
 	 * <li><code>CONTENT</code> - The bytes contained by the resource have 
 	 * 		been altered, or <code>IResource.touch</code> has been called on 
 	 * 		the resource.</li>
+	 * <li><code>ENCODING</code> - The encoding of the resource has been altered.</li>
 	 * <li><code>DESCRIPTION</code> - The description of the project has been altered,
 	 * 		or <code>IResource.touch</code> has been called on the project.
 	 * 		This flag is only valid for project resources.</li>
@@ -410,6 +419,7 @@
 	 * @return the flags
 	 * @see IResourceDelta#CONTENT
 	 * @see IResourceDelta#DESCRIPTION
+	 * @see IResourceDelta#ENCODING
 	 * @see IResourceDelta#OPEN
 	 * @see IResourceDelta#MOVED_TO
 	 * @see IResourceDelta#MOVED_FROM
diff --git a/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/CharsetTest.java b/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/CharsetTest.java
index da94034..a2d1c25 100644
--- a/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/CharsetTest.java
+++ b/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/CharsetTest.java
@@ -246,6 +246,34 @@
 		}
 	}
 
+	public void testBug59899() {
+		IWorkspace workspace = getWorkspace();
+		IProject project = workspace.getRoot().getProject(getUniqueString());
+		IFile file = project.getFile("file.txt");
+		IFolder folder = project.getFolder("folder");
+		ensureExistsInWorkspace(new IResource[] {file, folder}, true);
+		try {
+			file.setCharset("FOO", getMonitor());
+		} catch (CoreException e) {
+			fail("1.0", e);
+		}
+		try {
+			folder.setDefaultCharset("BAR", getMonitor());
+		} catch (CoreException e) {
+			fail("2.0", e);
+		}
+		try {
+			project.setDefaultCharset("PROJECT_CHARSET", getMonitor());
+		} catch (CoreException e) {
+			fail("3.0", e);
+		}
+		try {
+			getWorkspace().getRoot().setDefaultCharset("ROOT_CHARSET", getMonitor());
+		} catch (CoreException e) {
+			fail("4.0", e);
+		}
+	}
+
 	public void testFileCreation() throws CoreException {
 		IWorkspace workspace = getWorkspace();
 		IProject project = workspace.getRoot().getProject("MyProject");
@@ -368,13 +396,14 @@
 			ensureDoesNotExistInWorkspace(project);
 		}
 	}
+
 	public void testBug64503() throws CoreException {
 		IWorkspace workspace = getWorkspace();
 		IProject project = workspace.getRoot().getProject("MyProject");
 		try {
 			IContentTypeManager contentTypeManager = Platform.getContentTypeManager();
-			IContentType text = contentTypeManager.getContentType("org.eclipse.core.runtime.text");			
-			IFile file = project.getFile("file.txt");			
+			IContentType text = contentTypeManager.getContentType("org.eclipse.core.runtime.text");
+			IFile file = project.getFile("file.txt");
 			ensureExistsInWorkspace(file, true);
 			IContentDescription description = file.getContentDescription();
 			assertNotNull("1.0", description);
@@ -388,7 +417,7 @@
 			}
 		} finally {
 			ensureDoesNotExistInWorkspace(project);
-		}		
-	}	
-	
+		}
+	}
+
 }
\ No newline at end of file