Merge branch 'R3_development' of ssh://git.eclipse.org/gitroot/platform/eclipse.platform.ui into R3_development
diff --git a/bundles/org.eclipse.jface/build.properties b/bundles/org.eclipse.jface/build.properties
index 2c04303..a3eb1b3 100644
--- a/bundles/org.eclipse.jface/build.properties
+++ b/bundles/org.eclipse.jface/build.properties
@@ -11,6 +11,7 @@
 bin.includes = plugin.properties,\
                about.html,\
                .,\
-               META-INF/
+               META-INF/,\
+               icons/
 src.includes = about.html
 source.. = src/
diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/IDEWorkbenchMessages.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/IDEWorkbenchMessages.java
index 7a90233..ac7ddb4 100644
--- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/IDEWorkbenchMessages.java
+++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/IDEWorkbenchMessages.java
@@ -642,6 +642,14 @@
 	public static String ResourceInfo_read;
 	public static String ResourceInfo_write;
 	public static String ResourceInfo_execute;
+	public static String ResourceInfo_recursiveChangesTitle;
+	public static String ResourceInfo_recursiveChangesSummary;
+	public static String ResourceInfo_recursiveChangesSet;
+	public static String ResourceInfo_recursiveChangesUnset;
+	public static String ResourceInfo_recursiveChangesQuestion;
+	public static String ResourceInfo_recursiveChangesJobName;
+	public static String ResourceInfo_recursiveChangesSubTaskName;
+	public static String ResourceInfo_recursiveChangesError;
 
 	// --- Project References ---
 	public static String ProjectReferencesPage_label;
diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/dialogs/ResourceInfoPage.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/dialogs/ResourceInfoPage.java
index 1be93f5..18f3839 100644
--- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/dialogs/ResourceInfoPage.java
+++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/dialogs/ResourceInfoPage.java
@@ -13,6 +13,11 @@
 package org.eclipse.ui.internal.ide.dialogs;
 
 import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
 
 import org.eclipse.core.filesystem.EFS;
 import org.eclipse.core.filesystem.IFileInfo;
@@ -23,15 +28,24 @@
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceProxy;
+import org.eclipse.core.resources.IResourceProxyVisitor;
 import org.eclipse.core.resources.ResourceAttributes;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.content.IContentDescription;
+import org.eclipse.core.runtime.jobs.Job;
 import org.eclipse.jface.dialogs.Dialog;
 import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.jface.preference.FieldEditor;
 import org.eclipse.jface.util.IPropertyChangeListener;
 import org.eclipse.jface.util.PropertyChangeEvent;
@@ -57,6 +71,7 @@
 import org.eclipse.ui.dialogs.PropertyPage;
 import org.eclipse.ui.ide.dialogs.ResourceEncodingFieldEditor;
 import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
+import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
 import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
 import org.eclipse.ui.internal.ide.LineDelimiterEditor;
 
@@ -65,6 +80,11 @@
  * resource.
  */
 public class ResourceInfoPage extends PropertyPage {
+	private interface IResourceChange {
+		public String getMessage();
+
+		public void performChange(IResource resource) throws CoreException;
+	}
 
 	private Button editableBox;
 
@@ -915,6 +935,177 @@
 
 	}
 
+	private String getSimpleChangeName(boolean isSet, String name) {
+		String message = "\t"; //$NON-NLS-1$
+		message += isSet ? IDEWorkbenchMessages.ResourceInfo_recursiveChangesSet
+				: IDEWorkbenchMessages.ResourceInfo_recursiveChangesUnset;
+		message += " " + name + "\n"; //$NON-NLS-1$ //$NON-NLS-2$
+		return message;
+	}
+
+	private IResourceChange getAttributesChange(final boolean changedAttrs[],
+			final boolean finalAttrs[]) {
+		return new IResourceChange() {
+			public String getMessage() {
+				String message = ""; //$NON-NLS-1$
+				if (changedAttrs[0])
+					message += getSimpleChangeName(finalAttrs[0],
+							IDEWorkbenchMessages.ResourceInfo_readOnly);
+				if (changedAttrs[1])
+					message += getSimpleChangeName(finalAttrs[1],
+							IDEWorkbenchMessages.ResourceInfo_executable);
+				if (changedAttrs[2])
+					message += getSimpleChangeName(finalAttrs[2],
+							IDEWorkbenchMessages.ResourceInfo_archive);
+				return message;
+			}
+
+			public void performChange(IResource resource) throws CoreException {
+				ResourceAttributes attrs = resource.getResourceAttributes();
+				if (attrs != null) {
+					if (changedAttrs[0])
+						attrs.setReadOnly(finalAttrs[0]);
+					if (changedAttrs[1])
+						attrs.setExecutable(finalAttrs[1]);
+					if (changedAttrs[2])
+						attrs.setArchive(finalAttrs[2]);
+					resource.setResourceAttributes(attrs);
+				}
+			}
+		};
+	}
+
+	private IResourceChange getPermissionsChange(final int changedPermissions,
+			final int finalPermissions) {
+		return new IResourceChange() {
+			public String getMessage() {
+				// iterated with [j][i]
+				int permissionMasks[][] = new int[][] {
+						{ EFS.ATTRIBUTE_OWNER_READ, EFS.ATTRIBUTE_OWNER_WRITE,
+								EFS.ATTRIBUTE_OWNER_EXECUTE },
+						{ EFS.ATTRIBUTE_GROUP_READ, EFS.ATTRIBUTE_GROUP_WRITE,
+								EFS.ATTRIBUTE_GROUP_EXECUTE },
+						{ EFS.ATTRIBUTE_OTHER_READ, EFS.ATTRIBUTE_OTHER_WRITE,
+								EFS.ATTRIBUTE_OTHER_EXECUTE } };
+				// iterated with [j]
+				String groupNames[] = new String[] {
+						IDEWorkbenchMessages.ResourceInfo_owner,
+						IDEWorkbenchMessages.ResourceInfo_group,
+						IDEWorkbenchMessages.ResourceInfo_other };
+				// iterated with [i]
+				String permissionNames[] = new String[] {
+						IDEWorkbenchMessages.ResourceInfo_read,
+						IDEWorkbenchMessages.ResourceInfo_write,
+						IDEWorkbenchMessages.ResourceInfo_execute };
+
+				String message = ""; //$NON-NLS-1$
+				if ((changedPermissions & EFS.ATTRIBUTE_IMMUTABLE) != 0)
+					message += getSimpleChangeName(
+							(finalPermissions & EFS.ATTRIBUTE_IMMUTABLE) != 0,
+							IDEWorkbenchMessages.ResourceInfo_locked);
+
+				for (int j = 0; j < 3; j++) {
+					for (int i = 0; i < 3; i++) {
+						if ((changedPermissions & permissionMasks[j][i]) != 0)
+							message += getSimpleChangeName(
+									(finalPermissions & permissionMasks[j][i]) != 0,
+									groupNames[j] + " " + permissionNames[i]); //$NON-NLS-1$
+					}
+				}
+				return message;
+			}
+
+			public void performChange(IResource resource) {
+				int permissions = fetchPermissions(resource);
+				// add permissions
+				permissions |= changedPermissions & finalPermissions;
+				// remove permissions
+				permissions &= ~changedPermissions | finalPermissions;
+				putPermissions(resource, permissions);
+			}
+		};
+	}
+
+	private List/*<IResource>*/ getResourcesToVisit(IResource resource) throws CoreException {
+		// use set for fast lookup
+		final Set/*<URI>*/ visited = new HashSet/*<URI>*/();
+		// use list to preserve the order of visited resources
+		final List/*<IResource>*/ toVisit = new ArrayList/*<IResource>*/();
+		visited.add(resource.getLocationURI());
+		resource.accept(new IResourceProxyVisitor() {
+			public boolean visit(IResourceProxy proxy) {
+				IResource childResource = proxy.requestResource();
+				URI uri = childResource.getLocationURI();
+				if (!visited.contains(uri)) {
+					visited.add(uri);
+					toVisit.add(childResource);
+				}
+				return true;
+			}
+		}, IResource.NONE);
+		return toVisit;
+	}
+
+	private boolean shouldPerformRecursiveChanges(List/*<IResourceChange>*/ changes) {
+		if (!changes.isEmpty()) {
+			String message = IDEWorkbenchMessages.ResourceInfo_recursiveChangesSummary
+					+ "\n"; //$NON-NLS-1$
+			for (int i = 0; i < changes.size(); i++) {
+				message += ((IResourceChange) changes.get(i)).getMessage();
+			}
+			message += IDEWorkbenchMessages.ResourceInfo_recursiveChangesQuestion;
+
+			MessageDialog dialog = new MessageDialog(getShell(),
+					IDEWorkbenchMessages.ResourceInfo_recursiveChangesTitle,
+					null, message, MessageDialog.QUESTION, new String[] {
+							IDialogConstants.YES_LABEL,
+							IDialogConstants.NO_LABEL }, 1);
+
+			return dialog.open() == 0;
+		}
+		return false;
+	}
+
+	private void scheduleRecursiveChangesJob(final IResource resource, final List/*<IResourceChange>*/ changes) {
+		new Job(IDEWorkbenchMessages.ResourceInfo_recursiveChangesJobName) {
+			protected IStatus run(final IProgressMonitor monitor) {
+				try {
+					List/*<IResource>*/ toVisit = getResourcesToVisit(resource);
+
+					// Prepare the monitor for the given amount of work
+					monitor.beginTask(
+							IDEWorkbenchMessages.ResourceInfo_recursiveChangesJobName,
+							toVisit.size());
+
+					// Apply changes recursively
+					for (Iterator/*<IResource>*/ it = toVisit.iterator(); it.hasNext();) {
+						if (monitor.isCanceled())
+							throw new OperationCanceledException();
+						IResource childResource = (IResource) it.next();
+						monitor.subTask(NLS
+								.bind(IDEWorkbenchMessages.ResourceInfo_recursiveChangesSubTaskName,
+										childResource.getFullPath()));
+						for (int i = 0; i < changes.size(); i++) {
+							((IResourceChange) changes.get(i))
+									.performChange(childResource);
+						}
+						monitor.worked(1);
+					}
+				} catch (CoreException e) {
+					IDEWorkbenchPlugin
+							.log(IDEWorkbenchMessages.ResourceInfo_recursiveChangesError,
+									e.getStatus());
+					return e.getStatus();
+				} catch (OperationCanceledException e) {
+					return Status.CANCEL_STATUS;
+				} finally {
+					monitor.done();
+				}
+				return Status.OK_STATUS;
+			}
+		}.schedule();
+	}
+
 	/**
 	 * Apply the read only state and the encoding to the resource.
 	 */
@@ -940,26 +1131,32 @@
 							new NullProgressMonitor());
 			}
 
+			List/*<IResourceChange>*/ changes = new ArrayList/*<IResourceChange>*/();
+
 			ResourceAttributes attrs = resource.getResourceAttributes();
 			if (attrs != null) {
-				boolean hasChange = false;
+				boolean finalValues[] = new boolean[] { false, false, false };
+				boolean changedAttrs[] = new boolean[] { false, false, false };
 				// Nothing to update if we never made the box
 				if (editableBox != null
 						&& editableBox.getSelection() != previousReadOnlyValue) {
 					attrs.setReadOnly(editableBox.getSelection());
-					hasChange = true;
+					finalValues[0] = editableBox.getSelection();
+					changedAttrs[0] = true;
 				}
 				if (executableBox != null
 						&& executableBox.getSelection() != previousExecutableValue) {
 					attrs.setExecutable(executableBox.getSelection());
-					hasChange = true;
+					finalValues[1] = executableBox.getSelection();
+					changedAttrs[1] = true;
 				}
 				if (archiveBox != null
 						&& archiveBox.getSelection() != previousArchiveValue) {
 					attrs.setArchive(archiveBox.getSelection());
-					hasChange = true;
+					finalValues[2] = archiveBox.getSelection();
+					changedAttrs[2] = true;
 				}
-				if (hasChange) {
+				if (changedAttrs[0] || changedAttrs[1] || changedAttrs[2]) {
 					resource.setResourceAttributes(attrs);
 					attrs = resource.getResourceAttributes();
 					if (attrs != null) {
@@ -975,6 +1172,10 @@
 						if (archiveBox != null) {
 							archiveBox.setSelection(attrs.isArchive());
 						}
+						if (resource.getType() == IResource.FOLDER) {
+							changes.add(getAttributesChange(changedAttrs,
+									finalValues));
+						}
 					}
 				}
 			}
@@ -982,15 +1183,23 @@
 			if (permissionBoxes != null) {
 				int permissionValues = getPermissionsSelection();
 				if (previousPermissionsValue != permissionValues) {
+					int changedPermissions = previousPermissionsValue ^ permissionValues;
 					putPermissions(resource, permissionValues);
 					previousPermissionsValue = fetchPermissions(resource);
 					if (previousPermissionsValue != permissionValues) {
 						// We failed to set some of the permissions
 						setPermissionsSelection(previousPermissionsValue);
 					}
+					if (resource.getType() == IResource.FOLDER) {
+						changes.add(getPermissionsChange(changedPermissions,
+								permissionValues));
+					}
 				}
 			}
 
+			if (shouldPerformRecursiveChanges(changes))
+				scheduleRecursiveChangesJob(resource, changes);
+
 			// Nothing to update if we never made the box
 			if (this.derivedBox != null) {
 				boolean localDerivedValue = derivedBox.getSelection();
diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/messages.properties b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/messages.properties
index a8e9009..a7a3fd4 100644
--- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/messages.properties
+++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/messages.properties
@@ -661,6 +661,14 @@
 ResourceInfo_read=Read
 ResourceInfo_write=Write
 ResourceInfo_execute=Execute
+ResourceInfo_recursiveChangesTitle = Confirm recursive changes
+ResourceInfo_recursiveChangesSummary = The following changes have been made:
+ResourceInfo_recursiveChangesSet = set
+ResourceInfo_recursiveChangesUnset = unset
+ResourceInfo_recursiveChangesQuestion = Do you want to apply these changes to subfolders and files?
+ResourceInfo_recursiveChangesJobName = Applying recursive changes
+ResourceInfo_recursiveChangesSubTaskName = Applying changes for: ''{0}''
+ResourceInfo_recursiveChangesError = Error applying recursive changes
 
 # --- Project References ---
 ProjectReferencesPage_label = Projects may refer to other projects in the workspace.\nUse this page to specify what other projects are referenced by the project.\n\n&Project references for ''{0}'':
diff --git a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/PartPane.java b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/PartPane.java
index eb2ad31..9e04b2a 100644
--- a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/PartPane.java
+++ b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/PartPane.java
@@ -9,6 +9,7 @@
  *     IBM Corporation - initial API and implementation
  *     Stefan Xenos, IBM; Chris Torrence, ITT Visual Information Solutions - bug 51580
  *     Nikolay Botev - bug 240651
+ *     Mohamed Tarief - bug 203849
  *******************************************************************************/
 package org.eclipse.ui.internal;
 
@@ -16,6 +17,7 @@
 import org.eclipse.jface.action.MenuManager;
 import org.eclipse.jface.util.IPropertyChangeListener;
 import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.window.Window;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.FocusAdapter;
 import org.eclipse.swt.events.FocusEvent;
@@ -493,11 +495,14 @@
      * Add the Left,Right,Up,Botton menu items to the Size menu.
      */
     protected void addSizeItems(Menu sizeMenu) {
-        Sashes sashes = findSashes();
-        addSizeItem(sizeMenu,
-                WorkbenchMessages.PartPane_sizeLeft, sashes.left);
-        addSizeItem(sizeMenu,
-                WorkbenchMessages.PartPane_sizeRight, sashes.right); 
+		Sashes sashes = findSashes();
+		if (Window.getDefaultOrientation() == SWT.RIGHT_TO_LEFT) {
+			addSizeItem(sizeMenu, WorkbenchMessages.PartPane_sizeLeft, sashes.right);
+			addSizeItem(sizeMenu, WorkbenchMessages.PartPane_sizeRight, sashes.left);
+		} else {
+			addSizeItem(sizeMenu, WorkbenchMessages.PartPane_sizeLeft, sashes.left);
+			addSizeItem(sizeMenu, WorkbenchMessages.PartPane_sizeRight, sashes.right);
+		}
         addSizeItem(sizeMenu,
                 WorkbenchMessages.PartPane_sizeTop, sashes.top); 
         addSizeItem(sizeMenu, WorkbenchMessages.PartPane_sizeBottom, sashes.bottom);
diff --git a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/WorkbenchPlugin.java b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/WorkbenchPlugin.java
index 0c25a0a..9a95a3b 100644
--- a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/WorkbenchPlugin.java
+++ b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/WorkbenchPlugin.java
@@ -1244,10 +1244,11 @@
 	}
 
 	private void bundleChanged(BundleEvent event) {
+		int eventType = event.getType();
 		// a bundle in the STARTING state generates 2 events, LAZY_ACTIVATION
 		// when it enters STARTING and STARTING when it exists STARTING :-)
 		synchronized (startingBundles) {
-			switch (event.getType()) {
+			switch (eventType) {
 				case BundleEvent.STARTING :
 					startingBundles.add(event.getBundle());
 					break;