Apply Patch Wizard Changes
diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/CompareUI.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/CompareUI.java
index 94f1050..3c6d65c 100644
--- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/CompareUI.java
+++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/CompareUI.java
@@ -14,6 +14,7 @@
 
 import org.eclipse.compare.internal.CompareUIPlugin;
 import org.eclipse.compare.internal.DocumentManager;
+import org.eclipse.compare.internal.ICompareUIConstants;
 import org.eclipse.compare.structuremergeviewer.ICompareInput;
 import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.core.runtime.content.IContentType;
@@ -57,33 +58,33 @@
 	 * Image descriptor for the disabled icon of the 'Next' tool bar button.
 	 * @since 2.0
 	 */
-	public static final ImageDescriptor DESC_DTOOL_NEXT= CompareUIPlugin.getImageDescriptor(CompareUIPlugin.DTOOL_NEXT);
+	public static final ImageDescriptor DESC_DTOOL_NEXT= CompareUIPlugin.getImageDescriptor(ICompareUIConstants.DTOOL_NEXT);
 	/**
 	 * Image descriptor for the normal icon of the 'Next' tool bar button.
 	 * @since 2.0
 	 */
-	public static final ImageDescriptor DESC_CTOOL_NEXT= CompareUIPlugin.getImageDescriptor(CompareUIPlugin.CTOOL_NEXT);
+	public static final ImageDescriptor DESC_CTOOL_NEXT= CompareUIPlugin.getImageDescriptor(ICompareUIConstants.CTOOL_NEXT);
 	/**
 	 * Image descriptor for the roll-over icon of the 'Next' tool bar button.
 	 * @since 2.0
 	 */
-	public static final ImageDescriptor DESC_ETOOL_NEXT= CompareUIPlugin.getImageDescriptor(CompareUIPlugin.ETOOL_NEXT);
+	public static final ImageDescriptor DESC_ETOOL_NEXT= CompareUIPlugin.getImageDescriptor(ICompareUIConstants.ETOOL_NEXT);
 	
 	/**
 	 * Image descriptor for the disabled icon of the 'Previous' tool bar button.
 	 * @since 2.0
 	 */
-	public static final ImageDescriptor DESC_DTOOL_PREV= CompareUIPlugin.getImageDescriptor(CompareUIPlugin.DTOOL_PREV);
+	public static final ImageDescriptor DESC_DTOOL_PREV= CompareUIPlugin.getImageDescriptor(ICompareUIConstants.DTOOL_PREV);
 	/**
 	 * Image descriptor for the normal icon of the 'Previous' tool bar button.
 	 * @since 2.0
 	 */
-	public static final ImageDescriptor DESC_CTOOL_PREV= CompareUIPlugin.getImageDescriptor(CompareUIPlugin.CTOOL_PREV);
+	public static final ImageDescriptor DESC_CTOOL_PREV= CompareUIPlugin.getImageDescriptor(ICompareUIConstants.CTOOL_PREV);
 	/**
 	 * Image descriptor for the roll-over icon of the 'Previous' tool bar button.
 	 * @since 2.0
 	 */
-	public static final ImageDescriptor DESC_ETOOL_PREV= CompareUIPlugin.getImageDescriptor(CompareUIPlugin.ETOOL_PREV);
+	public static final ImageDescriptor DESC_ETOOL_PREV= CompareUIPlugin.getImageDescriptor(ICompareUIConstants.ETOOL_PREV);
 
 	/**
 	 * Name of the title property of a compare viewer.
diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/CompareUIPlugin.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/CompareUIPlugin.java
index 3cdfe35..34a04bf 100644
--- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/CompareUIPlugin.java
+++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/CompareUIPlugin.java
@@ -134,14 +134,6 @@
 	    	}
     }
 	
-	public static final String DTOOL_NEXT= "dlcl16/next_nav.gif";	//$NON-NLS-1$
-	public static final String ETOOL_NEXT= "elcl16/next_nav.gif";	//$NON-NLS-1$
-	public static final String CTOOL_NEXT= ETOOL_NEXT;
-	
-	public static final String DTOOL_PREV= "dlcl16/prev_nav.gif";	//$NON-NLS-1$
-	public static final String ETOOL_PREV= "elcl16/prev_nav.gif";	//$NON-NLS-1$
-	public static final String CTOOL_PREV= ETOOL_PREV;
-				
 	/** Status code describing an internal error */
 	public static final int INTERNAL_ERROR= 1;
 
diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/ICompareUIConstants.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/ICompareUIConstants.java
new file mode 100644
index 0000000..3e17776
--- /dev/null
+++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/ICompareUIConstants.java
@@ -0,0 +1,21 @@
+package org.eclipse.compare.internal;
+
+
+public interface ICompareUIConstants {
+	public final String PREFIX = CompareUIPlugin.getPluginId() + "."; //$NON-NLS-1$
+	
+	public static final String DTOOL_NEXT= "dlcl16/next_nav.gif";	//$NON-NLS-1$
+	public static final String ETOOL_NEXT= "elcl16/next_nav.gif";	//$NON-NLS-1$
+	public static final String CTOOL_NEXT= ETOOL_NEXT;
+	
+	public static final String DTOOL_PREV= "dlcl16/prev_nav.gif";	//$NON-NLS-1$
+	public static final String ETOOL_PREV= "elcl16/prev_nav.gif";	//$NON-NLS-1$
+	public static final String CTOOL_PREV= ETOOL_PREV;
+
+	public static final String RETARGET_PROJECT= "eview16/compare_view.gif";	//$NON-NLS-1$
+	
+	public static final String IGNORE_WHITESPACE_ENABLED= "etool16/ignorews_edit.gif";	//$NON-NLS-1$
+	public static final String IGNORE_WHITESPACE_DISABLED= "dtool16/ignorews_edit.gif";	//$NON-NLS-1$
+	
+	public static final String REVERSE_PATCH_ENABLED = "etool16/reverse_enabled.gif";	//$NON-NLS-1$
+}
diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/CheckboxDiffTreeViewer.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/CheckboxDiffTreeViewer.java
new file mode 100644
index 0000000..6d91532
--- /dev/null
+++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/CheckboxDiffTreeViewer.java
@@ -0,0 +1,297 @@
+package org.eclipse.compare.internal.patch;
+
+import java.util.ResourceBundle;
+
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.compare.internal.INavigatable;
+import org.eclipse.compare.internal.IOpenable;
+import org.eclipse.compare.internal.Utilities;
+import org.eclipse.compare.structuremergeviewer.IDiffContainer;
+import org.eclipse.compare.structuremergeviewer.IDiffElement;
+import org.eclipse.jface.viewers.DecoratingLabelProvider;
+import org.eclipse.jface.viewers.ILabelDecorator;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.OpenEvent;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.ui.dialogs.ContainerCheckedTreeViewer;
+
+public class CheckboxDiffTreeViewer extends ContainerCheckedTreeViewer {
+	
+	class CheckboxDiffViewerContentProvider implements ITreeContentProvider {
+		
+		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+			// empty implementation
+		}
+	
+		public boolean isDeleted(Object element) {
+			return false;
+		}
+			
+		public void dispose() {
+			inputChanged(CheckboxDiffTreeViewer.this, getInput(), null);
+		}
+			
+		public Object getParent(Object element) {
+			if (element instanceof IDiffElement) 
+				return ((IDiffElement)element).getParent();
+			return null;
+		}
+		
+		public final boolean hasChildren(Object element) {
+			if (element instanceof IDiffContainer) 
+				return ((IDiffContainer)element).hasChildren();
+			return false;
+		}
+		
+		public final Object[] getChildren(Object element) {
+			if (element instanceof IDiffContainer)
+				return ((IDiffContainer)element).getChildren();
+			return new Object[0];
+		}
+		
+		public Object[] getElements(Object element) {
+			return getChildren(element);
+		}				
+	}
+	
+	/*
+	 * Takes care of swapping left and right if fLeftIsLocal
+	 * is true.
+	 */
+	class CheckboxDiffViewerLabelProvider extends LabelProvider {
+		
+		public String getText(Object element) {
+		
+			if (element instanceof IDiffElement)
+				return ((IDiffElement)element).getName();
+			
+			
+			return Utilities.getString(fBundle, "defaultLabel"); //$NON-NLS-1$
+		}
+	
+		public Image getImage(Object element) {
+			if (element instanceof IDiffElement) {
+				IDiffElement input= (IDiffElement) element;	
+				return input.getImage();
+			}
+			return null;
+		}
+	}
+
+	CompareConfiguration fCompareConfiguration;
+	private ResourceBundle fBundle;
+
+	public CheckboxDiffTreeViewer(Composite parent, CompareConfiguration compareConfiguration) {
+		super(parent);
+		initialize(compareConfiguration);
+	}
+
+	private void initialize(CompareConfiguration compareConfiguration) {
+		Control tree= getControl();
+		
+		INavigatable nav= new INavigatable() {
+			public boolean gotoDifference(boolean next) {
+				// Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106
+				return internalNavigate(next, true);
+			}
+		};
+		tree.setData(INavigatable.NAVIGATOR_PROPERTY, nav);
+		
+		// Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106
+		IOpenable openable= new IOpenable() {
+			public void openSelected() {
+				internalOpen();
+			}
+		};
+		tree.setData(IOpenable.OPENABLE_PROPERTY, openable);
+		
+		fBundle= ResourceBundle.getBundle("org.eclipse.compare.structuremergeviewer.DiffTreeViewerResources"); //$NON-NLS-1$
+				
+		setContentProvider(new CheckboxDiffViewerContentProvider());
+		setLabelProvider(new CheckboxDiffViewerLabelProvider());
+		
+		addSelectionChangedListener(
+			new ISelectionChangedListener() {
+				public void selectionChanged(SelectionChangedEvent se) {
+					//updateActions();
+				}
+			}
+		);
+												
+	}
+
+/**
+ * Selects the next (or previous) node of the current selection.
+ * If there is no current selection the first (last) node in the tree is selected.
+ * Wraps around at end or beginning.
+ * Clients may override. 
+ *
+ * @param next if <code>true</code> the next node is selected, otherwise the previous node
+ * @param fireOpen if <code>true</code> an open event is fired.
+ * @return <code>true</code> if at end (or beginning)
+ */
+private boolean internalNavigate(boolean next, boolean fireOpen) {
+	
+	Control c= getControl();
+	if (!(c instanceof Tree))
+		return false;
+		
+	Tree tree= (Tree) c;
+	TreeItem item= null;
+	TreeItem children[]= tree.getSelection();
+	if (children != null && children.length > 0)
+		item= children[0];
+	if (item == null) {
+		children= tree.getItems();
+		if (children != null && children.length > 0) {
+			item= children[0];
+			if (item != null && item.getItemCount() <= 0) {
+				internalSetSelection(item, fireOpen);				// Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106
+				return false;
+			}
+		}
+	}
+		
+	while (true) {
+		item= findNextPrev(item, next);
+		if (item == null)
+			break;
+		if (item.getItemCount() <= 0)
+			break;
+	}
+	
+	if (item != null) {
+		internalSetSelection(item, fireOpen);	// Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106
+		return false;
+	}
+	return true;
+}
+
+private TreeItem findNextPrev(TreeItem item, boolean next) {
+	
+	if (item == null)
+		return null;
+	
+	TreeItem children[]= null;
+
+	if (!next) {
+	
+		TreeItem parent= item.getParentItem();
+		if (parent != null)
+			children= parent.getItems();
+		else
+			children= item.getParent().getItems();
+		
+		if (children != null && children.length > 0) {
+			// goto previous child
+			int index= 0;
+			for (; index < children.length; index++)
+				if (children[index] == item)
+					break;
+			
+			if (index > 0) {
+				
+				item= children[index-1];
+				
+				while (true) {
+					createChildren(item);
+					int n= item.getItemCount();
+					if (n <= 0)
+						break;
+						
+					item.setExpanded(true);
+					item= item.getItems()[n-1];
+				}
+
+				// previous
+				return item;
+			}
+		}
+		
+		// go up
+		item= parent;
+				
+	} else {
+		item.setExpanded(true);
+		createChildren(item);
+		
+		if (item.getItemCount() > 0) {
+			// has children: go down
+			children= item.getItems();
+			return children[0];
+		}
+		
+		while (item != null) {
+			children= null;
+			TreeItem parent= item.getParentItem();
+			if (parent != null)
+				children= parent.getItems();
+			else
+				children= item.getParent().getItems();
+			
+			if (children != null && children.length > 0) {
+				// goto next child
+				int index= 0;
+				for (; index < children.length; index++)
+					if (children[index] == item)
+						break;
+				
+				if (index < children.length-1) {
+					// next
+					return children[index+1];
+				}
+			}
+			
+			// go up
+			item= parent;
+		}
+	}
+			
+	return item;
+}
+
+private void internalSetSelection(TreeItem ti, boolean fireOpen) {
+	if (ti != null) {
+		Object data= ti.getData();
+		if (data != null) {
+			// Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106
+			ISelection selection= new StructuredSelection(data);
+			setSelection(selection, true);
+			ISelection currentSelection= getSelection();
+			if (fireOpen && currentSelection != null && selection.equals(currentSelection)) {
+				fireOpen(new OpenEvent(this, selection));
+			}
+		}
+	}
+}
+
+/*
+ * Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106
+ */ 
+private void internalOpen()  {
+	ISelection selection= getSelection();
+	if (selection != null && !selection.isEmpty()) {
+		fireOpen(new OpenEvent(this, selection));
+	}
+}
+
+/**
+ * Creates a new DecoratingLabelProvider (using the passed in ILabelDecorator) and sets
+ * it as the label provider for the tree
+ * @param decorator
+ */
+public void setLabelDecorator(ILabelDecorator decorator) {
+	setLabelProvider(new DecoratingLabelProvider(new CheckboxDiffViewerLabelProvider(), decorator));
+}
+
+}
diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/DiffProject.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/DiffProject.java
index 6da4e19..b8545b0 100644
--- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/DiffProject.java
+++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/DiffProject.java
@@ -14,14 +14,17 @@
 import java.util.Iterator;
 import java.util.List;
 
+import org.eclipse.compare.CompareUI;
+import org.eclipse.compare.ITypedElement;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
 import org.eclipse.ui.model.IWorkbenchAdapter;
 
-public class DiffProject implements IWorkbenchAdapter, IAdaptable {
+public class DiffProject implements IWorkbenchAdapter, IAdaptable, ITypedElement {
 
 	List fDiffs= new ArrayList();
 	IProject fProject;
@@ -48,7 +51,7 @@
 		return this.fProject;
 	}
 
-	String getName() {
+	public String getName() {
 		return fProject.getName();
 	}
 
@@ -125,4 +128,12 @@
 	public String getOriginalProjectName() {
 		return fOriginalProjectName;
 	}
+
+	public Image getImage() {
+		return CompareUI.getImage(fProject);
+	}
+
+	public String getType() {
+		return ITypedElement.FOLDER_TYPE;
+	}
 }
diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.java
index 75b3c6b..d60d1d3 100644
--- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.java
+++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.java
@@ -26,6 +26,9 @@
 	public static String PatchAction_AlwaysSaveQuestion;
 	public static String PatchAction_SaveAllQuestion;
 	public static String PatchAction_SaveAllDescription;
+	public static String PatcherCompareEditorInput_AfterPatch;
+	public static String PatcherCompareEditorInput_LocalCopy;
+	public static String PatcherCompareEditorInput_PatchContents;
 	public static String PatchWizard_title;
 	public static String PatchWizard_unexpectedException_message;
 	public static String InputPatchPage_title;
@@ -87,4 +90,8 @@
 	public static String PreviewPatchPage_SelectProject;
 	public static String PreviewPatchPage_Target;
 	public static String PreviewPatchLabelDecorator_ProjectDoesNotExist;
+	public static String PreviewPatchPage2_IgnoreWSAction;
+	public static String PreviewPatchPage2_IgnoreWSTooltip;
+	public static String PreviewPatchPage2_RetargetAction;
+	public static String PreviewPatchPage2_RetargetTooltip;
 }
\ No newline at end of file
diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.properties b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.properties
index a44d187..a482462 100644
--- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.properties
+++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.properties
@@ -16,6 +16,8 @@
 PatchAction_ExceptionTitle=Saving Resources
 PatchAction_Exception=Unexpected exception. See log for details
 PatchAction_SavingDirtyEditorsTask=Saving dirty editors
+PatcherCompareEditorInput_LocalCopy=Local Copy
+PatcherCompareEditorInput_AfterPatch=After Patch
 PatchAction_AlwaysSaveQuestion=&Always save all modified resources automatically prior to patching
 PatchAction_SaveAllQuestion=Save all modified resources
 PatchAction_SaveAllDescription=All modified resources have to be saved before this operation.\nClick 'OK' to confirm or click 'Cancel'.
@@ -25,6 +27,7 @@
 #
 PatchWizard_title=Apply Patch
 PatchWizard_unexpectedException_message= Unexpected exception while applying the patch. See log for a detailed error description.
+PatcherCompareEditorInput_PatchContents=Patch Contents
 
 #
 # InputPatchPage
@@ -73,10 +76,14 @@
 PreviewPatchPage_IgnoreSegments_text=&Ignore leading path name segments:
 PreviewPatchPage_ReversePatch_text=&Reverse patch
 PreviewPatchPage_FuzzFactor_text=&Maximum fuzz factor:
+PreviewPatchPage2_RetargetAction=Retarget
+PreviewPatchPage2_IgnoreWSAction=Ignore WhiteSpace
 PreviewPatchPage_FuzzFactor_tooltip=Allow Context to Shift This Number of Lines from the Original Location
 PreviewPatchPage_IgnoreWhitespace_text=Ignore &white space
 PreviewPatchPage_NoName_text=no name
 PreviewPatchPage_FileExists_error=(file already exists)
+PreviewPatchPage2_RetargetTooltip=Retarget Project
+PreviewPatchPage2_IgnoreWSTooltip=Ignore WhiteSpace
 PreviewPatchPage_FileDoesNotExist_error=(file does not exist)
 PreviewPatchPage_NoMatch_error=(no match)
 PreviewPatchPage_MatchProjects=Retarget &Patch...
diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchWizard.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchWizard.java
index 9ae3aa3..740ce77 100644
--- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchWizard.java
+++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchWizard.java
@@ -79,7 +79,7 @@
 		
 		addPage(fPatchWizardPage= new InputPatchPage(this));
 		addPage(new PatchTargetPage(this));
-		addPage(new PreviewPatchPage(this));
+		addPage(new PreviewPatchPage2(this));
 	}
 	
 	/* (non-Javadoc)
diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatcherCompareEditorInput.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatcherCompareEditorInput.java
new file mode 100644
index 0000000..395c661
--- /dev/null
+++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatcherCompareEditorInput.java
@@ -0,0 +1,593 @@
+package org.eclipse.compare.internal.patch;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.compare.CompareEditorInput;
+import org.eclipse.compare.CompareUI;
+import org.eclipse.compare.CompareViewerPane;
+import org.eclipse.compare.IStreamContentAccessor;
+import org.eclipse.compare.ITypedElement;
+import org.eclipse.compare.ResourceNode;
+import org.eclipse.compare.internal.CompareUIPlugin;
+import org.eclipse.compare.internal.DiffImage;
+import org.eclipse.compare.internal.Utilities;
+import org.eclipse.compare.structuremergeviewer.DiffNode;
+import org.eclipse.compare.structuremergeviewer.Differencer;
+import org.eclipse.compare.structuremergeviewer.IDiffContainer;
+import org.eclipse.compare.structuremergeviewer.IDiffElement;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.action.ToolBarManager;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.ILabelDecorator;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+
+public class PatcherCompareEditorInput extends CompareEditorInput {
+
+	class PatchedFileNode implements ITypedElement, IStreamContentAccessor {
+
+		byte[] bytes;
+		String type;
+		String name;
+		
+		
+		public PatchedFileNode(byte[] bytes, String type, String name){
+			this.bytes = bytes;
+			this.type = type;
+			this.name = name;
+		}
+		
+		public Image getImage() {
+			return null;
+		}
+
+		public String getName() {
+			return name;
+		}
+
+		public String getType() {
+			return type;
+		}
+
+		public InputStream getContents() throws CoreException {
+			return new ByteArrayInputStream(bytes);
+		}
+		
+	}
+
+	class MyDiffNode extends DiffNode {
+		
+		//Diff associated with this MyDiffNode
+		private Diff diff = null;
+		//Hunk associated with this MyDiffNode
+		private Hunk hunk = null;
+		
+
+		public MyDiffNode(IDiffContainer parent, int kind, ITypedElement ancestor, ITypedElement left, ITypedElement right, Diff diff) {
+			super(parent, kind, ancestor, left, right);
+			this.diff = diff;
+		}
+		
+		public MyDiffNode(IDiffContainer parent, int kind, ITypedElement ancestor, ITypedElement left, ITypedElement right, Hunk hunk) {
+			super(parent, kind, ancestor, left, right);
+			this.hunk = hunk;
+		}
+
+		public String getName() {
+			if (diff != null)
+				return diff.getLabel(diff);
+			
+			if (hunk != null)
+				return hunk.getLabel(hunk);
+			
+			return ""; //$NON-NLS-1$
+		}
+
+		Diff getDiff() {
+			return diff;
+		}
+
+
+		Hunk getHunk() {
+			return hunk;
+		}
+
+	}
+	
+	class PatcherCompareEditorDecorator implements ILabelDecorator {
+
+		/** Maps strings to images */
+		private Map fImages= new Hashtable(10);
+		private List fDisposeOnShutdownImages= new ArrayList();
+
+		ImageDescriptor errId= CompareUIPlugin.getImageDescriptor("ovr16/error_ov.gif");	//$NON-NLS-1$
+		
+		static final String error = "error"; //$NON-NLS-1$
+		static final String add = "add"; //$NON-NLS-1$
+		static final String delete = "del"; //$NON-NLS-1$
+		
+		public Image decorateImage(Image image, Object element) {
+			if (element instanceof MyDiffNode){
+				MyDiffNode myDiffNode = (MyDiffNode) element;
+				Diff diff = myDiffNode.getDiff();
+				Hunk hunk = myDiffNode.getHunk();
+				if (diff != null){
+				  switch (diff.getType()){
+					  case Differencer.ADDITION:
+					  return getImageFor(add + (diff.fMatches ? "" : error), image, diff.fMatches); //$NON-NLS-1$
+				
+					  case Differencer.DELETION:
+					  return getImageFor(delete + (diff.fMatches ? "" : error), image, diff.fMatches); //$NON-NLS-1$
+					  
+					  default:
+					  return getImageFor(diff.fMatches ? "" : error, image, diff.fMatches); //$NON-NLS-1$
+				  }
+				} else if (hunk != null){
+					return getImageFor((hunk.fMatches ? "" : error),image, hunk.fMatches); //$NON-NLS-1$
+				}
+			}
+			return null;
+		}
+
+		private Image getImageFor(String id, Image image, boolean hasMatches) {
+			Image cached_image = (Image) fImages.get(id);
+			if (cached_image == null){
+				DiffImage diffImage = new DiffImage(image, hasMatches ? null : errId, 16, false);
+				cached_image = diffImage.createImage();
+				fImages.put(id, cached_image);
+				fDisposeOnShutdownImages.add(cached_image);
+			}
+			return cached_image;
+		}
+
+		public String decorateText(String text, Object element) {
+			if (element instanceof DiffNode){	
+				ITypedElement typedElement = ((DiffNode) element).getLeft();
+				if (typedElement != null && typedElement instanceof DiffProject){
+					DiffProject project = (DiffProject) typedElement;
+					if (!project.getName().equals(project.getOriginalProjectName()))	
+						return NLS.bind(PatchMessages.Diff_2Args, 
+								new String[]{project.getOriginalProjectName(),
+								NLS.bind(PatchMessages.PreviewPatchPage_Target, new String[]{project.getName()})});
+				}
+			} 
+			
+			return null;
+		}
+
+		public void dispose() {
+			if (fDisposeOnShutdownImages != null) {
+				Iterator i= fDisposeOnShutdownImages.iterator();
+				while (i.hasNext()) {
+					Image img= (Image) i.next();
+					if (!img.isDisposed())
+						img.dispose();
+				}
+				fImages= null;
+			}
+		}
+
+		public boolean isLabelProperty(Object element, String property) {
+			return false;
+		}
+
+		public void addListener(ILabelProviderListener listener) {
+			//don't need listener	
+		}
+		
+		public void removeListener(ILabelProviderListener listener) {
+			//don't need listener
+		} 
+		
+	}
+	private DiffNode root;
+	private List failedHunks;
+	
+	private CheckboxDiffTreeViewer viewer;
+	private final static int LEFT = 0;
+	private final static int RIGHT = 1;
+	private PreviewPatchPage2 previewPatchPage;
+	
+	private HashMap nodesToDiffs;
+	
+	public PatcherCompareEditorInput() {
+		super(new CompareConfiguration());
+		root = new DiffNode(Differencer.NO_CHANGE) {
+			public boolean hasChildren() {
+				return true;
+			}
+		};
+	}
+
+	protected Object prepareInput(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+		initLabels();
+		return root;
+	}
+	
+	private void initLabels() {
+		CompareConfiguration cc = getCompareConfiguration();
+		cc.setLeftEditable(false);
+		cc.setRightEditable(false);
+		String leftLabel = PatchMessages.PatcherCompareEditorInput_LocalCopy;
+		cc.setLeftLabel(leftLabel);
+		String rightLabel = PatchMessages.PatcherCompareEditorInput_AfterPatch;
+		cc.setRightLabel(rightLabel);
+	}
+
+	public void updateInput(WorkspacePatcher patcher) {
+		buildTree(patcher);
+		updateTree(patcher);
+	}
+	
+	private void updateTree(WorkspacePatcher patcher){
+		if (viewer == null)
+			return;
+		
+		int strip= previewPatchPage.getStripPrefixSegments();
+		//Get the elements from the content provider
+		ITreeContentProvider contentProvider= (ITreeContentProvider) viewer.getContentProvider();
+		Object[] projects= contentProvider.getElements(root);
+		ArrayList hunksToCheck= new ArrayList();
+		ArrayList nodesToCheck=new ArrayList();
+		//Iterate through projects and call reset on each project
+		for (int j= 0; j<projects.length; j++) {
+			if (!(projects[j] instanceof MyDiffNode)) {
+				DiffNode projectNode = (DiffNode) projects[j];
+				ITypedElement project = projectNode.getLeft();
+				Assert.isNotNull(project);
+				Assert.isTrue(project instanceof DiffProject);
+				hunksToCheck.addAll(((DiffProject)project).reset(patcher, strip, previewPatchPage.getFuzzFactor()));
+				IDiffElement[] diffNodes = projectNode.getChildren();
+				
+				Iterator iter = hunksToCheck.iterator();
+				while (iter.hasNext()){
+					Hunk hunkToMatch = (Hunk) iter.next();
+					Object matchingHunkNode = nodesToDiffs.get(hunkToMatch);
+					if (matchingHunkNode != null)
+						nodesToCheck.add(matchingHunkNode);
+					
+				}
+				for (int i = 0; i < diffNodes.length; i++) {
+					viewer.update(diffNodes[i], null);
+					IDiffElement[] hunkNodes =((MyDiffNode) diffNodes[i]).getChildren();
+					for (int k = 0; k < hunkNodes.length; k++) {
+						viewer.update(hunkNodes[k],null);
+					}
+				}
+				
+			} else {
+				if (projects[j] instanceof MyDiffNode) {
+					Diff diff= ((MyDiffNode) projects[j]).getDiff();
+					hunksToCheck.addAll(diff.reset(patcher, strip, previewPatchPage.getFuzzFactor()));
+					viewer.update(diff, null);
+				}
+			}
+		}
+		viewer.refresh();
+		viewer.setCheckedElements(nodesToCheck.toArray());
+	
+		updateEnablements();
+	}
+	
+	private void buildTree(WorkspacePatcher patcher) {
+
+		if (patcher.isWorkspacePatch()) {
+
+			if (root.hasChildren()) {
+				IDiffElement[] children = root.getChildren();
+				for (int i = 0; i < children.length; i++) {
+					root.remove(children[i]);
+				}
+			}
+
+			nodesToDiffs = new HashMap();
+
+			DiffProject[] projects = patcher.getDiffProjects();
+			try {
+				for (int i = 0; i < projects.length; i++) {
+					DiffNode projectNode = new DiffNode(root, Differencer.CHANGE, null, projects[i], null);
+					Iterator iter = projects[i].fDiffs.iterator();
+					while (iter.hasNext()) {
+						Object obj = iter.next();
+						if (obj instanceof Diff) {
+							Diff diff = (Diff) obj;
+							IFile tempFile = projects[i].getFile(new Path(diff.getLabel(diff)));
+							byte[] bytes = quickPatch(tempFile, patcher, diff);
+							int differencer = Differencer.CHANGE;
+							if (failedHunks.size() != 0) {
+								differencer += Differencer.CONFLICTING;
+							}
+							if (!tempFile.exists())
+								tempFile = null;
+							
+							ResourceNode tempNode = new ResourceNode(tempFile);
+							PatchedFileNode patchedNode = new PatchedFileNode(bytes, tempNode.getType(), tempFile.getProjectRelativePath().toString());
+							MyDiffNode allFile = new MyDiffNode(projectNode, differencer, tempNode, tempNode, patchedNode, diff);
+							//Add individual hunks to each Diff node
+							Hunk[] hunks = diff.getHunks();
+							for (int j = 0; j < hunks.length; j++) {
+								Diff tempDiff = new Diff(diff.fOldPath, diff.fOldDate, diff.fNewPath, diff.fNewDate);
+								tempDiff.add(hunks[j]);
+								bytes = quickPatch(tempFile, patcher, tempDiff);
+								differencer = Differencer.NO_CHANGE;
+								switch (hunks[j].getHunkType()) {
+									case Hunk.ADDED :
+										differencer += Differencer.ADDITION;
+										break;
+
+									case Hunk.CHANGED :
+										differencer += Differencer.CHANGE;
+										break;
+
+									case Hunk.DELETED :
+										differencer += Differencer.DELETION;
+										break;
+								}
+
+								if (failedHunks.size() != 0) {
+									differencer += Differencer.CONFLICTING;
+									String[] hunkContents = createInput(hunks[j]);
+									PatchedFileNode ancestor = new PatchedFileNode(hunkContents[LEFT].getBytes(), hunks[j].fParent.getPath().getFileExtension(), hunks[j].getDescription());
+									patchedNode = new PatchedFileNode(hunkContents[RIGHT].getBytes(), tempNode.getType(), hunks[j].getDescription());
+									MyDiffNode hunkNode = new MyDiffNode(allFile, differencer, ancestor, tempNode, patchedNode, hunks[j]);
+									nodesToDiffs.put(hunks[j], hunkNode);
+								} else {
+									patchedNode = new PatchedFileNode(bytes, tempNode.getType(), hunks[j].getDescription());
+									MyDiffNode hunkNode = new MyDiffNode(allFile, differencer, tempNode, tempNode, patchedNode, hunks[j]);
+									nodesToDiffs.put(hunks[j], hunkNode);
+								}
+							}
+
+						}
+
+					}
+				
+				}
+
+			} catch (CoreException e) {
+				//ignore
+			}
+			viewer.setInput(root);
+			viewer.refresh();
+		} else {
+			if (root.hasChildren()) {
+				IDiffElement[] children = root.getChildren();
+				for (int i = 0; i < children.length; i++) {
+					root.remove(children[i]);
+				}
+			}
+
+			nodesToDiffs = new HashMap();
+
+			Diff[] diffs = patcher.getDiffs();
+			try {
+				for (int i = 0; i < diffs.length; i++) {
+					Diff diff = diffs[i];
+					IFile tempFile = patcher.existsInTarget(new Path(diff.getLabel(diff)));
+					
+					byte[] bytes = quickPatch(tempFile, patcher, diff);
+					int differencer = Differencer.CHANGE;
+					if (failedHunks.size() != 0) {
+						differencer += Differencer.CONFLICTING;
+					}
+					ResourceNode tempNode = new ResourceNode(tempFile);
+					PatchedFileNode patchedNode = new PatchedFileNode(bytes, tempNode.getType(), tempFile.getProjectRelativePath().toString());
+					MyDiffNode allFile = new MyDiffNode(root, differencer, tempNode, tempNode, patchedNode, diff);
+					//Add individual hunks to each Diff node
+					Hunk[] hunks = diff.getHunks();
+					for (int j = 0; j < hunks.length; j++) {
+						Diff tempDiff = new Diff(diff.fOldPath, diff.fOldDate, diff.fNewPath, diff.fNewDate);
+						tempDiff.add(hunks[j]);
+						bytes = quickPatch(tempFile, patcher, tempDiff);
+						differencer = Differencer.NO_CHANGE;
+						switch (hunks[j].getHunkType()) {
+							case Hunk.ADDED :
+								differencer += Differencer.ADDITION;
+								break;
+
+							case Hunk.CHANGED :
+								differencer += Differencer.CHANGE;
+								break;
+
+							case Hunk.DELETED :
+								differencer += Differencer.DELETION;
+								break;
+						}
+
+						if (failedHunks.size() != 0) {
+							differencer += Differencer.CONFLICTING;
+							String[] hunkContents = createInput(hunks[j]);
+							PatchedFileNode ancestor = new PatchedFileNode(hunkContents[LEFT].getBytes(), hunks[j].fParent.getPath().getFileExtension(), hunks[j].getDescription());
+							patchedNode = new PatchedFileNode(hunkContents[RIGHT].getBytes(), tempNode.getType(), hunks[j].getDescription());
+							MyDiffNode hunkNode = new MyDiffNode(allFile, differencer, ancestor, tempNode, patchedNode, hunks[j]);
+							nodesToDiffs.put(hunks[j], hunkNode);
+						} else {
+							patchedNode = new PatchedFileNode(bytes, tempNode.getType(), hunks[j].getDescription());
+							MyDiffNode hunkNode = new MyDiffNode(allFile, differencer, tempNode, tempNode, patchedNode, hunks[j]);
+							nodesToDiffs.put(hunks[j], hunkNode);
+						}
+					}
+
+				}
+			} catch (CoreException ex) {//ignore
+			}
+
+		}
+
+	}
+	
+	private byte[] quickPatch(IFile tempFile, WorkspacePatcher patcher, Diff diff) throws CoreException {
+			
+			failedHunks = new ArrayList();
+			List result = patcher.apply(diff, tempFile, diff.getType() == Differencer.ADDITION, failedHunks);
+			String patchedResults = patcher.createString(result);
+			byte[] bytes;
+			try {
+				bytes = patchedResults.getBytes(Utilities.getCharset(tempFile));
+			} catch (UnsupportedEncodingException e) {
+				// uses default encoding
+				bytes = patchedResults.getBytes();
+			}
+		
+		return bytes;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.compare.CompareEditorInput#createDiffViewer(org.eclipse.swt.widgets.Composite)
+	 */
+	public Viewer createDiffViewer(Composite parent) {
+		viewer =  new CheckboxDiffTreeViewer(parent, getCompareConfiguration());
+		viewer.setLabelDecorator(new PatcherCompareEditorDecorator());
+		viewer.getTree().setData(CompareUI.COMPARE_VIEWER_TITLE, PatchMessages.PatcherCompareEditorInput_PatchContents);
+		viewer.addCheckStateListener(new ICheckStateListener() {
+			public void checkStateChanged(CheckStateChangedEvent event) {
+				viewer.setSubtreeChecked(event.getElement(),event.getChecked());
+				updateEnablements();
+			}
+		});
+		viewer.setInput(this);
+		return viewer;
+	}
+	
+	private String[] createInput(Hunk hunk) {
+
+		String[] lines= hunk.fLines;
+		StringBuffer left= new StringBuffer();
+		StringBuffer right= new StringBuffer();
+
+		for (int i= 0; i<lines.length; i++) {
+			String line= lines[i];
+			String rest= line.substring(1);
+			switch (line.charAt(0)) {
+				case ' ' :
+					left.append(rest);
+					right.append(rest);
+					break;
+				case '-' :
+					left.append(rest);
+					break;
+				case '+' :
+					right.append(rest);
+					break;
+			}
+		}
+
+		
+		return new String[]{left.toString(),right.toString()};
+	}
+	
+	public void contributeDiffViewerToolbarItems(Action[] actions, boolean workspacePatch){
+		ToolBarManager tbm= CompareViewerPane.getToolBarManager(viewer.getControl().getParent());
+		if (tbm != null) {
+			tbm.removeAll();
+			
+			tbm.add(new Separator("contributed")); //$NON-NLS-1$
+			
+			for (int i = 0; i < actions.length; i++) {
+				//If this is a workspace patch, make sure all actions are enabled
+				if (workspacePatch)
+					actions[i].setEnabled(true);
+				
+				tbm.appendToGroup("contributed", actions[i]); //$NON-NLS-1$
+			}
+			
+			tbm.update(true);
+		}
+	}
+	
+	public CheckboxDiffTreeViewer getViewer() {
+		return viewer;
+	}
+	
+	/**
+	 * Makes sure that at least one hunk is checked off in the tree before
+	 * allowing the patch to be applied.
+	 */
+	/* private */void updateEnablements() {
+		boolean atLeastOneIsEnabled= false;
+		if (viewer!=null) {
+			ITreeContentProvider contentProvider= (ITreeContentProvider) viewer.getContentProvider();
+			Object[] projects= contentProvider.getElements(root);
+			//Iterate through projects
+			for (int j= 0; j<projects.length; j++) {
+				if (!(projects[j] instanceof MyDiffNode)) {
+					DiffNode project = (DiffNode) projects[j];
+					//Iterate through project diffs
+					Object[] diffs= project.getChildren();
+					for (int i= 0; i<diffs.length; i++) {
+						MyDiffNode diff= (MyDiffNode) diffs[i];
+						atLeastOneIsEnabled= updateEnablement(atLeastOneIsEnabled, diff);
+					}
+				} else if (projects[j] instanceof MyDiffNode) {
+					atLeastOneIsEnabled= updateEnablement(atLeastOneIsEnabled, (MyDiffNode) projects[j]);
+				}
+			}
+		}
+
+		previewPatchPage.setPageComplete(atLeastOneIsEnabled);
+	}
+
+	private boolean updateEnablement(boolean oneIsEnabled, MyDiffNode diffNode) {
+		boolean checked= viewer.getChecked(diffNode);
+		Diff diff = diffNode.getDiff();
+		Assert.isNotNull(diff);
+		diff.setEnabled(checked);
+		if (checked) {
+			Object[] hunkItems= diffNode.getChildren();
+			for (int h= 0; h<hunkItems.length; h++) {
+				MyDiffNode hunkNode = (MyDiffNode) hunkItems[h];
+				checked= viewer.getChecked(hunkNode);
+				Hunk hunk= hunkNode.getHunk();
+				Assert.isNotNull(hunk);
+				hunk.setEnabled(checked);
+				if (checked) {
+					//For workspace patch: before setting enabled flag, make sure that the project
+					//that contains this hunk actually exists in the workspace. This is to guard against the 
+					//case of having a new file in a patch that is being applied to a project that
+					//doesn't currently exist.
+					boolean projectExists= true;
+					DiffProject project= (DiffProject)diff.getParent(null);
+					if (project!= null){
+						projectExists=project.getProject().exists();
+					}
+					if (projectExists)
+						oneIsEnabled= true;
+				}
+
+			}
+		}
+	
+		return oneIsEnabled;
+	}
+	
+
+	/**
+	 * Stores a pointer back to the PreviewPatchPage
+	 * @param page
+	 */
+	public void setPreviewPatchPage(PreviewPatchPage2 page) {
+		previewPatchPage = page;
+	}
+}
diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PreviewPatchPage2.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PreviewPatchPage2.java
new file mode 100644
index 0000000..c8bc66a
--- /dev/null
+++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PreviewPatchPage2.java
@@ -0,0 +1,506 @@
+package org.eclipse.compare.internal.patch;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.compare.ITypedElement;
+import org.eclipse.compare.internal.CompareUIPlugin;
+import org.eclipse.compare.internal.ICompareUIConstants;
+import org.eclipse.compare.structuremergeviewer.DiffNode;
+import org.eclipse.compare.structuremergeviewer.Differencer;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.model.BaseWorkbenchContentProvider;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+import org.eclipse.ui.views.navigator.ResourceSorter;
+
+import com.ibm.icu.text.MessageFormat;
+
+
+public class PreviewPatchPage2 extends WizardPage {
+
+	protected final static String PREVIEWPATCHPAGE_NAME= "PreviewPatchPage";  //$NON-NLS-1$
+	private PatchWizard fPatchWizard;
+	private PatcherCompareEditorInput patcherCompareEditorInput = new PatcherCompareEditorInput();
+	
+	private Combo fStripPrefixSegments;
+	private Text fFuzzField;
+	
+	private Action fRetargetSelection;
+	private Action fIgnoreWhiteSpace;
+	private Action fReversePatch;
+	
+	protected boolean pageRecalculate= true;
+	
+	class RetargetPatchDialog extends Dialog {
+
+		protected TreeViewer rpTreeViewer;
+		protected DiffNode rpSelectedNode;
+		protected DiffProject rpSelectedProject;
+		protected IProject rpTargetProject;
+
+		public RetargetPatchDialog(Shell shell, ISelection selection) {
+			super(shell);
+			setShellStyle(getShellStyle()|SWT.RESIZE);
+			if (selection instanceof IStructuredSelection) {
+				rpSelectedNode= (DiffNode) ((IStructuredSelection) selection).getFirstElement();
+			}
+		}
+
+		protected Control createDialogArea(Composite parent) {
+			Composite composite= (Composite) super.createDialogArea(parent);
+
+			initializeDialogUnits(parent);
+
+			getShell().setText(PatchMessages.PreviewPatchPage_RetargetPatch);
+
+			GridLayout layout= new GridLayout();
+			layout.numColumns= 1;
+	        layout.marginHeight= convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
+	        layout.marginWidth= convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);			
+			composite.setLayout(layout);
+			final GridData data= new GridData(SWT.FILL, SWT.FILL, true, true);
+			composite.setLayoutData(data);
+
+			//add controls to composite as necessary
+			Label label= new Label(composite, SWT.LEFT|SWT.WRAP);
+			label.setText(NLS.bind(PatchMessages.PreviewPatchPage_SelectProject, rpSelectedNode.getName()));
+			final GridData data2= new GridData(SWT.FILL, SWT.BEGINNING, true, false);
+			label.setLayoutData(data2);
+
+			rpTreeViewer= new TreeViewer(composite, SWT.BORDER);
+			GridData gd= new GridData(SWT.FILL, SWT.FILL, true, true);
+			gd.widthHint= 0;
+			gd.heightHint= 0;
+			rpTreeViewer.getTree().setLayoutData(gd);
+
+			rpTreeViewer.setContentProvider(new RetargetPatchContentProvider());
+			rpTreeViewer.setLabelProvider(new WorkbenchLabelProvider());
+			rpTreeViewer.setSorter(new ResourceSorter(ResourceSorter.NAME));
+			rpTreeViewer.setInput(ResourcesPlugin.getWorkspace());
+			ITypedElement tempProject = rpSelectedNode.getLeft();
+			if (tempProject instanceof DiffProject){
+				rpSelectedProject = (DiffProject)tempProject;
+				rpTreeViewer.setSelection(new StructuredSelection(rpSelectedProject.getProject()));
+			}
+			
+			setupListeners();
+
+			Dialog.applyDialogFont(composite);
+			
+			return parent;
+		}
+
+		protected void okPressed() {
+			rpSelectedProject.setProject(rpTargetProject);
+			super.okPressed();
+		}
+
+		void setupListeners() {
+			rpTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+				public void selectionChanged(SelectionChangedEvent event) {
+					IStructuredSelection s= (IStructuredSelection) event.getSelection();
+					Object obj= s.getFirstElement();
+					if (obj instanceof IProject)
+						rpTargetProject= (IProject) obj;
+				}
+			});
+
+			rpTreeViewer.addDoubleClickListener(new IDoubleClickListener() {
+				public void doubleClick(DoubleClickEvent event) {
+					ISelection s= event.getSelection();
+					if (s instanceof IStructuredSelection) {
+						Object item= ((IStructuredSelection) s).getFirstElement();
+						if (rpTreeViewer.getExpandedState(item))
+							rpTreeViewer.collapseToLevel(item, 1);
+						else
+							rpTreeViewer.expandToLevel(item, 1);
+					}
+				}
+			});
+
+		}
+
+		protected Point getInitialSize() {
+			final Point size= super.getInitialSize();
+			size.x= convertWidthInCharsToPixels(75);
+			size.y+= convertHeightInCharsToPixels(20);
+			return size;
+		}
+	}
+
+	class RetargetPatchContentProvider extends BaseWorkbenchContentProvider {
+		//Never show closed projects
+		boolean showClosedProjects= false;
+
+		public Object[] getChildren(Object element) {
+			if (element instanceof IWorkspace) {
+				// check if closed projects should be shown
+				IProject[] allProjects= ((IWorkspace) element).getRoot().getProjects();
+				if (showClosedProjects)
+					return allProjects;
+
+				ArrayList accessibleProjects= new ArrayList();
+				for (int i= 0; i<allProjects.length; i++) {
+					if (allProjects[i].isOpen()) {
+						accessibleProjects.add(allProjects[i]);
+					}
+				}
+				return accessibleProjects.toArray();
+			}
+
+			if (element instanceof IProject) {
+				return new Object[0];
+			}
+			return super.getChildren(element);
+		}
+	}
+
+	public PreviewPatchPage2(PatchWizard pw) {
+		super(PREVIEWPATCHPAGE_NAME, PatchMessages.PreviewPatchPage_title, null);
+		
+		fPatchWizard= pw;
+		
+	}
+		
+	public void createControl(Composite parent) {
+
+		Composite composite = new Composite(parent, SWT.NONE);
+		composite.setLayout(new GridLayout());
+		composite.setLayoutData(new GridData(GridData.FILL_BOTH));
+		
+		initializeDialogUnits(parent);
+		
+		buildPatchOptionsGroup(composite);
+		
+		try {
+			patcherCompareEditorInput.run(null);
+		} catch (InterruptedException e) {//ignore
+		} catch (InvocationTargetException e) {//ignore
+		}
+	
+		
+		Control c = patcherCompareEditorInput.createContents(composite);
+		patcherCompareEditorInput.contributeDiffViewerToolbarItems(getContributedActions(), fPatchWizard.getPatcher().isWorkspacePatch());
+		patcherCompareEditorInput.setPreviewPatchPage(this);
+		c.setLayoutData(new GridData(GridData.FILL_BOTH));
+		setControl(composite);
+		
+	}
+	
+	private Action[] getContributedActions() {
+		fRetargetSelection= new Action(PatchMessages.PreviewPatchPage2_RetargetAction, CompareUIPlugin.getImageDescriptor(ICompareUIConstants.RETARGET_PROJECT)) {
+			public void run() {
+				Shell shell = getShell();
+				ISelection selection = patcherCompareEditorInput.getViewer().getSelection();
+				final RetargetPatchDialog dialog= new RetargetPatchDialog(shell, selection);
+				dialog.open();
+				patcherCompareEditorInput.updateInput(fPatchWizard.getPatcher());
+			}
+		};
+		fRetargetSelection.setToolTipText(PatchMessages.PreviewPatchPage2_RetargetTooltip);
+		fRetargetSelection.setEnabled(false);
+		
+		fIgnoreWhiteSpace = new Action(PatchMessages.PreviewPatchPage2_IgnoreWSAction, CompareUIPlugin.getImageDescriptor(ICompareUIConstants.IGNORE_WHITESPACE_ENABLED)){
+			public void run(){
+				fIgnoreWhiteSpace.setChecked(isChecked());
+				if (fPatchWizard.getPatcher().setIgnoreWhitespace(fIgnoreWhiteSpace.isChecked())){
+					fillTree();
+				}
+			}
+		};
+		fIgnoreWhiteSpace.setChecked(false);
+		fIgnoreWhiteSpace.setToolTipText(PatchMessages.PreviewPatchPage2_IgnoreWSTooltip);
+		fIgnoreWhiteSpace.setDisabledImageDescriptor(CompareUIPlugin.getImageDescriptor(ICompareUIConstants.IGNORE_WHITESPACE_DISABLED));
+		
+		fReversePatch = new Action(PatchMessages.PreviewPatchPage_ReversePatch_text, CompareUIPlugin.getImageDescriptor(ICompareUIConstants.REVERSE_PATCH_ENABLED)){
+			public void run(){
+				fReversePatch.setChecked(isChecked());
+				if (fPatchWizard.getPatcher().setReversed(isChecked())){
+					fillTree();
+				}
+			}
+		};
+		fReversePatch.setChecked(false);
+		fReversePatch.setToolTipText(PatchMessages.PreviewPatchPage_ReversePatch_text);
+		
+		return new Action[]{fIgnoreWhiteSpace, fRetargetSelection, fReversePatch};
+	}
+
+	public void setVisible(boolean visible) {
+		super.setVisible(visible);
+		//Need to handle input and rebuild tree only when becoming visible
+		if(visible){
+			fillTree();
+		}
+	}
+	
+	private void fillTree(){
+		//Update prefix count - go through all of the diffs and find the smallest
+		//path segment contained in all diffs.
+		int length= 99;
+		if (fStripPrefixSegments!=null&& pageRecalculate) {
+			length= fPatchWizard.getPatcher().calculatePrefixSegmentCount();
+			if (length!=99) {
+				for (int k= 1; k<length; k++)
+					fStripPrefixSegments.add(Integer.toString(k));
+				pageRecalculate= false;
+			}
+		}
+		
+		patcherCompareEditorInput.updateInput(fPatchWizard.getPatcher());
+		
+	}
+	/*
+	 *	Create the group for setting various patch options
+	 */
+	private void buildPatchOptionsGroup(Composite parent) {
+		
+		GridLayout gl;
+		GridData gd;
+		Label l;
+
+		final WorkspacePatcher patcher= fPatchWizard.getPatcher();
+
+		Group group= new Group(parent, SWT.NONE);
+		group.setText(PatchMessages.PreviewPatchPage_PatchOptions_title);
+		gl= new GridLayout(); gl.numColumns= 4;
+		group.setLayout(gl);
+		group.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL|GridData.GRAB_HORIZONTAL));
+
+		// 1st row
+
+		Composite pair= new Composite(group, SWT.NONE);
+		gl= new GridLayout(); gl.numColumns= 2; gl.marginHeight= gl.marginWidth= 0;
+		pair.setLayout(gl);
+		gd= new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+		pair.setLayoutData(gd);
+
+		l= new Label(pair, SWT.NONE);
+		l.setText(PatchMessages.PreviewPatchPage_IgnoreSegments_text);
+		gd= new GridData(GridData.VERTICAL_ALIGN_CENTER|GridData.HORIZONTAL_ALIGN_BEGINNING|GridData.GRAB_HORIZONTAL);
+		l.setLayoutData(gd);
+
+		fStripPrefixSegments= new Combo(pair, SWT.DROP_DOWN|SWT.READ_ONLY|SWT.SIMPLE);
+		int prefixCnt= patcher.getStripPrefixSegments();
+		String prefix= Integer.toString(prefixCnt);
+		fStripPrefixSegments.add(prefix);
+		fStripPrefixSegments.setText(prefix);
+		gd= new GridData(GridData.VERTICAL_ALIGN_CENTER|GridData.HORIZONTAL_ALIGN_END);
+		fStripPrefixSegments.setLayoutData(gd);
+
+		addSpacer(group);
+
+		// 2nd row
+		pair= new Composite(group, SWT.NONE);
+		gl= new GridLayout(); gl.numColumns= 3; gl.marginHeight= gl.marginWidth= 0;
+		pair.setLayout(gl);
+		gd= new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+		pair.setLayoutData(gd);
+
+		l= new Label(pair, SWT.NONE);
+		l.setText(PatchMessages.PreviewPatchPage_FuzzFactor_text);
+		l.setToolTipText(PatchMessages.PreviewPatchPage_FuzzFactor_tooltip);
+		gd= new GridData(GridData.VERTICAL_ALIGN_CENTER|GridData.HORIZONTAL_ALIGN_BEGINNING|GridData.GRAB_HORIZONTAL);
+		l.setLayoutData(gd);
+
+		fFuzzField= new Text(pair, SWT.BORDER);
+		fFuzzField.setText("2"); //$NON-NLS-1$
+			gd= new GridData(GridData.VERTICAL_ALIGN_CENTER | GridData.HORIZONTAL_ALIGN_END); gd.widthHint= 30;
+		fFuzzField.setLayoutData(gd);
+
+		Button b= new Button(pair, SWT.PUSH);
+		b.setText(PatchMessages.PreviewPatchPage_GuessFuzz_text);
+			b.addSelectionListener(
+				new SelectionAdapter() {
+			public void widgetSelected(SelectionEvent e) {
+				int fuzz= guessFuzzFactor(patcher);
+				if (fuzz>=0)
+					fFuzzField.setText(Integer.toString(fuzz));
+			}
+				}
+			);
+		gd= new GridData(GridData.VERTICAL_ALIGN_CENTER);
+		int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
+		Point minSize = b.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
+		gd.widthHint = Math.max(widthHint, minSize.x);		
+		b.setLayoutData(gd);
+
+		// register listeners
+
+		if (fStripPrefixSegments!=null)
+			fStripPrefixSegments.addSelectionListener(
+				new SelectionAdapter() {
+				public void widgetSelected(SelectionEvent e) {
+					if (patcher.setStripPrefixSegments(getStripPrefixSegments()))
+						patcherCompareEditorInput.updateInput(patcher);
+				}
+				}
+			);
+	
+
+		fFuzzField.addModifyListener(
+			new ModifyListener() {
+			public void modifyText(ModifyEvent e) {
+				if (patcher.setFuzz(getFuzzFactor()))
+					patcherCompareEditorInput.updateInput(patcher);
+			}
+		});
+	}
+	
+	private void addSpacer(Composite parent) {
+		Label label= new Label(parent, SWT.NONE);
+		GridData gd= new GridData(GridData.FILL_HORIZONTAL);
+		gd.widthHint= 10;
+		label.setLayoutData(gd);
+	}
+	
+	public int getFuzzFactor() {
+		int fuzzFactor= 0;
+		if (fFuzzField!=null) {
+			String s= fFuzzField.getText();
+			try {
+				fuzzFactor= Integer.parseInt(s);
+			} catch (NumberFormatException ex) {
+				// silently ignored
+			}
+		}
+		return fuzzFactor;
+	}
+	
+	public int getStripPrefixSegments() {
+		int stripPrefixSegments= 0;
+		if (fStripPrefixSegments!=null) {
+			String s= fStripPrefixSegments.getText();
+			try {
+				stripPrefixSegments= Integer.parseInt(s);
+			} catch (NumberFormatException ex) {
+				// silently ignored
+			}
+		}
+		return stripPrefixSegments;
+	}
+	
+	private int guessFuzzFactor(final WorkspacePatcher patcher) {
+		final int strip= getStripPrefixSegments();
+		final int[] result= new int[1];
+		try {
+			PlatformUI.getWorkbench().getProgressService().run(true, true,
+			//TimeoutContext.run(true, GUESS_TIMEOUT, getControl().getShell(),
+					new IRunnableWithProgress() {
+						public void run(IProgressMonitor monitor) {
+							result[0]= guess(patcher, monitor, strip);
+						}
+				}
+			);
+			return result[0];
+		} catch (InvocationTargetException ex) {
+			// NeedWork
+		} catch (InterruptedException ex) {
+			// NeedWork
+		}
+		return -1;
+	}
+	
+	private int guess(WorkspacePatcher patcher, IProgressMonitor pm, int strip) {
+
+		Diff[] diffs= patcher.getDiffs();
+		if (diffs==null||diffs.length<=0)
+			return -1;
+
+		// now collect files and determine "work"
+		IFile[] files= new IFile[diffs.length];
+		int work= 0;
+		for (int i= 0; i<diffs.length; i++) {
+			Diff diff= diffs[i];
+			if (diff==null)
+				continue;
+			if (diff.getType()!=Differencer.ADDITION) {
+				IPath p= diff.fOldPath;
+				if (strip>0&&strip<p.segmentCount())
+					p= p.removeFirstSegments(strip);
+				IFile file= existsInSelection(p);
+				if (file!=null) {
+					files[i]= file;
+					work+= diff.fHunks.size();
+				}
+			}
+		}
+
+		// do the "work"
+		int[] fuzzRef= new int[1];
+		String format= PatchMessages.PreviewPatchPage_GuessFuzzProgress_format;
+		pm.beginTask(PatchMessages.PreviewPatchPage_GuessFuzzProgress_text, work);
+		try {
+			int fuzz= 0;
+			for (int i= 0; i<diffs.length; i++) {
+				Diff d= diffs[i];
+				IFile file= files[i];
+				if (d!=null&&file!=null) {
+					List lines= patcher.load(file, false);
+					String name= d.getPath().lastSegment();
+					Iterator iter= d.fHunks.iterator();
+					int shift= 0;
+					for (int hcnt= 1; iter.hasNext(); hcnt++) {
+						pm.subTask(MessageFormat.format(format, new String[] {name, Integer.toString(hcnt)}));
+						Hunk h= (Hunk) iter.next();
+						shift= patcher.calculateFuzz(h, lines, shift, pm, fuzzRef);
+						int f= fuzzRef[0];
+						if (f==-1) // cancel
+							return -1;
+						if (f>fuzz)
+							fuzz= f;
+						pm.worked(1);
+					}
+				}
+			}
+			return fuzz;
+		} finally {
+			pm.done();
+		}
+	}
+	
+	private IFile existsInSelection(IPath path) {
+		return fPatchWizard.getPatcher().existsInTarget(path);
+	}
+	
+	
+
+}
diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/CompareUI.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/CompareUI.java
index 94f1050..3c6d65c 100644
--- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/CompareUI.java
+++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/CompareUI.java
@@ -14,6 +14,7 @@
 
 import org.eclipse.compare.internal.CompareUIPlugin;
 import org.eclipse.compare.internal.DocumentManager;
+import org.eclipse.compare.internal.ICompareUIConstants;
 import org.eclipse.compare.structuremergeviewer.ICompareInput;
 import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.core.runtime.content.IContentType;
@@ -57,33 +58,33 @@
 	 * Image descriptor for the disabled icon of the 'Next' tool bar button.
 	 * @since 2.0
 	 */
-	public static final ImageDescriptor DESC_DTOOL_NEXT= CompareUIPlugin.getImageDescriptor(CompareUIPlugin.DTOOL_NEXT);
+	public static final ImageDescriptor DESC_DTOOL_NEXT= CompareUIPlugin.getImageDescriptor(ICompareUIConstants.DTOOL_NEXT);
 	/**
 	 * Image descriptor for the normal icon of the 'Next' tool bar button.
 	 * @since 2.0
 	 */
-	public static final ImageDescriptor DESC_CTOOL_NEXT= CompareUIPlugin.getImageDescriptor(CompareUIPlugin.CTOOL_NEXT);
+	public static final ImageDescriptor DESC_CTOOL_NEXT= CompareUIPlugin.getImageDescriptor(ICompareUIConstants.CTOOL_NEXT);
 	/**
 	 * Image descriptor for the roll-over icon of the 'Next' tool bar button.
 	 * @since 2.0
 	 */
-	public static final ImageDescriptor DESC_ETOOL_NEXT= CompareUIPlugin.getImageDescriptor(CompareUIPlugin.ETOOL_NEXT);
+	public static final ImageDescriptor DESC_ETOOL_NEXT= CompareUIPlugin.getImageDescriptor(ICompareUIConstants.ETOOL_NEXT);
 	
 	/**
 	 * Image descriptor for the disabled icon of the 'Previous' tool bar button.
 	 * @since 2.0
 	 */
-	public static final ImageDescriptor DESC_DTOOL_PREV= CompareUIPlugin.getImageDescriptor(CompareUIPlugin.DTOOL_PREV);
+	public static final ImageDescriptor DESC_DTOOL_PREV= CompareUIPlugin.getImageDescriptor(ICompareUIConstants.DTOOL_PREV);
 	/**
 	 * Image descriptor for the normal icon of the 'Previous' tool bar button.
 	 * @since 2.0
 	 */
-	public static final ImageDescriptor DESC_CTOOL_PREV= CompareUIPlugin.getImageDescriptor(CompareUIPlugin.CTOOL_PREV);
+	public static final ImageDescriptor DESC_CTOOL_PREV= CompareUIPlugin.getImageDescriptor(ICompareUIConstants.CTOOL_PREV);
 	/**
 	 * Image descriptor for the roll-over icon of the 'Previous' tool bar button.
 	 * @since 2.0
 	 */
-	public static final ImageDescriptor DESC_ETOOL_PREV= CompareUIPlugin.getImageDescriptor(CompareUIPlugin.ETOOL_PREV);
+	public static final ImageDescriptor DESC_ETOOL_PREV= CompareUIPlugin.getImageDescriptor(ICompareUIConstants.ETOOL_PREV);
 
 	/**
 	 * Name of the title property of a compare viewer.
diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/CompareUIPlugin.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/CompareUIPlugin.java
index 3cdfe35..34a04bf 100644
--- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/CompareUIPlugin.java
+++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/CompareUIPlugin.java
@@ -134,14 +134,6 @@
 	    	}
     }
 	
-	public static final String DTOOL_NEXT= "dlcl16/next_nav.gif";	//$NON-NLS-1$
-	public static final String ETOOL_NEXT= "elcl16/next_nav.gif";	//$NON-NLS-1$
-	public static final String CTOOL_NEXT= ETOOL_NEXT;
-	
-	public static final String DTOOL_PREV= "dlcl16/prev_nav.gif";	//$NON-NLS-1$
-	public static final String ETOOL_PREV= "elcl16/prev_nav.gif";	//$NON-NLS-1$
-	public static final String CTOOL_PREV= ETOOL_PREV;
-				
 	/** Status code describing an internal error */
 	public static final int INTERNAL_ERROR= 1;
 
diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/ICompareUIConstants.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/ICompareUIConstants.java
new file mode 100644
index 0000000..3e17776
--- /dev/null
+++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/ICompareUIConstants.java
@@ -0,0 +1,21 @@
+package org.eclipse.compare.internal;
+
+
+public interface ICompareUIConstants {
+	public final String PREFIX = CompareUIPlugin.getPluginId() + "."; //$NON-NLS-1$
+	
+	public static final String DTOOL_NEXT= "dlcl16/next_nav.gif";	//$NON-NLS-1$
+	public static final String ETOOL_NEXT= "elcl16/next_nav.gif";	//$NON-NLS-1$
+	public static final String CTOOL_NEXT= ETOOL_NEXT;
+	
+	public static final String DTOOL_PREV= "dlcl16/prev_nav.gif";	//$NON-NLS-1$
+	public static final String ETOOL_PREV= "elcl16/prev_nav.gif";	//$NON-NLS-1$
+	public static final String CTOOL_PREV= ETOOL_PREV;
+
+	public static final String RETARGET_PROJECT= "eview16/compare_view.gif";	//$NON-NLS-1$
+	
+	public static final String IGNORE_WHITESPACE_ENABLED= "etool16/ignorews_edit.gif";	//$NON-NLS-1$
+	public static final String IGNORE_WHITESPACE_DISABLED= "dtool16/ignorews_edit.gif";	//$NON-NLS-1$
+	
+	public static final String REVERSE_PATCH_ENABLED = "etool16/reverse_enabled.gif";	//$NON-NLS-1$
+}
diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/CheckboxDiffTreeViewer.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/CheckboxDiffTreeViewer.java
new file mode 100644
index 0000000..6d91532
--- /dev/null
+++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/CheckboxDiffTreeViewer.java
@@ -0,0 +1,297 @@
+package org.eclipse.compare.internal.patch;
+
+import java.util.ResourceBundle;
+
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.compare.internal.INavigatable;
+import org.eclipse.compare.internal.IOpenable;
+import org.eclipse.compare.internal.Utilities;
+import org.eclipse.compare.structuremergeviewer.IDiffContainer;
+import org.eclipse.compare.structuremergeviewer.IDiffElement;
+import org.eclipse.jface.viewers.DecoratingLabelProvider;
+import org.eclipse.jface.viewers.ILabelDecorator;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.OpenEvent;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.ui.dialogs.ContainerCheckedTreeViewer;
+
+public class CheckboxDiffTreeViewer extends ContainerCheckedTreeViewer {
+	
+	class CheckboxDiffViewerContentProvider implements ITreeContentProvider {
+		
+		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+			// empty implementation
+		}
+	
+		public boolean isDeleted(Object element) {
+			return false;
+		}
+			
+		public void dispose() {
+			inputChanged(CheckboxDiffTreeViewer.this, getInput(), null);
+		}
+			
+		public Object getParent(Object element) {
+			if (element instanceof IDiffElement) 
+				return ((IDiffElement)element).getParent();
+			return null;
+		}
+		
+		public final boolean hasChildren(Object element) {
+			if (element instanceof IDiffContainer) 
+				return ((IDiffContainer)element).hasChildren();
+			return false;
+		}
+		
+		public final Object[] getChildren(Object element) {
+			if (element instanceof IDiffContainer)
+				return ((IDiffContainer)element).getChildren();
+			return new Object[0];
+		}
+		
+		public Object[] getElements(Object element) {
+			return getChildren(element);
+		}				
+	}
+	
+	/*
+	 * Takes care of swapping left and right if fLeftIsLocal
+	 * is true.
+	 */
+	class CheckboxDiffViewerLabelProvider extends LabelProvider {
+		
+		public String getText(Object element) {
+		
+			if (element instanceof IDiffElement)
+				return ((IDiffElement)element).getName();
+			
+			
+			return Utilities.getString(fBundle, "defaultLabel"); //$NON-NLS-1$
+		}
+	
+		public Image getImage(Object element) {
+			if (element instanceof IDiffElement) {
+				IDiffElement input= (IDiffElement) element;	
+				return input.getImage();
+			}
+			return null;
+		}
+	}
+
+	CompareConfiguration fCompareConfiguration;
+	private ResourceBundle fBundle;
+
+	public CheckboxDiffTreeViewer(Composite parent, CompareConfiguration compareConfiguration) {
+		super(parent);
+		initialize(compareConfiguration);
+	}
+
+	private void initialize(CompareConfiguration compareConfiguration) {
+		Control tree= getControl();
+		
+		INavigatable nav= new INavigatable() {
+			public boolean gotoDifference(boolean next) {
+				// Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106
+				return internalNavigate(next, true);
+			}
+		};
+		tree.setData(INavigatable.NAVIGATOR_PROPERTY, nav);
+		
+		// Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106
+		IOpenable openable= new IOpenable() {
+			public void openSelected() {
+				internalOpen();
+			}
+		};
+		tree.setData(IOpenable.OPENABLE_PROPERTY, openable);
+		
+		fBundle= ResourceBundle.getBundle("org.eclipse.compare.structuremergeviewer.DiffTreeViewerResources"); //$NON-NLS-1$
+				
+		setContentProvider(new CheckboxDiffViewerContentProvider());
+		setLabelProvider(new CheckboxDiffViewerLabelProvider());
+		
+		addSelectionChangedListener(
+			new ISelectionChangedListener() {
+				public void selectionChanged(SelectionChangedEvent se) {
+					//updateActions();
+				}
+			}
+		);
+												
+	}
+
+/**
+ * Selects the next (or previous) node of the current selection.
+ * If there is no current selection the first (last) node in the tree is selected.
+ * Wraps around at end or beginning.
+ * Clients may override. 
+ *
+ * @param next if <code>true</code> the next node is selected, otherwise the previous node
+ * @param fireOpen if <code>true</code> an open event is fired.
+ * @return <code>true</code> if at end (or beginning)
+ */
+private boolean internalNavigate(boolean next, boolean fireOpen) {
+	
+	Control c= getControl();
+	if (!(c instanceof Tree))
+		return false;
+		
+	Tree tree= (Tree) c;
+	TreeItem item= null;
+	TreeItem children[]= tree.getSelection();
+	if (children != null && children.length > 0)
+		item= children[0];
+	if (item == null) {
+		children= tree.getItems();
+		if (children != null && children.length > 0) {
+			item= children[0];
+			if (item != null && item.getItemCount() <= 0) {
+				internalSetSelection(item, fireOpen);				// Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106
+				return false;
+			}
+		}
+	}
+		
+	while (true) {
+		item= findNextPrev(item, next);
+		if (item == null)
+			break;
+		if (item.getItemCount() <= 0)
+			break;
+	}
+	
+	if (item != null) {
+		internalSetSelection(item, fireOpen);	// Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106
+		return false;
+	}
+	return true;
+}
+
+private TreeItem findNextPrev(TreeItem item, boolean next) {
+	
+	if (item == null)
+		return null;
+	
+	TreeItem children[]= null;
+
+	if (!next) {
+	
+		TreeItem parent= item.getParentItem();
+		if (parent != null)
+			children= parent.getItems();
+		else
+			children= item.getParent().getItems();
+		
+		if (children != null && children.length > 0) {
+			// goto previous child
+			int index= 0;
+			for (; index < children.length; index++)
+				if (children[index] == item)
+					break;
+			
+			if (index > 0) {
+				
+				item= children[index-1];
+				
+				while (true) {
+					createChildren(item);
+					int n= item.getItemCount();
+					if (n <= 0)
+						break;
+						
+					item.setExpanded(true);
+					item= item.getItems()[n-1];
+				}
+
+				// previous
+				return item;
+			}
+		}
+		
+		// go up
+		item= parent;
+				
+	} else {
+		item.setExpanded(true);
+		createChildren(item);
+		
+		if (item.getItemCount() > 0) {
+			// has children: go down
+			children= item.getItems();
+			return children[0];
+		}
+		
+		while (item != null) {
+			children= null;
+			TreeItem parent= item.getParentItem();
+			if (parent != null)
+				children= parent.getItems();
+			else
+				children= item.getParent().getItems();
+			
+			if (children != null && children.length > 0) {
+				// goto next child
+				int index= 0;
+				for (; index < children.length; index++)
+					if (children[index] == item)
+						break;
+				
+				if (index < children.length-1) {
+					// next
+					return children[index+1];
+				}
+			}
+			
+			// go up
+			item= parent;
+		}
+	}
+			
+	return item;
+}
+
+private void internalSetSelection(TreeItem ti, boolean fireOpen) {
+	if (ti != null) {
+		Object data= ti.getData();
+		if (data != null) {
+			// Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106
+			ISelection selection= new StructuredSelection(data);
+			setSelection(selection, true);
+			ISelection currentSelection= getSelection();
+			if (fireOpen && currentSelection != null && selection.equals(currentSelection)) {
+				fireOpen(new OpenEvent(this, selection));
+			}
+		}
+	}
+}
+
+/*
+ * Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106
+ */ 
+private void internalOpen()  {
+	ISelection selection= getSelection();
+	if (selection != null && !selection.isEmpty()) {
+		fireOpen(new OpenEvent(this, selection));
+	}
+}
+
+/**
+ * Creates a new DecoratingLabelProvider (using the passed in ILabelDecorator) and sets
+ * it as the label provider for the tree
+ * @param decorator
+ */
+public void setLabelDecorator(ILabelDecorator decorator) {
+	setLabelProvider(new DecoratingLabelProvider(new CheckboxDiffViewerLabelProvider(), decorator));
+}
+
+}
diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/DiffProject.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/DiffProject.java
index 6da4e19..b8545b0 100644
--- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/DiffProject.java
+++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/DiffProject.java
@@ -14,14 +14,17 @@
 import java.util.Iterator;
 import java.util.List;
 
+import org.eclipse.compare.CompareUI;
+import org.eclipse.compare.ITypedElement;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
 import org.eclipse.ui.model.IWorkbenchAdapter;
 
-public class DiffProject implements IWorkbenchAdapter, IAdaptable {
+public class DiffProject implements IWorkbenchAdapter, IAdaptable, ITypedElement {
 
 	List fDiffs= new ArrayList();
 	IProject fProject;
@@ -48,7 +51,7 @@
 		return this.fProject;
 	}
 
-	String getName() {
+	public String getName() {
 		return fProject.getName();
 	}
 
@@ -125,4 +128,12 @@
 	public String getOriginalProjectName() {
 		return fOriginalProjectName;
 	}
+
+	public Image getImage() {
+		return CompareUI.getImage(fProject);
+	}
+
+	public String getType() {
+		return ITypedElement.FOLDER_TYPE;
+	}
 }
diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.java
index 75b3c6b..d60d1d3 100644
--- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.java
+++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.java
@@ -26,6 +26,9 @@
 	public static String PatchAction_AlwaysSaveQuestion;
 	public static String PatchAction_SaveAllQuestion;
 	public static String PatchAction_SaveAllDescription;
+	public static String PatcherCompareEditorInput_AfterPatch;
+	public static String PatcherCompareEditorInput_LocalCopy;
+	public static String PatcherCompareEditorInput_PatchContents;
 	public static String PatchWizard_title;
 	public static String PatchWizard_unexpectedException_message;
 	public static String InputPatchPage_title;
@@ -87,4 +90,8 @@
 	public static String PreviewPatchPage_SelectProject;
 	public static String PreviewPatchPage_Target;
 	public static String PreviewPatchLabelDecorator_ProjectDoesNotExist;
+	public static String PreviewPatchPage2_IgnoreWSAction;
+	public static String PreviewPatchPage2_IgnoreWSTooltip;
+	public static String PreviewPatchPage2_RetargetAction;
+	public static String PreviewPatchPage2_RetargetTooltip;
 }
\ No newline at end of file
diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.properties b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.properties
index a44d187..a482462 100644
--- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.properties
+++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.properties
@@ -16,6 +16,8 @@
 PatchAction_ExceptionTitle=Saving Resources
 PatchAction_Exception=Unexpected exception. See log for details
 PatchAction_SavingDirtyEditorsTask=Saving dirty editors
+PatcherCompareEditorInput_LocalCopy=Local Copy
+PatcherCompareEditorInput_AfterPatch=After Patch
 PatchAction_AlwaysSaveQuestion=&Always save all modified resources automatically prior to patching
 PatchAction_SaveAllQuestion=Save all modified resources
 PatchAction_SaveAllDescription=All modified resources have to be saved before this operation.\nClick 'OK' to confirm or click 'Cancel'.
@@ -25,6 +27,7 @@
 #
 PatchWizard_title=Apply Patch
 PatchWizard_unexpectedException_message= Unexpected exception while applying the patch. See log for a detailed error description.
+PatcherCompareEditorInput_PatchContents=Patch Contents
 
 #
 # InputPatchPage
@@ -73,10 +76,14 @@
 PreviewPatchPage_IgnoreSegments_text=&Ignore leading path name segments:
 PreviewPatchPage_ReversePatch_text=&Reverse patch
 PreviewPatchPage_FuzzFactor_text=&Maximum fuzz factor:
+PreviewPatchPage2_RetargetAction=Retarget
+PreviewPatchPage2_IgnoreWSAction=Ignore WhiteSpace
 PreviewPatchPage_FuzzFactor_tooltip=Allow Context to Shift This Number of Lines from the Original Location
 PreviewPatchPage_IgnoreWhitespace_text=Ignore &white space
 PreviewPatchPage_NoName_text=no name
 PreviewPatchPage_FileExists_error=(file already exists)
+PreviewPatchPage2_RetargetTooltip=Retarget Project
+PreviewPatchPage2_IgnoreWSTooltip=Ignore WhiteSpace
 PreviewPatchPage_FileDoesNotExist_error=(file does not exist)
 PreviewPatchPage_NoMatch_error=(no match)
 PreviewPatchPage_MatchProjects=Retarget &Patch...
diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchWizard.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchWizard.java
index 9ae3aa3..740ce77 100644
--- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchWizard.java
+++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchWizard.java
@@ -79,7 +79,7 @@
 		
 		addPage(fPatchWizardPage= new InputPatchPage(this));
 		addPage(new PatchTargetPage(this));
-		addPage(new PreviewPatchPage(this));
+		addPage(new PreviewPatchPage2(this));
 	}
 	
 	/* (non-Javadoc)
diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatcherCompareEditorInput.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatcherCompareEditorInput.java
new file mode 100644
index 0000000..395c661
--- /dev/null
+++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatcherCompareEditorInput.java
@@ -0,0 +1,593 @@
+package org.eclipse.compare.internal.patch;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.compare.CompareEditorInput;
+import org.eclipse.compare.CompareUI;
+import org.eclipse.compare.CompareViewerPane;
+import org.eclipse.compare.IStreamContentAccessor;
+import org.eclipse.compare.ITypedElement;
+import org.eclipse.compare.ResourceNode;
+import org.eclipse.compare.internal.CompareUIPlugin;
+import org.eclipse.compare.internal.DiffImage;
+import org.eclipse.compare.internal.Utilities;
+import org.eclipse.compare.structuremergeviewer.DiffNode;
+import org.eclipse.compare.structuremergeviewer.Differencer;
+import org.eclipse.compare.structuremergeviewer.IDiffContainer;
+import org.eclipse.compare.structuremergeviewer.IDiffElement;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.action.ToolBarManager;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.ILabelDecorator;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+
+public class PatcherCompareEditorInput extends CompareEditorInput {
+
+	class PatchedFileNode implements ITypedElement, IStreamContentAccessor {
+
+		byte[] bytes;
+		String type;
+		String name;
+		
+		
+		public PatchedFileNode(byte[] bytes, String type, String name){
+			this.bytes = bytes;
+			this.type = type;
+			this.name = name;
+		}
+		
+		public Image getImage() {
+			return null;
+		}
+
+		public String getName() {
+			return name;
+		}
+
+		public String getType() {
+			return type;
+		}
+
+		public InputStream getContents() throws CoreException {
+			return new ByteArrayInputStream(bytes);
+		}
+		
+	}
+
+	class MyDiffNode extends DiffNode {
+		
+		//Diff associated with this MyDiffNode
+		private Diff diff = null;
+		//Hunk associated with this MyDiffNode
+		private Hunk hunk = null;
+		
+
+		public MyDiffNode(IDiffContainer parent, int kind, ITypedElement ancestor, ITypedElement left, ITypedElement right, Diff diff) {
+			super(parent, kind, ancestor, left, right);
+			this.diff = diff;
+		}
+		
+		public MyDiffNode(IDiffContainer parent, int kind, ITypedElement ancestor, ITypedElement left, ITypedElement right, Hunk hunk) {
+			super(parent, kind, ancestor, left, right);
+			this.hunk = hunk;
+		}
+
+		public String getName() {
+			if (diff != null)
+				return diff.getLabel(diff);
+			
+			if (hunk != null)
+				return hunk.getLabel(hunk);
+			
+			return ""; //$NON-NLS-1$
+		}
+
+		Diff getDiff() {
+			return diff;
+		}
+
+
+		Hunk getHunk() {
+			return hunk;
+		}
+
+	}
+	
+	class PatcherCompareEditorDecorator implements ILabelDecorator {
+
+		/** Maps strings to images */
+		private Map fImages= new Hashtable(10);
+		private List fDisposeOnShutdownImages= new ArrayList();
+
+		ImageDescriptor errId= CompareUIPlugin.getImageDescriptor("ovr16/error_ov.gif");	//$NON-NLS-1$
+		
+		static final String error = "error"; //$NON-NLS-1$
+		static final String add = "add"; //$NON-NLS-1$
+		static final String delete = "del"; //$NON-NLS-1$
+		
+		public Image decorateImage(Image image, Object element) {
+			if (element instanceof MyDiffNode){
+				MyDiffNode myDiffNode = (MyDiffNode) element;
+				Diff diff = myDiffNode.getDiff();
+				Hunk hunk = myDiffNode.getHunk();
+				if (diff != null){
+				  switch (diff.getType()){
+					  case Differencer.ADDITION:
+					  return getImageFor(add + (diff.fMatches ? "" : error), image, diff.fMatches); //$NON-NLS-1$
+				
+					  case Differencer.DELETION:
+					  return getImageFor(delete + (diff.fMatches ? "" : error), image, diff.fMatches); //$NON-NLS-1$
+					  
+					  default:
+					  return getImageFor(diff.fMatches ? "" : error, image, diff.fMatches); //$NON-NLS-1$
+				  }
+				} else if (hunk != null){
+					return getImageFor((hunk.fMatches ? "" : error),image, hunk.fMatches); //$NON-NLS-1$
+				}
+			}
+			return null;
+		}
+
+		private Image getImageFor(String id, Image image, boolean hasMatches) {
+			Image cached_image = (Image) fImages.get(id);
+			if (cached_image == null){
+				DiffImage diffImage = new DiffImage(image, hasMatches ? null : errId, 16, false);
+				cached_image = diffImage.createImage();
+				fImages.put(id, cached_image);
+				fDisposeOnShutdownImages.add(cached_image);
+			}
+			return cached_image;
+		}
+
+		public String decorateText(String text, Object element) {
+			if (element instanceof DiffNode){	
+				ITypedElement typedElement = ((DiffNode) element).getLeft();
+				if (typedElement != null && typedElement instanceof DiffProject){
+					DiffProject project = (DiffProject) typedElement;
+					if (!project.getName().equals(project.getOriginalProjectName()))	
+						return NLS.bind(PatchMessages.Diff_2Args, 
+								new String[]{project.getOriginalProjectName(),
+								NLS.bind(PatchMessages.PreviewPatchPage_Target, new String[]{project.getName()})});
+				}
+			} 
+			
+			return null;
+		}
+
+		public void dispose() {
+			if (fDisposeOnShutdownImages != null) {
+				Iterator i= fDisposeOnShutdownImages.iterator();
+				while (i.hasNext()) {
+					Image img= (Image) i.next();
+					if (!img.isDisposed())
+						img.dispose();
+				}
+				fImages= null;
+			}
+		}
+
+		public boolean isLabelProperty(Object element, String property) {
+			return false;
+		}
+
+		public void addListener(ILabelProviderListener listener) {
+			//don't need listener	
+		}
+		
+		public void removeListener(ILabelProviderListener listener) {
+			//don't need listener
+		} 
+		
+	}
+	private DiffNode root;
+	private List failedHunks;
+	
+	private CheckboxDiffTreeViewer viewer;
+	private final static int LEFT = 0;
+	private final static int RIGHT = 1;
+	private PreviewPatchPage2 previewPatchPage;
+	
+	private HashMap nodesToDiffs;
+	
+	public PatcherCompareEditorInput() {
+		super(new CompareConfiguration());
+		root = new DiffNode(Differencer.NO_CHANGE) {
+			public boolean hasChildren() {
+				return true;
+			}
+		};
+	}
+
+	protected Object prepareInput(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+		initLabels();
+		return root;
+	}
+	
+	private void initLabels() {
+		CompareConfiguration cc = getCompareConfiguration();
+		cc.setLeftEditable(false);
+		cc.setRightEditable(false);
+		String leftLabel = PatchMessages.PatcherCompareEditorInput_LocalCopy;
+		cc.setLeftLabel(leftLabel);
+		String rightLabel = PatchMessages.PatcherCompareEditorInput_AfterPatch;
+		cc.setRightLabel(rightLabel);
+	}
+
+	public void updateInput(WorkspacePatcher patcher) {
+		buildTree(patcher);
+		updateTree(patcher);
+	}
+	
+	private void updateTree(WorkspacePatcher patcher){
+		if (viewer == null)
+			return;
+		
+		int strip= previewPatchPage.getStripPrefixSegments();
+		//Get the elements from the content provider
+		ITreeContentProvider contentProvider= (ITreeContentProvider) viewer.getContentProvider();
+		Object[] projects= contentProvider.getElements(root);
+		ArrayList hunksToCheck= new ArrayList();
+		ArrayList nodesToCheck=new ArrayList();
+		//Iterate through projects and call reset on each project
+		for (int j= 0; j<projects.length; j++) {
+			if (!(projects[j] instanceof MyDiffNode)) {
+				DiffNode projectNode = (DiffNode) projects[j];
+				ITypedElement project = projectNode.getLeft();
+				Assert.isNotNull(project);
+				Assert.isTrue(project instanceof DiffProject);
+				hunksToCheck.addAll(((DiffProject)project).reset(patcher, strip, previewPatchPage.getFuzzFactor()));
+				IDiffElement[] diffNodes = projectNode.getChildren();
+				
+				Iterator iter = hunksToCheck.iterator();
+				while (iter.hasNext()){
+					Hunk hunkToMatch = (Hunk) iter.next();
+					Object matchingHunkNode = nodesToDiffs.get(hunkToMatch);
+					if (matchingHunkNode != null)
+						nodesToCheck.add(matchingHunkNode);
+					
+				}
+				for (int i = 0; i < diffNodes.length; i++) {
+					viewer.update(diffNodes[i], null);
+					IDiffElement[] hunkNodes =((MyDiffNode) diffNodes[i]).getChildren();
+					for (int k = 0; k < hunkNodes.length; k++) {
+						viewer.update(hunkNodes[k],null);
+					}
+				}
+				
+			} else {
+				if (projects[j] instanceof MyDiffNode) {
+					Diff diff= ((MyDiffNode) projects[j]).getDiff();
+					hunksToCheck.addAll(diff.reset(patcher, strip, previewPatchPage.getFuzzFactor()));
+					viewer.update(diff, null);
+				}
+			}
+		}
+		viewer.refresh();
+		viewer.setCheckedElements(nodesToCheck.toArray());
+	
+		updateEnablements();
+	}
+	
+	private void buildTree(WorkspacePatcher patcher) {
+
+		if (patcher.isWorkspacePatch()) {
+
+			if (root.hasChildren()) {
+				IDiffElement[] children = root.getChildren();
+				for (int i = 0; i < children.length; i++) {
+					root.remove(children[i]);
+				}
+			}
+
+			nodesToDiffs = new HashMap();
+
+			DiffProject[] projects = patcher.getDiffProjects();
+			try {
+				for (int i = 0; i < projects.length; i++) {
+					DiffNode projectNode = new DiffNode(root, Differencer.CHANGE, null, projects[i], null);
+					Iterator iter = projects[i].fDiffs.iterator();
+					while (iter.hasNext()) {
+						Object obj = iter.next();
+						if (obj instanceof Diff) {
+							Diff diff = (Diff) obj;
+							IFile tempFile = projects[i].getFile(new Path(diff.getLabel(diff)));
+							byte[] bytes = quickPatch(tempFile, patcher, diff);
+							int differencer = Differencer.CHANGE;
+							if (failedHunks.size() != 0) {
+								differencer += Differencer.CONFLICTING;
+							}
+							if (!tempFile.exists())
+								tempFile = null;
+							
+							ResourceNode tempNode = new ResourceNode(tempFile);
+							PatchedFileNode patchedNode = new PatchedFileNode(bytes, tempNode.getType(), tempFile.getProjectRelativePath().toString());
+							MyDiffNode allFile = new MyDiffNode(projectNode, differencer, tempNode, tempNode, patchedNode, diff);
+							//Add individual hunks to each Diff node
+							Hunk[] hunks = diff.getHunks();
+							for (int j = 0; j < hunks.length; j++) {
+								Diff tempDiff = new Diff(diff.fOldPath, diff.fOldDate, diff.fNewPath, diff.fNewDate);
+								tempDiff.add(hunks[j]);
+								bytes = quickPatch(tempFile, patcher, tempDiff);
+								differencer = Differencer.NO_CHANGE;
+								switch (hunks[j].getHunkType()) {
+									case Hunk.ADDED :
+										differencer += Differencer.ADDITION;
+										break;
+
+									case Hunk.CHANGED :
+										differencer += Differencer.CHANGE;
+										break;
+
+									case Hunk.DELETED :
+										differencer += Differencer.DELETION;
+										break;
+								}
+
+								if (failedHunks.size() != 0) {
+									differencer += Differencer.CONFLICTING;
+									String[] hunkContents = createInput(hunks[j]);
+									PatchedFileNode ancestor = new PatchedFileNode(hunkContents[LEFT].getBytes(), hunks[j].fParent.getPath().getFileExtension(), hunks[j].getDescription());
+									patchedNode = new PatchedFileNode(hunkContents[RIGHT].getBytes(), tempNode.getType(), hunks[j].getDescription());
+									MyDiffNode hunkNode = new MyDiffNode(allFile, differencer, ancestor, tempNode, patchedNode, hunks[j]);
+									nodesToDiffs.put(hunks[j], hunkNode);
+								} else {
+									patchedNode = new PatchedFileNode(bytes, tempNode.getType(), hunks[j].getDescription());
+									MyDiffNode hunkNode = new MyDiffNode(allFile, differencer, tempNode, tempNode, patchedNode, hunks[j]);
+									nodesToDiffs.put(hunks[j], hunkNode);
+								}
+							}
+
+						}
+
+					}
+				
+				}
+
+			} catch (CoreException e) {
+				//ignore
+			}
+			viewer.setInput(root);
+			viewer.refresh();
+		} else {
+			if (root.hasChildren()) {
+				IDiffElement[] children = root.getChildren();
+				for (int i = 0; i < children.length; i++) {
+					root.remove(children[i]);
+				}
+			}
+
+			nodesToDiffs = new HashMap();
+
+			Diff[] diffs = patcher.getDiffs();
+			try {
+				for (int i = 0; i < diffs.length; i++) {
+					Diff diff = diffs[i];
+					IFile tempFile = patcher.existsInTarget(new Path(diff.getLabel(diff)));
+					
+					byte[] bytes = quickPatch(tempFile, patcher, diff);
+					int differencer = Differencer.CHANGE;
+					if (failedHunks.size() != 0) {
+						differencer += Differencer.CONFLICTING;
+					}
+					ResourceNode tempNode = new ResourceNode(tempFile);
+					PatchedFileNode patchedNode = new PatchedFileNode(bytes, tempNode.getType(), tempFile.getProjectRelativePath().toString());
+					MyDiffNode allFile = new MyDiffNode(root, differencer, tempNode, tempNode, patchedNode, diff);
+					//Add individual hunks to each Diff node
+					Hunk[] hunks = diff.getHunks();
+					for (int j = 0; j < hunks.length; j++) {
+						Diff tempDiff = new Diff(diff.fOldPath, diff.fOldDate, diff.fNewPath, diff.fNewDate);
+						tempDiff.add(hunks[j]);
+						bytes = quickPatch(tempFile, patcher, tempDiff);
+						differencer = Differencer.NO_CHANGE;
+						switch (hunks[j].getHunkType()) {
+							case Hunk.ADDED :
+								differencer += Differencer.ADDITION;
+								break;
+
+							case Hunk.CHANGED :
+								differencer += Differencer.CHANGE;
+								break;
+
+							case Hunk.DELETED :
+								differencer += Differencer.DELETION;
+								break;
+						}
+
+						if (failedHunks.size() != 0) {
+							differencer += Differencer.CONFLICTING;
+							String[] hunkContents = createInput(hunks[j]);
+							PatchedFileNode ancestor = new PatchedFileNode(hunkContents[LEFT].getBytes(), hunks[j].fParent.getPath().getFileExtension(), hunks[j].getDescription());
+							patchedNode = new PatchedFileNode(hunkContents[RIGHT].getBytes(), tempNode.getType(), hunks[j].getDescription());
+							MyDiffNode hunkNode = new MyDiffNode(allFile, differencer, ancestor, tempNode, patchedNode, hunks[j]);
+							nodesToDiffs.put(hunks[j], hunkNode);
+						} else {
+							patchedNode = new PatchedFileNode(bytes, tempNode.getType(), hunks[j].getDescription());
+							MyDiffNode hunkNode = new MyDiffNode(allFile, differencer, tempNode, tempNode, patchedNode, hunks[j]);
+							nodesToDiffs.put(hunks[j], hunkNode);
+						}
+					}
+
+				}
+			} catch (CoreException ex) {//ignore
+			}
+
+		}
+
+	}
+	
+	private byte[] quickPatch(IFile tempFile, WorkspacePatcher patcher, Diff diff) throws CoreException {
+			
+			failedHunks = new ArrayList();
+			List result = patcher.apply(diff, tempFile, diff.getType() == Differencer.ADDITION, failedHunks);
+			String patchedResults = patcher.createString(result);
+			byte[] bytes;
+			try {
+				bytes = patchedResults.getBytes(Utilities.getCharset(tempFile));
+			} catch (UnsupportedEncodingException e) {
+				// uses default encoding
+				bytes = patchedResults.getBytes();
+			}
+		
+		return bytes;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.compare.CompareEditorInput#createDiffViewer(org.eclipse.swt.widgets.Composite)
+	 */
+	public Viewer createDiffViewer(Composite parent) {
+		viewer =  new CheckboxDiffTreeViewer(parent, getCompareConfiguration());
+		viewer.setLabelDecorator(new PatcherCompareEditorDecorator());
+		viewer.getTree().setData(CompareUI.COMPARE_VIEWER_TITLE, PatchMessages.PatcherCompareEditorInput_PatchContents);
+		viewer.addCheckStateListener(new ICheckStateListener() {
+			public void checkStateChanged(CheckStateChangedEvent event) {
+				viewer.setSubtreeChecked(event.getElement(),event.getChecked());
+				updateEnablements();
+			}
+		});
+		viewer.setInput(this);
+		return viewer;
+	}
+	
+	private String[] createInput(Hunk hunk) {
+
+		String[] lines= hunk.fLines;
+		StringBuffer left= new StringBuffer();
+		StringBuffer right= new StringBuffer();
+
+		for (int i= 0; i<lines.length; i++) {
+			String line= lines[i];
+			String rest= line.substring(1);
+			switch (line.charAt(0)) {
+				case ' ' :
+					left.append(rest);
+					right.append(rest);
+					break;
+				case '-' :
+					left.append(rest);
+					break;
+				case '+' :
+					right.append(rest);
+					break;
+			}
+		}
+
+		
+		return new String[]{left.toString(),right.toString()};
+	}
+	
+	public void contributeDiffViewerToolbarItems(Action[] actions, boolean workspacePatch){
+		ToolBarManager tbm= CompareViewerPane.getToolBarManager(viewer.getControl().getParent());
+		if (tbm != null) {
+			tbm.removeAll();
+			
+			tbm.add(new Separator("contributed")); //$NON-NLS-1$
+			
+			for (int i = 0; i < actions.length; i++) {
+				//If this is a workspace patch, make sure all actions are enabled
+				if (workspacePatch)
+					actions[i].setEnabled(true);
+				
+				tbm.appendToGroup("contributed", actions[i]); //$NON-NLS-1$
+			}
+			
+			tbm.update(true);
+		}
+	}
+	
+	public CheckboxDiffTreeViewer getViewer() {
+		return viewer;
+	}
+	
+	/**
+	 * Makes sure that at least one hunk is checked off in the tree before
+	 * allowing the patch to be applied.
+	 */
+	/* private */void updateEnablements() {
+		boolean atLeastOneIsEnabled= false;
+		if (viewer!=null) {
+			ITreeContentProvider contentProvider= (ITreeContentProvider) viewer.getContentProvider();
+			Object[] projects= contentProvider.getElements(root);
+			//Iterate through projects
+			for (int j= 0; j<projects.length; j++) {
+				if (!(projects[j] instanceof MyDiffNode)) {
+					DiffNode project = (DiffNode) projects[j];
+					//Iterate through project diffs
+					Object[] diffs= project.getChildren();
+					for (int i= 0; i<diffs.length; i++) {
+						MyDiffNode diff= (MyDiffNode) diffs[i];
+						atLeastOneIsEnabled= updateEnablement(atLeastOneIsEnabled, diff);
+					}
+				} else if (projects[j] instanceof MyDiffNode) {
+					atLeastOneIsEnabled= updateEnablement(atLeastOneIsEnabled, (MyDiffNode) projects[j]);
+				}
+			}
+		}
+
+		previewPatchPage.setPageComplete(atLeastOneIsEnabled);
+	}
+
+	private boolean updateEnablement(boolean oneIsEnabled, MyDiffNode diffNode) {
+		boolean checked= viewer.getChecked(diffNode);
+		Diff diff = diffNode.getDiff();
+		Assert.isNotNull(diff);
+		diff.setEnabled(checked);
+		if (checked) {
+			Object[] hunkItems= diffNode.getChildren();
+			for (int h= 0; h<hunkItems.length; h++) {
+				MyDiffNode hunkNode = (MyDiffNode) hunkItems[h];
+				checked= viewer.getChecked(hunkNode);
+				Hunk hunk= hunkNode.getHunk();
+				Assert.isNotNull(hunk);
+				hunk.setEnabled(checked);
+				if (checked) {
+					//For workspace patch: before setting enabled flag, make sure that the project
+					//that contains this hunk actually exists in the workspace. This is to guard against the 
+					//case of having a new file in a patch that is being applied to a project that
+					//doesn't currently exist.
+					boolean projectExists= true;
+					DiffProject project= (DiffProject)diff.getParent(null);
+					if (project!= null){
+						projectExists=project.getProject().exists();
+					}
+					if (projectExists)
+						oneIsEnabled= true;
+				}
+
+			}
+		}
+	
+		return oneIsEnabled;
+	}
+	
+
+	/**
+	 * Stores a pointer back to the PreviewPatchPage
+	 * @param page
+	 */
+	public void setPreviewPatchPage(PreviewPatchPage2 page) {
+		previewPatchPage = page;
+	}
+}
diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PreviewPatchPage2.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PreviewPatchPage2.java
new file mode 100644
index 0000000..c8bc66a
--- /dev/null
+++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PreviewPatchPage2.java
@@ -0,0 +1,506 @@
+package org.eclipse.compare.internal.patch;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.compare.ITypedElement;
+import org.eclipse.compare.internal.CompareUIPlugin;
+import org.eclipse.compare.internal.ICompareUIConstants;
+import org.eclipse.compare.structuremergeviewer.DiffNode;
+import org.eclipse.compare.structuremergeviewer.Differencer;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.model.BaseWorkbenchContentProvider;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+import org.eclipse.ui.views.navigator.ResourceSorter;
+
+import com.ibm.icu.text.MessageFormat;
+
+
+public class PreviewPatchPage2 extends WizardPage {
+
+	protected final static String PREVIEWPATCHPAGE_NAME= "PreviewPatchPage";  //$NON-NLS-1$
+	private PatchWizard fPatchWizard;
+	private PatcherCompareEditorInput patcherCompareEditorInput = new PatcherCompareEditorInput();
+	
+	private Combo fStripPrefixSegments;
+	private Text fFuzzField;
+	
+	private Action fRetargetSelection;
+	private Action fIgnoreWhiteSpace;
+	private Action fReversePatch;
+	
+	protected boolean pageRecalculate= true;
+	
+	class RetargetPatchDialog extends Dialog {
+
+		protected TreeViewer rpTreeViewer;
+		protected DiffNode rpSelectedNode;
+		protected DiffProject rpSelectedProject;
+		protected IProject rpTargetProject;
+
+		public RetargetPatchDialog(Shell shell, ISelection selection) {
+			super(shell);
+			setShellStyle(getShellStyle()|SWT.RESIZE);
+			if (selection instanceof IStructuredSelection) {
+				rpSelectedNode= (DiffNode) ((IStructuredSelection) selection).getFirstElement();
+			}
+		}
+
+		protected Control createDialogArea(Composite parent) {
+			Composite composite= (Composite) super.createDialogArea(parent);
+
+			initializeDialogUnits(parent);
+
+			getShell().setText(PatchMessages.PreviewPatchPage_RetargetPatch);
+
+			GridLayout layout= new GridLayout();
+			layout.numColumns= 1;
+	        layout.marginHeight= convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
+	        layout.marginWidth= convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);			
+			composite.setLayout(layout);
+			final GridData data= new GridData(SWT.FILL, SWT.FILL, true, true);
+			composite.setLayoutData(data);
+
+			//add controls to composite as necessary
+			Label label= new Label(composite, SWT.LEFT|SWT.WRAP);
+			label.setText(NLS.bind(PatchMessages.PreviewPatchPage_SelectProject, rpSelectedNode.getName()));
+			final GridData data2= new GridData(SWT.FILL, SWT.BEGINNING, true, false);
+			label.setLayoutData(data2);
+
+			rpTreeViewer= new TreeViewer(composite, SWT.BORDER);
+			GridData gd= new GridData(SWT.FILL, SWT.FILL, true, true);
+			gd.widthHint= 0;
+			gd.heightHint= 0;
+			rpTreeViewer.getTree().setLayoutData(gd);
+
+			rpTreeViewer.setContentProvider(new RetargetPatchContentProvider());
+			rpTreeViewer.setLabelProvider(new WorkbenchLabelProvider());
+			rpTreeViewer.setSorter(new ResourceSorter(ResourceSorter.NAME));
+			rpTreeViewer.setInput(ResourcesPlugin.getWorkspace());
+			ITypedElement tempProject = rpSelectedNode.getLeft();
+			if (tempProject instanceof DiffProject){
+				rpSelectedProject = (DiffProject)tempProject;
+				rpTreeViewer.setSelection(new StructuredSelection(rpSelectedProject.getProject()));
+			}
+			
+			setupListeners();
+
+			Dialog.applyDialogFont(composite);
+			
+			return parent;
+		}
+
+		protected void okPressed() {
+			rpSelectedProject.setProject(rpTargetProject);
+			super.okPressed();
+		}
+
+		void setupListeners() {
+			rpTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+				public void selectionChanged(SelectionChangedEvent event) {
+					IStructuredSelection s= (IStructuredSelection) event.getSelection();
+					Object obj= s.getFirstElement();
+					if (obj instanceof IProject)
+						rpTargetProject= (IProject) obj;
+				}
+			});
+
+			rpTreeViewer.addDoubleClickListener(new IDoubleClickListener() {
+				public void doubleClick(DoubleClickEvent event) {
+					ISelection s= event.getSelection();
+					if (s instanceof IStructuredSelection) {
+						Object item= ((IStructuredSelection) s).getFirstElement();
+						if (rpTreeViewer.getExpandedState(item))
+							rpTreeViewer.collapseToLevel(item, 1);
+						else
+							rpTreeViewer.expandToLevel(item, 1);
+					}
+				}
+			});
+
+		}
+
+		protected Point getInitialSize() {
+			final Point size= super.getInitialSize();
+			size.x= convertWidthInCharsToPixels(75);
+			size.y+= convertHeightInCharsToPixels(20);
+			return size;
+		}
+	}
+
+	class RetargetPatchContentProvider extends BaseWorkbenchContentProvider {
+		//Never show closed projects
+		boolean showClosedProjects= false;
+
+		public Object[] getChildren(Object element) {
+			if (element instanceof IWorkspace) {
+				// check if closed projects should be shown
+				IProject[] allProjects= ((IWorkspace) element).getRoot().getProjects();
+				if (showClosedProjects)
+					return allProjects;
+
+				ArrayList accessibleProjects= new ArrayList();
+				for (int i= 0; i<allProjects.length; i++) {
+					if (allProjects[i].isOpen()) {
+						accessibleProjects.add(allProjects[i]);
+					}
+				}
+				return accessibleProjects.toArray();
+			}
+
+			if (element instanceof IProject) {
+				return new Object[0];
+			}
+			return super.getChildren(element);
+		}
+	}
+
+	public PreviewPatchPage2(PatchWizard pw) {
+		super(PREVIEWPATCHPAGE_NAME, PatchMessages.PreviewPatchPage_title, null);
+		
+		fPatchWizard= pw;
+		
+	}
+		
+	public void createControl(Composite parent) {
+
+		Composite composite = new Composite(parent, SWT.NONE);
+		composite.setLayout(new GridLayout());
+		composite.setLayoutData(new GridData(GridData.FILL_BOTH));
+		
+		initializeDialogUnits(parent);
+		
+		buildPatchOptionsGroup(composite);
+		
+		try {
+			patcherCompareEditorInput.run(null);
+		} catch (InterruptedException e) {//ignore
+		} catch (InvocationTargetException e) {//ignore
+		}
+	
+		
+		Control c = patcherCompareEditorInput.createContents(composite);
+		patcherCompareEditorInput.contributeDiffViewerToolbarItems(getContributedActions(), fPatchWizard.getPatcher().isWorkspacePatch());
+		patcherCompareEditorInput.setPreviewPatchPage(this);
+		c.setLayoutData(new GridData(GridData.FILL_BOTH));
+		setControl(composite);
+		
+	}
+	
+	private Action[] getContributedActions() {
+		fRetargetSelection= new Action(PatchMessages.PreviewPatchPage2_RetargetAction, CompareUIPlugin.getImageDescriptor(ICompareUIConstants.RETARGET_PROJECT)) {
+			public void run() {
+				Shell shell = getShell();
+				ISelection selection = patcherCompareEditorInput.getViewer().getSelection();
+				final RetargetPatchDialog dialog= new RetargetPatchDialog(shell, selection);
+				dialog.open();
+				patcherCompareEditorInput.updateInput(fPatchWizard.getPatcher());
+			}
+		};
+		fRetargetSelection.setToolTipText(PatchMessages.PreviewPatchPage2_RetargetTooltip);
+		fRetargetSelection.setEnabled(false);
+		
+		fIgnoreWhiteSpace = new Action(PatchMessages.PreviewPatchPage2_IgnoreWSAction, CompareUIPlugin.getImageDescriptor(ICompareUIConstants.IGNORE_WHITESPACE_ENABLED)){
+			public void run(){
+				fIgnoreWhiteSpace.setChecked(isChecked());
+				if (fPatchWizard.getPatcher().setIgnoreWhitespace(fIgnoreWhiteSpace.isChecked())){
+					fillTree();
+				}
+			}
+		};
+		fIgnoreWhiteSpace.setChecked(false);
+		fIgnoreWhiteSpace.setToolTipText(PatchMessages.PreviewPatchPage2_IgnoreWSTooltip);
+		fIgnoreWhiteSpace.setDisabledImageDescriptor(CompareUIPlugin.getImageDescriptor(ICompareUIConstants.IGNORE_WHITESPACE_DISABLED));
+		
+		fReversePatch = new Action(PatchMessages.PreviewPatchPage_ReversePatch_text, CompareUIPlugin.getImageDescriptor(ICompareUIConstants.REVERSE_PATCH_ENABLED)){
+			public void run(){
+				fReversePatch.setChecked(isChecked());
+				if (fPatchWizard.getPatcher().setReversed(isChecked())){
+					fillTree();
+				}
+			}
+		};
+		fReversePatch.setChecked(false);
+		fReversePatch.setToolTipText(PatchMessages.PreviewPatchPage_ReversePatch_text);
+		
+		return new Action[]{fIgnoreWhiteSpace, fRetargetSelection, fReversePatch};
+	}
+
+	public void setVisible(boolean visible) {
+		super.setVisible(visible);
+		//Need to handle input and rebuild tree only when becoming visible
+		if(visible){
+			fillTree();
+		}
+	}
+	
+	private void fillTree(){
+		//Update prefix count - go through all of the diffs and find the smallest
+		//path segment contained in all diffs.
+		int length= 99;
+		if (fStripPrefixSegments!=null&& pageRecalculate) {
+			length= fPatchWizard.getPatcher().calculatePrefixSegmentCount();
+			if (length!=99) {
+				for (int k= 1; k<length; k++)
+					fStripPrefixSegments.add(Integer.toString(k));
+				pageRecalculate= false;
+			}
+		}
+		
+		patcherCompareEditorInput.updateInput(fPatchWizard.getPatcher());
+		
+	}
+	/*
+	 *	Create the group for setting various patch options
+	 */
+	private void buildPatchOptionsGroup(Composite parent) {
+		
+		GridLayout gl;
+		GridData gd;
+		Label l;
+
+		final WorkspacePatcher patcher= fPatchWizard.getPatcher();
+
+		Group group= new Group(parent, SWT.NONE);
+		group.setText(PatchMessages.PreviewPatchPage_PatchOptions_title);
+		gl= new GridLayout(); gl.numColumns= 4;
+		group.setLayout(gl);
+		group.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL|GridData.GRAB_HORIZONTAL));
+
+		// 1st row
+
+		Composite pair= new Composite(group, SWT.NONE);
+		gl= new GridLayout(); gl.numColumns= 2; gl.marginHeight= gl.marginWidth= 0;
+		pair.setLayout(gl);
+		gd= new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+		pair.setLayoutData(gd);
+
+		l= new Label(pair, SWT.NONE);
+		l.setText(PatchMessages.PreviewPatchPage_IgnoreSegments_text);
+		gd= new GridData(GridData.VERTICAL_ALIGN_CENTER|GridData.HORIZONTAL_ALIGN_BEGINNING|GridData.GRAB_HORIZONTAL);
+		l.setLayoutData(gd);
+
+		fStripPrefixSegments= new Combo(pair, SWT.DROP_DOWN|SWT.READ_ONLY|SWT.SIMPLE);
+		int prefixCnt= patcher.getStripPrefixSegments();
+		String prefix= Integer.toString(prefixCnt);
+		fStripPrefixSegments.add(prefix);
+		fStripPrefixSegments.setText(prefix);
+		gd= new GridData(GridData.VERTICAL_ALIGN_CENTER|GridData.HORIZONTAL_ALIGN_END);
+		fStripPrefixSegments.setLayoutData(gd);
+
+		addSpacer(group);
+
+		// 2nd row
+		pair= new Composite(group, SWT.NONE);
+		gl= new GridLayout(); gl.numColumns= 3; gl.marginHeight= gl.marginWidth= 0;
+		pair.setLayout(gl);
+		gd= new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+		pair.setLayoutData(gd);
+
+		l= new Label(pair, SWT.NONE);
+		l.setText(PatchMessages.PreviewPatchPage_FuzzFactor_text);
+		l.setToolTipText(PatchMessages.PreviewPatchPage_FuzzFactor_tooltip);
+		gd= new GridData(GridData.VERTICAL_ALIGN_CENTER|GridData.HORIZONTAL_ALIGN_BEGINNING|GridData.GRAB_HORIZONTAL);
+		l.setLayoutData(gd);
+
+		fFuzzField= new Text(pair, SWT.BORDER);
+		fFuzzField.setText("2"); //$NON-NLS-1$
+			gd= new GridData(GridData.VERTICAL_ALIGN_CENTER | GridData.HORIZONTAL_ALIGN_END); gd.widthHint= 30;
+		fFuzzField.setLayoutData(gd);
+
+		Button b= new Button(pair, SWT.PUSH);
+		b.setText(PatchMessages.PreviewPatchPage_GuessFuzz_text);
+			b.addSelectionListener(
+				new SelectionAdapter() {
+			public void widgetSelected(SelectionEvent e) {
+				int fuzz= guessFuzzFactor(patcher);
+				if (fuzz>=0)
+					fFuzzField.setText(Integer.toString(fuzz));
+			}
+				}
+			);
+		gd= new GridData(GridData.VERTICAL_ALIGN_CENTER);
+		int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
+		Point minSize = b.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
+		gd.widthHint = Math.max(widthHint, minSize.x);		
+		b.setLayoutData(gd);
+
+		// register listeners
+
+		if (fStripPrefixSegments!=null)
+			fStripPrefixSegments.addSelectionListener(
+				new SelectionAdapter() {
+				public void widgetSelected(SelectionEvent e) {
+					if (patcher.setStripPrefixSegments(getStripPrefixSegments()))
+						patcherCompareEditorInput.updateInput(patcher);
+				}
+				}
+			);
+	
+
+		fFuzzField.addModifyListener(
+			new ModifyListener() {
+			public void modifyText(ModifyEvent e) {
+				if (patcher.setFuzz(getFuzzFactor()))
+					patcherCompareEditorInput.updateInput(patcher);
+			}
+		});
+	}
+	
+	private void addSpacer(Composite parent) {
+		Label label= new Label(parent, SWT.NONE);
+		GridData gd= new GridData(GridData.FILL_HORIZONTAL);
+		gd.widthHint= 10;
+		label.setLayoutData(gd);
+	}
+	
+	public int getFuzzFactor() {
+		int fuzzFactor= 0;
+		if (fFuzzField!=null) {
+			String s= fFuzzField.getText();
+			try {
+				fuzzFactor= Integer.parseInt(s);
+			} catch (NumberFormatException ex) {
+				// silently ignored
+			}
+		}
+		return fuzzFactor;
+	}
+	
+	public int getStripPrefixSegments() {
+		int stripPrefixSegments= 0;
+		if (fStripPrefixSegments!=null) {
+			String s= fStripPrefixSegments.getText();
+			try {
+				stripPrefixSegments= Integer.parseInt(s);
+			} catch (NumberFormatException ex) {
+				// silently ignored
+			}
+		}
+		return stripPrefixSegments;
+	}
+	
+	private int guessFuzzFactor(final WorkspacePatcher patcher) {
+		final int strip= getStripPrefixSegments();
+		final int[] result= new int[1];
+		try {
+			PlatformUI.getWorkbench().getProgressService().run(true, true,
+			//TimeoutContext.run(true, GUESS_TIMEOUT, getControl().getShell(),
+					new IRunnableWithProgress() {
+						public void run(IProgressMonitor monitor) {
+							result[0]= guess(patcher, monitor, strip);
+						}
+				}
+			);
+			return result[0];
+		} catch (InvocationTargetException ex) {
+			// NeedWork
+		} catch (InterruptedException ex) {
+			// NeedWork
+		}
+		return -1;
+	}
+	
+	private int guess(WorkspacePatcher patcher, IProgressMonitor pm, int strip) {
+
+		Diff[] diffs= patcher.getDiffs();
+		if (diffs==null||diffs.length<=0)
+			return -1;
+
+		// now collect files and determine "work"
+		IFile[] files= new IFile[diffs.length];
+		int work= 0;
+		for (int i= 0; i<diffs.length; i++) {
+			Diff diff= diffs[i];
+			if (diff==null)
+				continue;
+			if (diff.getType()!=Differencer.ADDITION) {
+				IPath p= diff.fOldPath;
+				if (strip>0&&strip<p.segmentCount())
+					p= p.removeFirstSegments(strip);
+				IFile file= existsInSelection(p);
+				if (file!=null) {
+					files[i]= file;
+					work+= diff.fHunks.size();
+				}
+			}
+		}
+
+		// do the "work"
+		int[] fuzzRef= new int[1];
+		String format= PatchMessages.PreviewPatchPage_GuessFuzzProgress_format;
+		pm.beginTask(PatchMessages.PreviewPatchPage_GuessFuzzProgress_text, work);
+		try {
+			int fuzz= 0;
+			for (int i= 0; i<diffs.length; i++) {
+				Diff d= diffs[i];
+				IFile file= files[i];
+				if (d!=null&&file!=null) {
+					List lines= patcher.load(file, false);
+					String name= d.getPath().lastSegment();
+					Iterator iter= d.fHunks.iterator();
+					int shift= 0;
+					for (int hcnt= 1; iter.hasNext(); hcnt++) {
+						pm.subTask(MessageFormat.format(format, new String[] {name, Integer.toString(hcnt)}));
+						Hunk h= (Hunk) iter.next();
+						shift= patcher.calculateFuzz(h, lines, shift, pm, fuzzRef);
+						int f= fuzzRef[0];
+						if (f==-1) // cancel
+							return -1;
+						if (f>fuzz)
+							fuzz= f;
+						pm.worked(1);
+					}
+				}
+			}
+			return fuzz;
+		} finally {
+			pm.done();
+		}
+	}
+	
+	private IFile existsInSelection(IPath path) {
+		return fPatchWizard.getPatcher().existsInTarget(path);
+	}
+	
+	
+
+}