View | Details | Raw Unified | Return to bug 71374 | Differences between
and this patch

Collapse All | Expand All

(-)compare/org/eclipse/compare/internal/CompareMessages.java (+39 lines)
Lines 130-135 Link Here
130
	public static String CompareWithOtherResourceDialog_workspaceMainButton;
130
	public static String CompareWithOtherResourceDialog_workspaceMainButton;
131
	public static String CompareWithOtherResourceDialog_workspaceRadioButton;
131
	public static String CompareWithOtherResourceDialog_workspaceRadioButton;
132
132
133
	public static String CreatePatchActionTitle;
134
	public static String WorkspacePatchDialogTitle;
135
	public static String WorkspacePatchDialogDescription;
136
	public static String Save_Patch_As_5;
137
	public static String Save_To_Clipboard_2;
138
	public static String Save_In_File_System_3;
139
	public static String Browse____4;
140
	public static String patch_txt_6;
141
	public static String Save_In_Workspace_7;
142
	public static String Fi_le_name__9;
143
	public static String Context_14;
144
	public static String Standard_15;
145
	public static String Diff_output_format_12;
146
	public static String Advanced_options_19;
147
	public static String Configure_the_options_used_for_the_CVS_diff_command_20;
148
	public static String Unified__format_required_by_Compare_With_Patch_feature__13;
149
	public static String GenerateLocalDiff_title;
150
	public static String GenerateLocalDiff_pageTitle;
151
	public static String GenerateLocalDiff_pageDescription;
152
	public static String GenerateLocalDiff_Specify_the_file_which_contributes_the_changes;
153
	public static String GenerateLocalDiff_overwriteTitle;
154
	public static String GenerateLocalDiff_overwriteMsg;
155
	public static String GenerateLocalDiff_1;
156
	public static String GenerateLocalDiff_2;
157
	public static String GenerateDiffFileWizard_6;
158
	public static String GenerateDiffFileWizard_7;
159
	public static String GenerateDiffFileWizard_8;
160
	public static String GenerateDiffFileWizard_9;
161
	public static String GenerateDiffFileWizard_10;
162
	public static String GenerateDiffFileWizard_0;
163
	public static String GenerateDiffFileWizard_2;
164
	public static String GenerateDiffFileWizard_3;
165
	public static String GenerateDiffFileWizard_4;
166
	public static String GenerateDiffFileWizard_5;
167
	public static String GenerateDiffFileWizard_browseFilesystem;
168
	public static String GenerateDiffFileWizard_FolderExists;
169
	public static String GenerateDiffFileWizard_ProjectClosed;
170
	public static String GenerateDiffFileWizard_13;
171
133
	static {
172
	static {
134
		NLS.initializeMessages(BUNDLE_NAME, CompareMessages.class);
173
		NLS.initializeMessages(BUNDLE_NAME, CompareMessages.class);
135
	}
174
	}
(-)compare/org/eclipse/compare/internal/CompareMessages.properties (+39 lines)
Lines 141-143 Link Here
141
CompareWithOtherResourceDialog_externalFolderRadioButton=External folder
141
CompareWithOtherResourceDialog_externalFolderRadioButton=External folder
142
CompareWithOtherResourceDialog_workspaceMainButton=Browse...
142
CompareWithOtherResourceDialog_workspaceMainButton=Browse...
143
CompareWithOtherResourceDialog_workspaceRadioButton=Workspace
143
CompareWithOtherResourceDialog_workspaceRadioButton=Workspace
144
145
CreatePatchActionTitle=Save Diffs...
146
WorkspacePatchDialogTitle=Set a Patch Location
147
WorkspacePatchDialogDescription=Select a folder in the workspace and enter a name for the patch.
148
Save_To_Clipboard_2=&Clipboard
149
Save_In_File_System_3=Fil&e
150
Browse____4=Br&owse...
151
Save_Patch_As_5=Save Patch As
152
patch_txt_6=patch.txt
153
Save_In_Workspace_7=&Workspace
154
Fi_le_name__9=Fi&le name:
155
Context_14=&Context
156
Standard_15=&Standard
157
Diff_output_format_12=Diff Output Format
158
Advanced_options_19=Advanced Options
159
Configure_the_options_used_for_the_CVS_diff_command_20=Configure the options used for the command.
160
Unified__format_required_by_Compare_With_Patch_feature__13=&Unified (format required by the Apply Patch wizard)
161
GenerateLocalDiff_title=Save Diffs
162
GenerateLocalDiff_pageTitle=Save Diffs into a Patch
163
GenerateLocalDiff_pageDescription=Specify the input and the location for the patch.
164
GenerateLocalDiff_Specify_the_file_which_contributes_the_changes=Select which side of the compare editor is contributing the changes. 
165
GenerateLocalDiff_overwriteTitle=Confirm Overwrite
166
GenerateLocalDiff_overwriteMsg=A file with that name already exists. Overwrite?
167
GenerateLocalDiff_1=Read-only file
168
GenerateLocalDiff_2=The specified file is read-only and cannot be overwritten.
169
GenerateDiffFileWizard_6=&Workspace (Multi-project Apply Patch wizard specific)
170
GenerateDiffFileWizard_7=&Project
171
GenerateDiffFileWizard_8=S&election
172
GenerateDiffFileWizard_9=Save Patch
173
GenerateDiffFileWizard_10=Patch Root
174
GenerateDiffFileWizard_0=Please enter a valid location.
175
GenerateDiffFileWizard_2=Please enter a file name.
176
GenerateDiffFileWizard_3=The specified directory does not exist.
177
GenerateDiffFileWizard_4=Please select a location in the workspace by browsing.
178
GenerateDiffFileWizard_5=Please enter a valid filename.
179
GenerateDiffFileWizard_browseFilesystem=Please select a location in the filesystem by browsing.
180
GenerateDiffFileWizard_FolderExists=The specified path points to an existing folder.
181
GenerateDiffFileWizard_ProjectClosed=The specified path points to a closed project.
182
GenerateDiffFileWizard_13=&Use only file path:
(-)compare/org/eclipse/compare/internal/ICompareUIConstants.java (+2 lines)
Lines 49-52 Link Here
49
	public static final String PREF_VALUE_NEXT = "next"; //$NON-NLS-1$
49
	public static final String PREF_VALUE_NEXT = "next"; //$NON-NLS-1$
50
50
51
	public static final String COMMAND_IGNORE_WHITESPACE = PREFIX + "ignoreWhiteSpace"; //$NON-NLS-1$
51
	public static final String COMMAND_IGNORE_WHITESPACE = PREFIX + "ignoreWhiteSpace"; //$NON-NLS-1$
52
53
	public final String IMG_WIZBAN_DIFF = "wizban/createpatch_wizban.png";   //$NON-NLS-1$
52
}
54
}
(-)compare/org/eclipse/compare/internal/MergeSourceViewer.java (+2 lines)
Lines 99-104 Link Here
99
	public static final String SAVE_ID= "save"; //$NON-NLS-1$
99
	public static final String SAVE_ID= "save"; //$NON-NLS-1$
100
	public static final String FIND_ID= "find"; //$NON-NLS-1$
100
	public static final String FIND_ID= "find"; //$NON-NLS-1$
101
	public static final String GOTO_LINE_ID= "gotoLine"; //$NON-NLS-1$
101
	public static final String GOTO_LINE_ID= "gotoLine"; //$NON-NLS-1$
102
	public static final String CREATE_PATCH_ID= "createPatch"; //$NON-NLS-1$
102
103
103
	class TextOperationAction extends MergeViewerAction {
104
	class TextOperationAction extends MergeViewerAction {
104
		
105
		
Lines 789-794 Link Here
789
		addMenu(menu, SELECT_ALL_ID);
790
		addMenu(menu, SELECT_ALL_ID);
790
791
791
		menu.add(new Separator("edit")); //$NON-NLS-1$
792
		menu.add(new Separator("edit")); //$NON-NLS-1$
793
		addMenu(menu, CREATE_PATCH_ID);
792
		menu.add(new Separator("find")); //$NON-NLS-1$
794
		menu.add(new Separator("find")); //$NON-NLS-1$
793
		addMenu(menu, FIND_ID);
795
		addMenu(menu, FIND_ID);
794
		
796
		
(-)compare/org/eclipse/compare/internal/merge/DocumentMerger.java (-1 / +5 lines)
Lines 1343-1347 Link Here
1343
		}
1343
		}
1344
		return null;
1344
		return null;
1345
	}
1345
	}
1346
	
1346
1347
	public ArrayList getAllDiffs() {
1348
		return fAllDiffs;
1349
	}
1350
1347
}
1351
}
(-)compare/org/eclipse/compare/contentmergeviewer/TextMergeViewer.java (-1 / +12 lines)
Lines 43-48 Link Here
43
import org.eclipse.compare.internal.CompareMessages;
43
import org.eclipse.compare.internal.CompareMessages;
44
import org.eclipse.compare.internal.ComparePreferencePage;
44
import org.eclipse.compare.internal.ComparePreferencePage;
45
import org.eclipse.compare.internal.CompareUIPlugin;
45
import org.eclipse.compare.internal.CompareUIPlugin;
46
import org.eclipse.compare.internal.CreatePatchAction;
46
import org.eclipse.compare.internal.DocumentManager;
47
import org.eclipse.compare.internal.DocumentManager;
47
import org.eclipse.compare.internal.ICompareContextIds;
48
import org.eclipse.compare.internal.ICompareContextIds;
48
import org.eclipse.compare.internal.ICompareUIConstants;
49
import org.eclipse.compare.internal.ICompareUIConstants;
Lines 1908-1915 Link Here
1908
				}
1909
				}
1909
			}
1910
			}
1910
		);
1911
		);
1912
1913
		contributeCreatePatchAction(fAncestor, false);
1914
		contributeCreatePatchAction(fLeft, false);
1915
		contributeCreatePatchAction(fRight, true);
1911
	}
1916
	}
1912
	
1917
1913
	private void hsynchViewport(final TextViewer tv1, final TextViewer tv2, final TextViewer tv3) {
1918
	private void hsynchViewport(final TextViewer tv1, final TextViewer tv2, final TextViewer tv3) {
1914
		final StyledText st1= tv1.getTextWidget();
1919
		final StyledText st1= tv1.getTextWidget();
1915
		final StyledText st2= tv2.getTextWidget();
1920
		final StyledText st2= tv2.getTextWidget();
Lines 2333-2338 Link Here
2333
		viewer.addAction(MergeSourceViewer.GOTO_LINE_ID, action);
2338
		viewer.addAction(MergeSourceViewer.GOTO_LINE_ID, action);
2334
	}
2339
	}
2335
2340
2341
	private void contributeCreatePatchAction(MergeSourceViewer viewer,
2342
			boolean rightToLeft) {
2343
		IAction action = new CreatePatchAction(this, rightToLeft);
2344
		viewer.addAction(MergeSourceViewer.CREATE_PATCH_ID, action);
2345
	}
2346
2336
	private void connectGlobalActions(final MergeSourceViewer part) {
2347
	private void connectGlobalActions(final MergeSourceViewer part) {
2337
		if (fHandlerService != null) {
2348
		if (fHandlerService != null) {
2338
			if (part != null)
2349
			if (part != null)
(-)compare/org/eclipse/compare/internal/SaveDiffFileWizard.java (+1383 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.compare.internal;
12
13
import java.io.File;
14
import java.io.IOException;
15
import java.net.MalformedURLException;
16
import java.net.URL;
17
import java.util.ArrayList;
18
import java.util.Iterator;
19
import java.util.List;
20
21
import org.eclipse.compare.internal.merge.DocumentMerger;
22
import org.eclipse.core.resources.IContainer;
23
import org.eclipse.core.resources.IFile;
24
import org.eclipse.core.resources.IProject;
25
import org.eclipse.core.resources.IResource;
26
import org.eclipse.core.resources.IWorkspace;
27
import org.eclipse.core.resources.IWorkspaceRoot;
28
import org.eclipse.core.resources.ResourcesPlugin;
29
import org.eclipse.core.runtime.IPath;
30
import org.eclipse.core.runtime.IStatus;
31
import org.eclipse.core.runtime.Path;
32
import org.eclipse.jface.dialogs.Dialog;
33
import org.eclipse.jface.dialogs.IDialogConstants;
34
import org.eclipse.jface.dialogs.IDialogSettings;
35
import org.eclipse.jface.dialogs.MessageDialog;
36
import org.eclipse.jface.dialogs.TitleAreaDialog;
37
import org.eclipse.jface.resource.ImageDescriptor;
38
import org.eclipse.jface.text.IDocument;
39
import org.eclipse.jface.viewers.DoubleClickEvent;
40
import org.eclipse.jface.viewers.IDoubleClickListener;
41
import org.eclipse.jface.viewers.ISelection;
42
import org.eclipse.jface.viewers.ISelectionChangedListener;
43
import org.eclipse.jface.viewers.IStructuredSelection;
44
import org.eclipse.jface.viewers.SelectionChangedEvent;
45
import org.eclipse.jface.viewers.StructuredSelection;
46
import org.eclipse.jface.viewers.TreeViewer;
47
import org.eclipse.jface.wizard.Wizard;
48
import org.eclipse.jface.wizard.WizardDialog;
49
import org.eclipse.jface.wizard.WizardPage;
50
import org.eclipse.swt.SWT;
51
import org.eclipse.swt.events.ModifyEvent;
52
import org.eclipse.swt.events.ModifyListener;
53
import org.eclipse.swt.events.SelectionAdapter;
54
import org.eclipse.swt.events.SelectionEvent;
55
import org.eclipse.swt.graphics.Image;
56
import org.eclipse.swt.graphics.Point;
57
import org.eclipse.swt.layout.GridData;
58
import org.eclipse.swt.layout.GridLayout;
59
import org.eclipse.swt.widgets.Button;
60
import org.eclipse.swt.widgets.Composite;
61
import org.eclipse.swt.widgets.Control;
62
import org.eclipse.swt.widgets.Event;
63
import org.eclipse.swt.widgets.FileDialog;
64
import org.eclipse.swt.widgets.Group;
65
import org.eclipse.swt.widgets.Label;
66
import org.eclipse.swt.widgets.Listener;
67
import org.eclipse.swt.widgets.Shell;
68
import org.eclipse.swt.widgets.Text;
69
import org.eclipse.ui.model.BaseWorkbenchContentProvider;
70
import org.eclipse.ui.model.WorkbenchLabelProvider;
71
import org.eclipse.ui.views.navigator.ResourceComparator;
72
73
/**
74
 * A wizard for creating a patch file by running the CVS diff command.
75
 */
76
public class SaveDiffFileWizard extends Wizard {
77
78
	private final static int INITIAL_WIDTH = 300;
79
	private final static int INITIAL_HEIGHT = 350;
80
81
	public static void run(DocumentMerger merger, IDocument leftDoc,
82
			IDocument rightDoc, String leftLabel, String rightLabel,
83
			String leftPath, String rightPath, Shell shell, boolean rightToLeft) {
84
		final String title = CompareMessages.GenerateLocalDiff_title;
85
		final SaveDiffFileWizard wizard = new SaveDiffFileWizard(merger,
86
				leftDoc, rightDoc, leftLabel, rightLabel, leftPath, rightPath,
87
				rightToLeft);
88
		wizard.setWindowTitle(title);
89
		WizardDialog dialog = new WizardDialog(shell, wizard);
90
		dialog.setMinimumPageSize(INITIAL_WIDTH, INITIAL_HEIGHT);
91
		dialog.open();
92
	}
93
94
	private class DirectionSelectionPage extends WizardPage {
95
96
		public final static int LEFT_OPTION = 1;
97
		public final static int RIGHT_OPTION = 2;
98
99
		private Button fromLeftOption;
100
		private Button fromRightOption;
101
		private RadioButtonGroup fromRadioGroup = new RadioButtonGroup();
102
103
		protected DirectionSelectionPage(String pageName, String title,
104
				ImageDescriptor titleImage) {
105
			super(pageName, title, titleImage);
106
		}
107
108
		public void createControl(Composite parent) {
109
			Composite composite = new Composite(parent, SWT.NULL);
110
			GridLayout layout = new GridLayout();
111
			layout.marginLeft = 5;
112
			layout.marginTop = 9;
113
			composite.setLayout(layout);
114
			composite.setLayoutData(new GridData());
115
			setControl(composite);
116
117
			fromLeftOption = new Button(composite, SWT.RADIO);
118
			fromLeftOption.setText(leftLabel);
119
120
			fromRightOption = new Button(composite, SWT.RADIO);
121
			fromRightOption.setText(rightLabel);
122
			GridData data = new GridData();
123
			data.verticalIndent = 6;
124
			fromRightOption.setLayoutData(data);
125
126
			fromRadioGroup.add(LEFT_OPTION, fromLeftOption);
127
			fromRadioGroup.add(RIGHT_OPTION, fromRightOption);
128
129
			Dialog.applyDialogFont(parent);
130
131
			// Add listeners
132
			fromLeftOption.addSelectionListener(new SelectionAdapter() {
133
				public void widgetSelected(SelectionEvent e) {
134
					fromRadioGroup.setSelection(LEFT_OPTION, true);
135
					targetFileEdited = false;
136
				}
137
			});
138
139
			fromRightOption.addSelectionListener(new SelectionAdapter() {
140
				public void widgetSelected(SelectionEvent e) {
141
					fromRadioGroup.setSelection(RIGHT_OPTION, true);
142
					targetFileEdited = false;
143
				}
144
			});
145
146
			fromRadioGroup.setSelection(rightToLeft ? RIGHT_OPTION
147
					: LEFT_OPTION, true);
148
		}
149
150
		public boolean isRightToLeft() {
151
			return fromRadioGroup.getSelected() != LEFT_OPTION;
152
		}
153
154
	}
155
156
	/**
157
	 * Page to select a patch file. Overriding validatePage was necessary to
158
	 * allow entering a file name that already exists.
159
	 */
160
	private class LocationPage extends WizardPage {
161
162
		public final static int CLIPBOARD = 1;
163
		public final static int FILESYSTEM = 2;
164
		public final static int WORKSPACE = 3;
165
166
		private Button cpRadio;
167
168
		private Button fsRadio;
169
		protected Text fsPathText;
170
		private Button fsBrowseButton;
171
		private boolean fsBrowsed = false;
172
173
		private Button wsRadio;
174
		protected Text wsPathText;
175
		private Button wsBrowseButton;
176
		private boolean wsBrowsed = false;
177
178
		protected boolean pageValid;
179
		protected IContainer wsSelectedContainer;
180
		protected IPath[] foldersToCreate;
181
		protected int selectedLocation;
182
183
		/**
184
		 * The default values store used to initialize the selections.
185
		 */
186
		private final DefaultValuesStore store;
187
188
		class LocationPageContentProvider extends BaseWorkbenchContentProvider {
189
			boolean showClosedProjects = false;
190
191
			public Object[] getChildren(Object element) {
192
				if (element instanceof IWorkspace) {
193
					// Check if closed projects should be shown
194
					IProject[] allProjects = ((IWorkspace) element).getRoot()
195
							.getProjects();
196
					if (showClosedProjects)
197
						return allProjects;
198
199
					ArrayList accessibleProjects = new ArrayList();
200
					for (int i = 0; i < allProjects.length; i++) {
201
						if (allProjects[i].isOpen()) {
202
							accessibleProjects.add(allProjects[i]);
203
						}
204
					}
205
					return accessibleProjects.toArray();
206
				}
207
				return super.getChildren(element);
208
			}
209
		}
210
211
		class WorkspaceDialog extends TitleAreaDialog {
212
213
			protected TreeViewer wsTreeViewer;
214
			protected Text wsFilenameText;
215
			protected Image dlgTitleImage;
216
217
			private boolean modified = false;
218
219
			public WorkspaceDialog(Shell shell) {
220
				super(shell);
221
			}
222
223
			protected Control createContents(Composite parent) {
224
				Control control = super.createContents(parent);
225
				setTitle(CompareMessages.WorkspacePatchDialogTitle);
226
				setMessage(CompareMessages.WorkspacePatchDialogDescription);
227
				dlgTitleImage = CompareUIPlugin.getImageDescriptor(
228
						ICompareUIConstants.IMG_WIZBAN_DIFF).createImage();
229
				setTitleImage(dlgTitleImage);
230
				return control;
231
			}
232
233
			protected Control createDialogArea(Composite parent) {
234
				Composite parentComposite = (Composite) super
235
						.createDialogArea(parent);
236
237
				// Create a composite with standard margins and spacing
238
				Composite composite = new Composite(parentComposite, SWT.NONE);
239
				GridLayout layout = new GridLayout();
240
				layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
241
				layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
242
				layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
243
				layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
244
				composite.setLayout(layout);
245
				composite.setLayoutData(new GridData(GridData.FILL_BOTH));
246
				composite.setFont(parentComposite.getFont());
247
248
				getShell().setText(CompareMessages.GenerateDiffFileWizard_9);
249
250
				wsTreeViewer = new TreeViewer(composite, SWT.BORDER);
251
				final GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
252
				gd.widthHint = 550;
253
				gd.heightHint = 250;
254
				wsTreeViewer.getTree().setLayoutData(gd);
255
256
				wsTreeViewer
257
						.setContentProvider(new LocationPageContentProvider());
258
				wsTreeViewer.setComparator(new ResourceComparator(
259
						ResourceComparator.NAME));
260
				wsTreeViewer.setLabelProvider(new WorkbenchLabelProvider());
261
				wsTreeViewer.setInput(ResourcesPlugin.getWorkspace());
262
263
				// Open to whatever is selected in the workspace field
264
				IPath existingWorkspacePath = new Path(wsPathText.getText());
265
				if (existingWorkspacePath != null) {
266
					// Ensure that this workspace path is valid
267
					IResource selectedResource = ResourcesPlugin.getWorkspace()
268
							.getRoot().findMember(existingWorkspacePath);
269
					if (selectedResource != null) {
270
						wsTreeViewer.expandToLevel(selectedResource, 0);
271
						wsTreeViewer.setSelection(new StructuredSelection(
272
								selectedResource));
273
					}
274
				}
275
276
				final Composite group = new Composite(composite, SWT.NONE);
277
				layout = new GridLayout(2, false);
278
				layout.marginWidth = 0;
279
				group.setLayout(layout);
280
				group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
281
						false));
282
283
				final Label label = new Label(group, SWT.NONE);
284
				label.setLayoutData(new GridData());
285
				label.setText(CompareMessages.Fi_le_name__9);
286
287
				wsFilenameText = new Text(group, SWT.BORDER);
288
				wsFilenameText.setLayoutData(new GridData(SWT.FILL, SWT.TOP,
289
						true, false));
290
291
				setupListeners();
292
293
				return parent;
294
			}
295
296
			protected Button createButton(Composite parent, int id,
297
					String label, boolean defaultButton) {
298
				Button button = super.createButton(parent, id, label,
299
						defaultButton);
300
				if (id == IDialogConstants.OK_ID) {
301
					button.setEnabled(false);
302
				}
303
				return button;
304
			}
305
306
			private void validateDialog() {
307
				String fileName = wsFilenameText.getText();
308
309
				if (fileName.equals("")) { //$NON-NLS-1$
310
					if (modified) {
311
						setErrorMessage(CompareMessages.GenerateDiffFileWizard_2);
312
						getButton(IDialogConstants.OK_ID).setEnabled(false);
313
						return;
314
					}
315
					setErrorMessage(null);
316
					getButton(IDialogConstants.OK_ID).setEnabled(false);
317
					return;
318
				}
319
320
				// Make sure that the filename is valid
321
				if (!(ResourcesPlugin.getWorkspace().validateName(fileName,
322
						IResource.FILE)).isOK()
323
						&& modified) {
324
					setErrorMessage(CompareMessages.GenerateDiffFileWizard_5);
325
					getButton(IDialogConstants.OK_ID).setEnabled(false);
326
					return;
327
				}
328
329
				// Make sure that a container has been selected
330
				if (getSelectedContainer() == null) {
331
					setErrorMessage(CompareMessages.GenerateDiffFileWizard_0);
332
					getButton(IDialogConstants.OK_ID).setEnabled(false);
333
					return;
334
				}
335
				IWorkspace workspace = ResourcesPlugin.getWorkspace();
336
				IPath fullPath = wsSelectedContainer.getFullPath().append(
337
						fileName);
338
				if (workspace.getRoot().getFolder(fullPath).exists()) {
339
					setErrorMessage(CompareMessages.GenerateDiffFileWizard_FolderExists);
340
					getButton(IDialogConstants.OK_ID).setEnabled(false);
341
					return;
342
343
				}
344
345
				setErrorMessage(null);
346
				getButton(IDialogConstants.OK_ID).setEnabled(true);
347
			}
348
349
			protected void okPressed() {
350
				IFile file = wsSelectedContainer.getFile(new Path(
351
						wsFilenameText.getText()));
352
				if (file != null)
353
					wsPathText.setText(file.getFullPath().toString());
354
355
				validatePage();
356
				super.okPressed();
357
			}
358
359
			private IContainer getSelectedContainer() {
360
				Object obj = ((IStructuredSelection) wsTreeViewer
361
						.getSelection()).getFirstElement();
362
				if (obj instanceof IContainer) {
363
					wsSelectedContainer = (IContainer) obj;
364
				} else if (obj instanceof IFile) {
365
					wsSelectedContainer = ((IFile) obj).getParent();
366
				}
367
				return wsSelectedContainer;
368
			}
369
370
			protected void cancelPressed() {
371
				validatePage();
372
				super.cancelPressed();
373
			}
374
375
			public boolean close() {
376
				if (dlgTitleImage != null)
377
					dlgTitleImage.dispose();
378
				return super.close();
379
			}
380
381
			void setupListeners() {
382
				wsTreeViewer
383
						.addSelectionChangedListener(new ISelectionChangedListener() {
384
							public void selectionChanged(
385
									SelectionChangedEvent event) {
386
								IStructuredSelection s = (IStructuredSelection) event
387
										.getSelection();
388
								Object obj = s.getFirstElement();
389
								if (obj instanceof IContainer)
390
									wsSelectedContainer = (IContainer) obj;
391
								else if (obj instanceof IFile) {
392
									IFile tempFile = (IFile) obj;
393
									wsSelectedContainer = tempFile.getParent();
394
									wsFilenameText.setText(tempFile.getName());
395
								}
396
								validateDialog();
397
							}
398
						});
399
400
				wsTreeViewer.addDoubleClickListener(new IDoubleClickListener() {
401
					public void doubleClick(DoubleClickEvent event) {
402
						ISelection s = event.getSelection();
403
						if (s instanceof IStructuredSelection) {
404
							Object item = ((IStructuredSelection) s)
405
									.getFirstElement();
406
							if (wsTreeViewer.getExpandedState(item))
407
								wsTreeViewer.collapseToLevel(item, 1);
408
							else
409
								wsTreeViewer.expandToLevel(item, 1);
410
						}
411
						validateDialog();
412
					}
413
				});
414
415
				wsFilenameText.addModifyListener(new ModifyListener() {
416
					public void modifyText(ModifyEvent e) {
417
						modified = true;
418
						validateDialog();
419
					}
420
				});
421
			}
422
		}
423
424
		LocationPage(String pageName, String title, ImageDescriptor image,
425
				DefaultValuesStore store) {
426
			super(pageName, title, image);
427
			setPageComplete(false);
428
			this.store = store;
429
		}
430
431
		protected boolean validatePage() {
432
			switch (selectedLocation) {
433
			case WORKSPACE:
434
				pageValid = validateWorkspaceLocation();
435
				break;
436
			case FILESYSTEM:
437
				pageValid = validateFilesystemLocation();
438
				break;
439
			case CLIPBOARD:
440
				pageValid = true;
441
				break;
442
			}
443
444
			// Avoid draw flicker by clearing error message if all is valid.
445
			if (pageValid) {
446
				setMessage(null);
447
				setErrorMessage(null);
448
			}
449
			setPageComplete(pageValid);
450
			return pageValid;
451
		}
452
453
		private boolean validateFilesystemLocation() {
454
			// Conditions for the file system location to be valid:
455
			// - the path must be valid and non-empty
456
			// - the path must be absolute
457
			// - the specified file must be of type file
458
			// - the parent must exist (new folders can be created via browse)
459
			final String pathString = fsPathText.getText().trim();
460
			if (pathString.length() == 0
461
					|| !new Path("").isValidPath(pathString)) { //$NON-NLS-1$
462
				if (fsBrowsed)
463
					setErrorMessage(CompareMessages.GenerateDiffFileWizard_0);
464
				else
465
					setErrorMessage(CompareMessages.GenerateDiffFileWizard_browseFilesystem);
466
				return false;
467
			}
468
469
			final File file = new File(pathString);
470
			if (!file.isAbsolute()) {
471
				setErrorMessage(CompareMessages.GenerateDiffFileWizard_0);
472
				return false;
473
			}
474
475
			if (file.isDirectory()) {
476
				setErrorMessage(CompareMessages.GenerateDiffFileWizard_2);
477
				return false;
478
			}
479
480
			if (pathString.endsWith("/") || pathString.endsWith("\\")) { //$NON-NLS-1$//$NON-NLS-2$
481
				setErrorMessage(CompareMessages.GenerateDiffFileWizard_3);
482
				return false;
483
			}
484
485
			final File parent = file.getParentFile();
486
			if (!(parent.exists() && parent.isDirectory())) {
487
				setErrorMessage(CompareMessages.GenerateDiffFileWizard_3);
488
				return false;
489
			}
490
			return true;
491
		}
492
493
		private boolean validateWorkspaceLocation() {
494
			// Conditions for the file system location to be valid:
495
			// - a parent must be selected in the workspace tree view
496
			// - the resource name must be valid
497
			if (wsPathText.getText().equals("")) { //$NON-NLS-1$
498
				// Make sure that the field actually has a filename in it
499
				// amd make sure that the user has had a chance to browse
500
				if (selectedLocation == WORKSPACE && wsBrowsed)
501
					setErrorMessage(CompareMessages.GenerateDiffFileWizard_5);
502
				else
503
					setErrorMessage(CompareMessages.GenerateDiffFileWizard_4);
504
				return false;
505
			}
506
507
			// Make sure that all the segments but the last one (i.e. project +
508
			// all folders) exist - file doesn't have to exist. It may have
509
			// happened that some folder refactoring has been done since this
510
			// path was last saved.
511
			//
512
			// The path will always be in format project/{folders}*/file - this
513
			// is controlled by the workspace location dialog and by
514
			// validatePath method when path has been entered manually.
515
			IPath pathToWorkspaceFile = new Path(wsPathText.getText());
516
			IStatus status = ResourcesPlugin.getWorkspace().validatePath(
517
					wsPathText.getText(), IResource.FILE);
518
			if (status.isOK()) {
519
				// Trim file name from path
520
				IPath containerPath = pathToWorkspaceFile.removeLastSegments(1);
521
				IResource container = ResourcesPlugin.getWorkspace().getRoot()
522
						.findMember(containerPath);
523
				if (container == null) {
524
					if (selectedLocation == WORKSPACE)
525
						setErrorMessage(CompareMessages.GenerateDiffFileWizard_4);
526
					return false;
527
				} else if (!container.isAccessible()) {
528
					if (selectedLocation == WORKSPACE)
529
						setErrorMessage(CompareMessages.GenerateDiffFileWizard_ProjectClosed);
530
					return false;
531
				} else {
532
					if (ResourcesPlugin.getWorkspace().getRoot().getFolder(
533
							pathToWorkspaceFile).exists()) {
534
						setErrorMessage(CompareMessages.GenerateDiffFileWizard_FolderExists);
535
						return false;
536
					}
537
				}
538
			} else {
539
				setErrorMessage(status.getMessage());
540
				return false;
541
			}
542
543
			return true;
544
		}
545
546
		/**
547
		 * Answers a full path to a file system file or <code>null</code> if the
548
		 * user selected to save the patch in the clipboard.
549
		 */
550
		public File getFile() {
551
			if (pageValid && selectedLocation == FILESYSTEM) {
552
				return new File(fsPathText.getText().trim());
553
			}
554
			if (pageValid && selectedLocation == WORKSPACE) {
555
				final String filename = wsPathText.getText().trim();
556
				IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
557
				final IFile file = root.getFile(new Path(filename));
558
				return file.getLocation().toFile();
559
			}
560
			return null;
561
		}
562
563
		/**
564
		 * Answers the workspace string entered in the dialog or
565
		 * <code>null</code> if the user selected to save the patch in the
566
		 * clipboard or file system.
567
		 * 
568
		 * @return workspace location or null
569
		 */
570
		public String getWorkspaceLocation() {
571
			if (pageValid && selectedLocation == WORKSPACE) {
572
				final String filename = wsPathText.getText().trim();
573
				return filename;
574
			}
575
			return null;
576
		}
577
578
		/**
579
		 * Get the selected workspace resource if the patch is to be saved in
580
		 * the workspace, or null otherwise.
581
		 * 
582
		 * @return selected resource or null
583
		 */
584
		public IResource getResource() {
585
			if (pageValid && selectedLocation == WORKSPACE) {
586
				IPath pathToWorkspaceFile = new Path(wsPathText.getText()
587
						.trim());
588
				// Trim file name from path
589
				IPath containerPath = pathToWorkspaceFile.removeLastSegments(1);
590
				return ResourcesPlugin.getWorkspace().getRoot().findMember(
591
						containerPath);
592
			}
593
			return null;
594
		}
595
596
		public void createControl(Composite parent) {
597
			final Composite composite = new Composite(parent, SWT.NULL);
598
			composite.setLayout(new GridLayout());
599
			setControl(composite);
600
			initializeDialogUnits(composite);
601
602
			setupLocationControls(composite);
603
604
			initializeDefaultValues();
605
606
			Dialog.applyDialogFont(parent);
607
608
			validatePage();
609
610
			updateEnablements();
611
			setupListeners();
612
		}
613
614
		private void setupLocationControls(final Composite parent) {
615
			final Composite composite = new Composite(parent, SWT.NULL);
616
			GridLayout gridLayout = new GridLayout();
617
			gridLayout.numColumns = 3;
618
			composite.setLayout(gridLayout);
619
			composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
620
621
			// Clipboard
622
			GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
623
			gd.horizontalSpan = 3;
624
			cpRadio = new Button(composite, SWT.RADIO);
625
			cpRadio.setText(CompareMessages.Save_To_Clipboard_2);
626
			cpRadio.setLayoutData(gd);
627
628
			// Filesystem
629
			fsRadio = new Button(composite, SWT.RADIO);
630
			fsRadio.setText(CompareMessages.Save_In_File_System_3);
631
632
			fsPathText = new Text(composite, SWT.BORDER);
633
			gd = new GridData(GridData.FILL_HORIZONTAL);
634
			fsPathText.setLayoutData(gd);
635
636
			fsBrowseButton = new Button(composite, SWT.PUSH);
637
			fsBrowseButton.setText(CompareMessages.Browse____4);
638
			GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
639
			int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
640
			Point minSize = fsBrowseButton.computeSize(SWT.DEFAULT,
641
					SWT.DEFAULT, true);
642
			data.widthHint = Math.max(widthHint, minSize.x);
643
			fsBrowseButton.setLayoutData(data);
644
645
			// Workspace
646
			wsRadio = new Button(composite, SWT.RADIO);
647
			wsRadio.setText(CompareMessages.Save_In_Workspace_7);
648
649
			wsPathText = new Text(composite, SWT.BORDER);
650
			gd = new GridData(GridData.FILL_HORIZONTAL);
651
			wsPathText.setLayoutData(gd);
652
653
			wsBrowseButton = new Button(composite, SWT.PUSH);
654
			wsBrowseButton.setText(CompareMessages.Browse____4);
655
			data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
656
			widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
657
			minSize = fsBrowseButton
658
					.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
659
			data.widthHint = Math.max(widthHint, minSize.x);
660
			wsBrowseButton.setLayoutData(data);
661
662
			((GridData) cpRadio.getLayoutData()).heightHint = minSize.y;
663
		}
664
665
		private void initializeDefaultValues() {
666
			selectedLocation = store.getLocationSelection();
667
668
			updateRadioButtons();
669
670
			// We need to ensure that we have a valid workspace path - user
671
			// could have altered workspace since last time this was saved
672
			wsPathText.setText(store.getWorkspacePath());
673
			if (!validateWorkspaceLocation()) {
674
				wsPathText.setText(""); //$NON-NLS-1$
675
				// Don't open wizard with an error - change to clipboard
676
				if (selectedLocation == WORKSPACE) {
677
					// Clear the error message caused by the workspace not
678
					// having any workspace path entered
679
					setErrorMessage(null);
680
					selectedLocation = CLIPBOARD;
681
					updateRadioButtons();
682
				}
683
			}
684
			// Do the same thing for the filesystem field
685
			fsPathText.setText(store.getFilesystemPath());
686
			if (!validateFilesystemLocation()) {
687
				fsPathText.setText(""); //$NON-NLS-1$
688
				if (selectedLocation == FILESYSTEM) {
689
					setErrorMessage(null);
690
					selectedLocation = CLIPBOARD;
691
					updateRadioButtons();
692
				}
693
			}
694
695
		}
696
697
		private void updateRadioButtons() {
698
			cpRadio.setSelection(selectedLocation == CLIPBOARD);
699
			fsRadio.setSelection(selectedLocation == FILESYSTEM);
700
			wsRadio.setSelection(selectedLocation == WORKSPACE);
701
		}
702
703
		private void setupListeners() {
704
			cpRadio.addListener(SWT.Selection, new Listener() {
705
				public void handleEvent(Event event) {
706
					selectedLocation = CLIPBOARD;
707
					validatePage();
708
					updateEnablements();
709
				}
710
			});
711
			fsRadio.addListener(SWT.Selection, new Listener() {
712
				public void handleEvent(Event event) {
713
					selectedLocation = FILESYSTEM;
714
					validatePage();
715
					updateEnablements();
716
				}
717
			});
718
719
			wsRadio.addListener(SWT.Selection, new Listener() {
720
				public void handleEvent(Event event) {
721
					selectedLocation = WORKSPACE;
722
					validatePage();
723
					updateEnablements();
724
				}
725
			});
726
727
			ModifyListener pathTextModifyListener = new ModifyListener() {
728
				public void modifyText(ModifyEvent e) {
729
					validatePage();
730
				}
731
			};
732
			fsPathText.addModifyListener(pathTextModifyListener);
733
			wsPathText.addModifyListener(pathTextModifyListener);
734
735
			fsBrowseButton.addListener(SWT.Selection, new Listener() {
736
				public void handleEvent(Event event) {
737
					final FileDialog dialog = new FileDialog(getShell(),
738
							SWT.PRIMARY_MODAL | SWT.SAVE);
739
					if (pageValid) {
740
						final File file = new File(fsPathText.getText());
741
						dialog.setFilterPath(file.getParent());
742
					}
743
					dialog.setText(CompareMessages.Save_Patch_As_5);
744
					dialog.setFileName(CompareMessages.patch_txt_6);
745
					final String path = dialog.open();
746
					fsBrowsed = true;
747
					if (path != null) {
748
						fsPathText.setText(new Path(path).toOSString());
749
					}
750
					validatePage();
751
				}
752
			});
753
754
			wsBrowseButton.addListener(SWT.Selection, new Listener() {
755
				public void handleEvent(Event event) {
756
					final WorkspaceDialog dialog = new WorkspaceDialog(
757
							getShell());
758
					wsBrowsed = true;
759
					dialog.open();
760
					validatePage();
761
				}
762
			});
763
764
		}
765
766
		public void updateEnablements() {
767
			// Enable and disable controls based on the selected radio button.
768
			fsBrowseButton.setEnabled(selectedLocation == FILESYSTEM);
769
			fsPathText.setEnabled(selectedLocation == FILESYSTEM);
770
			if (selectedLocation == FILESYSTEM)
771
				fsBrowsed = false;
772
			wsPathText.setEnabled(selectedLocation == WORKSPACE);
773
			wsBrowseButton.setEnabled(selectedLocation == WORKSPACE);
774
			if (selectedLocation == WORKSPACE)
775
				wsBrowsed = false;
776
		}
777
778
		public int getSelectedLocation() {
779
			return selectedLocation;
780
		}
781
782
	}
783
784
	private class OptionsPage extends WizardPage {
785
786
		public final static int FORMAT_UNIFIED = 1;
787
		public final static int FORMAT_CONTEXT = 2;
788
		public final static int FORMAT_STANDARD = 3;
789
790
		public final static int ROOT_WORKSPACE = 1;
791
		public final static int ROOT_PROJECT = 2;
792
		public final static int ROOT_SELECTION = 3;
793
		public final static int ROOT_CUSTOM = 4;
794
795
		private boolean initialized = false;
796
797
		private Button unifiedDiffOption;
798
		private Button contextDiffOption;
799
		private Button regularDiffOption;
800
801
		private Button unified_workspaceRelativeOption;
802
		private Button unified_projectRelativeOption;
803
		private Button unified_selectionRelativeOption;
804
		private Button unified_customRelativeOption;
805
		private Text unified_customRelativeText;
806
807
		private final RadioButtonGroup diffTypeRadioGroup = new RadioButtonGroup();
808
		private final RadioButtonGroup unifiedRadioGroup = new RadioButtonGroup();
809
810
		private final DefaultValuesStore store;
811
812
		protected OptionsPage(String pageName, String title,
813
				ImageDescriptor titleImage, DefaultValuesStore store) {
814
			super(pageName, title, titleImage);
815
			this.store = store;
816
		}
817
818
		public void setVisible(boolean visible) {
819
			super.setVisible(visible);
820
			if (!initialized && visible) {
821
				File toFile = null;
822
				if (directionSelectionPage.isRightToLeft()) {
823
					toFile = new File(leftPath);
824
				} else {
825
					toFile = new File(rightPath);
826
				}
827
				String toPath = toFile.getPath();
828
				unified_customRelativeText.setText(toPath);
829
				targetFileEdited = true;
830
			}
831
		}
832
833
		public void createControl(Composite parent) {
834
			Composite composite = new Composite(parent, SWT.NULL);
835
			GridLayout layout = new GridLayout();
836
			composite.setLayout(layout);
837
			composite.setLayoutData(new GridData());
838
			setControl(composite);
839
840
			Group diffTypeGroup = new Group(composite, SWT.NONE);
841
			layout = new GridLayout();
842
			layout.marginHeight = 0;
843
			diffTypeGroup.setLayout(layout);
844
			GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL
845
					| GridData.GRAB_HORIZONTAL);
846
			diffTypeGroup.setLayoutData(data);
847
			diffTypeGroup.setText(CompareMessages.Diff_output_format_12);
848
849
			unifiedDiffOption = new Button(diffTypeGroup, SWT.RADIO);
850
			unifiedDiffOption
851
					.setText(CompareMessages.Unified__format_required_by_Compare_With_Patch_feature__13);
852
853
			contextDiffOption = new Button(diffTypeGroup, SWT.RADIO);
854
			contextDiffOption.setText(CompareMessages.Context_14);
855
			regularDiffOption = new Button(diffTypeGroup, SWT.RADIO);
856
			regularDiffOption.setText(CompareMessages.Standard_15);
857
858
			diffTypeRadioGroup.add(FORMAT_UNIFIED, unifiedDiffOption);
859
			diffTypeRadioGroup.add(FORMAT_CONTEXT, contextDiffOption);
860
			diffTypeRadioGroup.add(FORMAT_STANDARD, regularDiffOption);
861
862
			// Unified Format Options
863
			Group unifiedGroup = new Group(composite, SWT.None);
864
			layout = new GridLayout();
865
			layout.numColumns = 2;
866
			unifiedGroup.setLayout(layout);
867
			data = new GridData(GridData.HORIZONTAL_ALIGN_FILL
868
					| GridData.GRAB_HORIZONTAL);
869
			unifiedGroup.setLayoutData(data);
870
			unifiedGroup.setText(CompareMessages.GenerateDiffFileWizard_10);
871
872
			unified_workspaceRelativeOption = new Button(unifiedGroup,
873
					SWT.RADIO);
874
			unified_workspaceRelativeOption
875
					.setText(CompareMessages.GenerateDiffFileWizard_6);
876
			unified_workspaceRelativeOption.setLayoutData(new GridData(
877
					SWT.BEGINNING, SWT.CENTER, false, false, 2, 1));
878
879
			unified_projectRelativeOption = new Button(unifiedGroup, SWT.RADIO);
880
			unified_projectRelativeOption
881
					.setText(CompareMessages.GenerateDiffFileWizard_7);
882
			unified_projectRelativeOption.setLayoutData(new GridData(
883
					SWT.BEGINNING, SWT.CENTER, false, false, 2, 1));
884
885
			unified_selectionRelativeOption = new Button(unifiedGroup,
886
					SWT.RADIO);
887
			unified_selectionRelativeOption
888
					.setText(CompareMessages.GenerateDiffFileWizard_8);
889
			unified_selectionRelativeOption.setLayoutData(new GridData(
890
					SWT.BEGINNING, SWT.CENTER, false, false, 2, 1));
891
892
			unified_customRelativeOption = new Button(unifiedGroup, SWT.RADIO);
893
			unified_customRelativeOption
894
					.setText(CompareMessages.GenerateDiffFileWizard_13);
895
			unified_customRelativeOption.setSelection(true);
896
			unified_customRelativeOption.setLayoutData(new GridData(
897
					SWT.BEGINNING, SWT.CENTER, false, false, 1, 1));
898
899
			unified_customRelativeText = new Text(unifiedGroup, SWT.BORDER);
900
			unified_customRelativeText.setLayoutData(new GridData(SWT.FILL,
901
					SWT.CENTER, true, false, 1, 1));
902
903
			unifiedRadioGroup.add(ROOT_WORKSPACE,
904
					unified_workspaceRelativeOption);
905
			unifiedRadioGroup.add(ROOT_PROJECT, unified_projectRelativeOption);
906
			unifiedRadioGroup.add(ROOT_SELECTION,
907
					unified_selectionRelativeOption);
908
			unifiedRadioGroup.add(ROOT_CUSTOM, unified_customRelativeOption);
909
910
			Dialog.applyDialogFont(parent);
911
912
			initializeDefaultValues();
913
914
			// add listeners
915
			unifiedDiffOption.addSelectionListener(new SelectionAdapter() {
916
				public void widgetSelected(SelectionEvent e) {
917
					diffTypeRadioGroup.setSelection(FORMAT_UNIFIED, false);
918
				}
919
			});
920
921
			contextDiffOption.addSelectionListener(new SelectionAdapter() {
922
				public void widgetSelected(SelectionEvent e) {
923
					diffTypeRadioGroup.setSelection(FORMAT_CONTEXT, false);
924
				}
925
			});
926
927
			regularDiffOption.addSelectionListener(new SelectionAdapter() {
928
				public void widgetSelected(SelectionEvent e) {
929
					diffTypeRadioGroup.setSelection(FORMAT_STANDARD, false);
930
				}
931
			});
932
933
			unified_workspaceRelativeOption
934
					.addSelectionListener(new SelectionAdapter() {
935
						public void widgetSelected(SelectionEvent e) {
936
							unifiedRadioGroup.setSelection(ROOT_WORKSPACE,
937
									false);
938
						}
939
					});
940
941
			unified_projectRelativeOption
942
					.addSelectionListener(new SelectionAdapter() {
943
						public void widgetSelected(SelectionEvent e) {
944
							unifiedRadioGroup.setSelection(ROOT_PROJECT, false);
945
						}
946
					});
947
948
			unified_selectionRelativeOption
949
					.addSelectionListener(new SelectionAdapter() {
950
						public void widgetSelected(SelectionEvent e) {
951
							unifiedRadioGroup.setSelection(ROOT_SELECTION,
952
									false);
953
						}
954
					});
955
956
			unified_selectionRelativeOption
957
					.addSelectionListener(new SelectionAdapter() {
958
						public void widgetSelected(SelectionEvent e) {
959
							unifiedRadioGroup.setSelection(ROOT_CUSTOM, false);
960
						}
961
					});
962
963
			// calculatePatchRoot();
964
			updateEnablements();
965
966
			// update selection
967
			diffTypeRadioGroup.selectEnabledOnly();
968
			unifiedRadioGroup.selectEnabledOnly();
969
		}
970
971
		public int getFormatSelection() {
972
			return diffTypeRadioGroup.getSelected();
973
		}
974
975
		public int getRootSelection() {
976
			return unifiedRadioGroup.getSelected();
977
		}
978
979
		public String getPath() {
980
			return unified_customRelativeText.getText();
981
		}
982
983
		private void initializeDefaultValues() {
984
			// Radio buttons for format
985
			diffTypeRadioGroup.setSelection(store.getFormatSelection(), true);
986
			// Radio buttons for patch root
987
			unifiedRadioGroup.setSelection(store.getRootSelection(), true);
988
		}
989
990
		protected void updateEnablements() {
991
			diffTypeRadioGroup.setEnablement(false, new int[] { FORMAT_CONTEXT,
992
					FORMAT_STANDARD }, FORMAT_UNIFIED);
993
			unifiedRadioGroup.setEnablement(false, new int[] { ROOT_WORKSPACE,
994
					ROOT_PROJECT, ROOT_SELECTION }, ROOT_CUSTOM);
995
		}
996
997
	}
998
999
	/**
1000
	 * Class to retrieve and store the default selected values.
1001
	 */
1002
	private final class DefaultValuesStore {
1003
1004
		private static final String PREF_LAST_SELECTION = "org.eclipse.compare.internal.GenerateDiffFileWizard.PatchFileSelectionPage.lastselection"; //$NON-NLS-1$
1005
		private static final String PREF_LAST_FS_PATH = "org.eclipse.compare.internal.GenerateDiffFileWizard.PatchFileSelectionPage.filesystem.path"; //$NON-NLS-1$
1006
		private static final String PREF_LAST_WS_PATH = "org.eclipse.compare.internal.GenerateDiffFileWizard.PatchFileSelectionPage.workspace.path"; //$NON-NLS-1$
1007
		private static final String PREF_LAST_AO_FORMAT = "org.eclipse.compare.internal.GenerateDiffFileWizard.OptionsPage.diff.format"; //$NON-NLS-1$
1008
		private static final String PREF_LAST_AO_ROOT = "org.eclipse.compare.internal.GenerateDiffFileWizard.OptionsPage.patch.root"; //$NON-NLS-1$
1009
1010
		private final IDialogSettings dialogSettings;
1011
1012
		public DefaultValuesStore() {
1013
			dialogSettings = CompareUIPlugin.getDefault().getDialogSettings();
1014
		}
1015
1016
		public int getLocationSelection() {
1017
			int value = LocationPage.CLIPBOARD;
1018
			try {
1019
				value = dialogSettings.getInt(PREF_LAST_SELECTION);
1020
			} catch (NumberFormatException e) {
1021
				// Ignore
1022
			}
1023
1024
			switch (value) {
1025
			case LocationPage.FILESYSTEM:
1026
			case LocationPage.WORKSPACE:
1027
			case LocationPage.CLIPBOARD:
1028
				return value;
1029
			default:
1030
				return LocationPage.CLIPBOARD;
1031
			}
1032
		}
1033
1034
		public String getFilesystemPath() {
1035
			final String path = dialogSettings.get(PREF_LAST_FS_PATH);
1036
			return path != null ? path : ""; //$NON-NLS-1$
1037
		}
1038
1039
		public String getWorkspacePath() {
1040
			final String path = dialogSettings.get(PREF_LAST_WS_PATH);
1041
			return path != null ? path : ""; //$NON-NLS-1$
1042
		}
1043
1044
		public int getFormatSelection() {
1045
			int value = OptionsPage.FORMAT_UNIFIED;
1046
			try {
1047
				value = dialogSettings.getInt(PREF_LAST_AO_FORMAT);
1048
			} catch (NumberFormatException e) {
1049
				// Ignore
1050
			}
1051
1052
			switch (value) {
1053
			case OptionsPage.FORMAT_UNIFIED:
1054
			case OptionsPage.FORMAT_CONTEXT:
1055
			case OptionsPage.FORMAT_STANDARD:
1056
				return value;
1057
			default:
1058
				return OptionsPage.FORMAT_UNIFIED;
1059
			}
1060
		}
1061
1062
		public int getRootSelection() {
1063
			int value = OptionsPage.ROOT_WORKSPACE;
1064
			try {
1065
				value = dialogSettings.getInt(PREF_LAST_AO_ROOT);
1066
			} catch (NumberFormatException e) {
1067
				// Ignore
1068
			}
1069
1070
			switch (value) {
1071
			case OptionsPage.ROOT_WORKSPACE:
1072
			case OptionsPage.ROOT_PROJECT:
1073
			case OptionsPage.ROOT_SELECTION:
1074
				return value;
1075
			default:
1076
				return OptionsPage.ROOT_WORKSPACE;
1077
			}
1078
		}
1079
1080
		public void storeLocationSelection(int defaultSelection) {
1081
			dialogSettings.put(PREF_LAST_SELECTION, defaultSelection);
1082
		}
1083
1084
		public void storeFilesystemPath(String path) {
1085
			dialogSettings.put(PREF_LAST_FS_PATH, path);
1086
		}
1087
1088
		public void storeWorkspacePath(String path) {
1089
			dialogSettings.put(PREF_LAST_WS_PATH, path);
1090
		}
1091
1092
		public void storeOutputFormat(int selection) {
1093
			dialogSettings.put(PREF_LAST_AO_FORMAT, selection);
1094
		}
1095
1096
		public void storePatchRoot(int selection) {
1097
			dialogSettings.put(PREF_LAST_AO_ROOT, selection);
1098
		}
1099
	}
1100
1101
	private DirectionSelectionPage directionSelectionPage;
1102
	private LocationPage locationPage;
1103
	private OptionsPage optionsPage;
1104
1105
	// protected IResource[] resources;
1106
	private final DefaultValuesStore defaultValuesStore;
1107
	// private final IWorkbenchPart part;
1108
1109
	private DocumentMerger merger;
1110
	private IDocument leftDoc;
1111
	private IDocument rightDoc;
1112
	private String leftLabel;
1113
	private String rightLabel;
1114
	private String leftPath;
1115
	private String rightPath;
1116
	private boolean rightToLeft;
1117
1118
	private boolean targetFileEdited = false;
1119
1120
	public SaveDiffFileWizard(DocumentMerger merger, IDocument leftDoc,
1121
			IDocument rightDoc, String leftLabel, String rightLabel,
1122
			String leftPath, String rightPath, boolean rightToLeft) {
1123
		super();
1124
		setWindowTitle(CompareMessages.GenerateLocalDiff_title);
1125
		initializeDefaultPageImageDescriptor();
1126
		defaultValuesStore = new DefaultValuesStore();
1127
		this.merger = merger;
1128
		this.leftDoc = leftDoc;
1129
		this.rightDoc = rightDoc;
1130
		this.leftLabel = leftLabel;
1131
		this.rightLabel = rightLabel;
1132
		this.leftPath = leftPath;
1133
		this.rightPath = rightPath;
1134
		this.rightToLeft = rightToLeft;
1135
	}
1136
1137
	public void addPages() {
1138
		String pageTitle = CompareMessages.GenerateLocalDiff_pageTitle;
1139
		String pageDescription = CompareMessages.GenerateLocalDiff_Specify_the_file_which_contributes_the_changes;
1140
		directionSelectionPage = new DirectionSelectionPage(
1141
				pageTitle,
1142
				pageTitle,
1143
				CompareUIPlugin
1144
						.getImageDescriptor(ICompareUIConstants.IMG_WIZBAN_DIFF));
1145
		directionSelectionPage.setDescription(pageDescription);
1146
		addPage(directionSelectionPage);
1147
1148
		pageTitle = CompareMessages.GenerateLocalDiff_pageTitle;
1149
		pageDescription = CompareMessages.GenerateLocalDiff_pageDescription;
1150
		locationPage = new LocationPage(pageTitle, pageTitle, CompareUIPlugin
1151
				.getImageDescriptor(ICompareUIConstants.IMG_WIZBAN_DIFF),
1152
				defaultValuesStore);
1153
		locationPage.setDescription(pageDescription);
1154
		addPage(locationPage);
1155
1156
		pageTitle = CompareMessages.Advanced_options_19;
1157
		pageDescription = CompareMessages.Configure_the_options_used_for_the_CVS_diff_command_20;
1158
		optionsPage = new OptionsPage(pageTitle, pageTitle, CompareUIPlugin
1159
				.getImageDescriptor(ICompareUIConstants.IMG_WIZBAN_DIFF),
1160
				defaultValuesStore);
1161
		optionsPage.setDescription(pageDescription);
1162
		addPage(optionsPage);
1163
	}
1164
1165
	/**
1166
	 * Declares the wizard banner iamge descriptor
1167
	 */
1168
	protected void initializeDefaultPageImageDescriptor() {
1169
		final String iconPath = "icons/full/"; //$NON-NLS-1$
1170
		try {
1171
			final URL installURL = CompareUIPlugin.getDefault().getBundle()
1172
					.getEntry("/"); //$NON-NLS-1$
1173
			final URL url = new URL(installURL, iconPath
1174
					+ "wizards/newconnect_wiz.gif"); //$NON-NLS-1$
1175
			ImageDescriptor desc = ImageDescriptor.createFromURL(url);
1176
			setDefaultPageImageDescriptor(desc);
1177
		} catch (MalformedURLException e) {
1178
			// Should not happen. Ignore.
1179
		}
1180
	}
1181
1182
	/*
1183
	 * (Non-javadoc) Method declared on IWizard.
1184
	 */
1185
	public boolean needsProgressMonitor() {
1186
		return true;
1187
	}
1188
1189
	public boolean performFinish() {
1190
		final int location = locationPage.getSelectedLocation();
1191
		final File file = location != LocationPage.CLIPBOARD ? locationPage
1192
				.getFile() : null;
1193
1194
		if (!(file == null || validateFile(file))) {
1195
			return false;
1196
		}
1197
1198
		// Create the patch
1199
		generateDiffFile(file);
1200
1201
		// Refresh workspace if necessary and save default selection.
1202
		switch (location) {
1203
		case LocationPage.WORKSPACE:
1204
			final String workspaceResource = locationPage
1205
					.getWorkspaceLocation();
1206
			if (workspaceResource != null) {
1207
				defaultValuesStore
1208
						.storeLocationSelection(LocationPage.WORKSPACE);
1209
				defaultValuesStore.storeWorkspacePath(workspaceResource);
1210
			} else {
1211
				// Problem with workspace location, choose clipboard next time
1212
				defaultValuesStore
1213
						.storeLocationSelection(LocationPage.CLIPBOARD);
1214
			}
1215
			break;
1216
		case LocationPage.FILESYSTEM:
1217
			defaultValuesStore.storeFilesystemPath(file.getPath());
1218
			defaultValuesStore.storeLocationSelection(LocationPage.FILESYSTEM);
1219
			break;
1220
		case LocationPage.CLIPBOARD:
1221
			defaultValuesStore.storeLocationSelection(LocationPage.CLIPBOARD);
1222
			break;
1223
		default:
1224
			return false;
1225
		}
1226
1227
		defaultValuesStore.storeOutputFormat(optionsPage.getFormatSelection());
1228
		defaultValuesStore.storePatchRoot(optionsPage.getRootSelection());
1229
1230
		return true;
1231
	}
1232
1233
	private void generateDiffFile(File file) {
1234
		String toPath = null;
1235
		if (targetFileEdited) {
1236
			toPath = optionsPage.getPath();
1237
		} else {
1238
			File toFile = null;
1239
			if (directionSelectionPage.isRightToLeft()) {
1240
				toFile = new File(leftPath);
1241
			} else {
1242
				toFile = new File(rightPath);
1243
			}
1244
			toPath = toFile.getPath();
1245
		}
1246
1247
		UnifiedDiffFormatter formatter = new UnifiedDiffFormatter(merger,
1248
				leftDoc, rightDoc, toPath, directionSelectionPage
1249
						.isRightToLeft());
1250
		try {
1251
			if (file == null) {
1252
				formatter.generateDiff(getShell().getDisplay());
1253
			} else {
1254
				formatter.generateDiff(file);
1255
			}
1256
		} catch (IOException e) {
1257
			throw new RuntimeException(e);
1258
		}
1259
	}
1260
1261
	public boolean validateFile(File file) {
1262
		if (file == null)
1263
			return false;
1264
1265
		// Consider file valid if it doesn't exist for now.
1266
		if (!file.exists())
1267
			return true;
1268
1269
		// The file exists.
1270
		if (!file.canWrite()) {
1271
			final String title = CompareMessages.GenerateLocalDiff_1;
1272
			final String msg = CompareMessages.GenerateLocalDiff_2;
1273
			final MessageDialog dialog = new MessageDialog(getShell(), title,
1274
					null, msg, MessageDialog.ERROR,
1275
					new String[] { IDialogConstants.OK_LABEL }, 0);
1276
			dialog.open();
1277
			return false;
1278
		}
1279
1280
		final String title = CompareMessages.GenerateLocalDiff_overwriteTitle;
1281
		final String msg = CompareMessages.GenerateLocalDiff_overwriteMsg;
1282
		final MessageDialog dialog = new MessageDialog(getShell(), title, null,
1283
				msg, MessageDialog.QUESTION, new String[] {
1284
						IDialogConstants.YES_LABEL,
1285
						IDialogConstants.CANCEL_LABEL }, 0);
1286
		dialog.open();
1287
		if (dialog.getReturnCode() != 0) {
1288
			return false;
1289
		}
1290
		return true;
1291
	}
1292
1293
	/**
1294
	 * The class maintain proper selection of radio button within the group:
1295
	 * <ul>
1296
	 * <li>Only one button can be selected at the time.</li>
1297
	 * <li>Disabled button can't be selected unless all buttons in the group are
1298
	 * disabled.</li>
1299
	 * </ul>
1300
	 */
1301
	private class RadioButtonGroup {
1302
1303
		private List buttons = new ArrayList(3);
1304
1305
		private int selected = 0;
1306
1307
		public void add(int buttonCode, Button button) {
1308
			if (button != null && (button.getStyle() & SWT.RADIO) != 0) {
1309
				if (button.getSelection() && !buttons.isEmpty()) {
1310
					deselectAll();
1311
					selected = buttonCode - 1;
1312
				}
1313
				buttons.add(buttonCode - 1, button);
1314
			}
1315
		}
1316
1317
		public int getSelected() {
1318
			return selected + 1;
1319
		}
1320
1321
		public int setSelection(int buttonCode, boolean selectEnabledOnly) {
1322
			deselectAll();
1323
1324
			((Button) buttons.get(buttonCode - 1)).setSelection(true);
1325
			selected = buttonCode - 1;
1326
			if (selectEnabledOnly)
1327
				selected = selectEnabledOnly() - 1;
1328
			return getSelected();
1329
		}
1330
1331
		public int selectEnabledOnly() {
1332
			deselectAll();
1333
			Button selectedButton = (Button) buttons.get(selected);
1334
			if (!selectedButton.isEnabled()) {
1335
				// If the button is disabled, set selection to an enabled one
1336
				for (Iterator iterator = buttons.iterator(); iterator.hasNext();) {
1337
					Button b = (Button) iterator.next();
1338
					if (b.isEnabled()) {
1339
						b.setSelection(true);
1340
						selected = buttons.indexOf(b);
1341
						return selected + 1;
1342
					}
1343
				}
1344
				// If none found, reset the initial selection
1345
				selectedButton.setSelection(true);
1346
			} else {
1347
				// Because selection has been cleared, set it again
1348
				selectedButton.setSelection(true);
1349
			}
1350
			// Return selected button's code so the value can be stored
1351
			return getSelected();
1352
		}
1353
1354
		public void setEnablement(boolean enabled, int[] buttonsToChange,
1355
				int defaultSelection) {
1356
			// Enable (or disable) given buttons
1357
			for (int i = 0; i < buttonsToChange.length; i++) {
1358
				((Button) this.buttons.get(buttonsToChange[i] - 1))
1359
						.setEnabled(enabled);
1360
			}
1361
			// Check whether the selected button is enabled
1362
			if (!((Button) this.buttons.get(selected)).isEnabled()) {
1363
				if (defaultSelection != -1)
1364
					// Set the default selection and check if it's enabled
1365
					setSelection(defaultSelection, true);
1366
				else
1367
					// No default selection is given, select any enabled button
1368
					selectEnabledOnly();
1369
			}
1370
		}
1371
1372
		public void setEnablement(boolean enabled, int[] buttonsToChange) {
1373
			// Value -1 means that no default selection is given
1374
			setEnablement(enabled, buttonsToChange, -1);
1375
		}
1376
1377
		private void deselectAll() {
1378
			for (Iterator iterator = buttons.iterator(); iterator.hasNext();)
1379
				((Button) iterator.next()).setSelection(false);
1380
		}
1381
	}
1382
1383
}
(-)compare/org/eclipse/compare/internal/CreatePatchAction.java (+121 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.compare.internal;
12
13
import java.lang.reflect.Field;
14
15
import org.eclipse.compare.CompareConfiguration;
16
import org.eclipse.compare.contentmergeviewer.ContentMergeViewer;
17
import org.eclipse.compare.contentmergeviewer.TextMergeViewer;
18
import org.eclipse.compare.internal.merge.DocumentMerger;
19
import org.eclipse.jface.action.Action;
20
import org.eclipse.jface.text.IDocument;
21
import org.eclipse.ui.IEditorInput;
22
import org.eclipse.ui.part.FileEditorInput;
23
24
public class CreatePatchAction extends Action {
25
26
	private TextMergeViewer viewer;
27
	private boolean rightToLeft;
28
29
	public CreatePatchAction(TextMergeViewer viewer, boolean rightToLeft) {
30
		super(CompareMessages.CreatePatchActionTitle);
31
		this.viewer = viewer;
32
		this.rightToLeft = rightToLeft;
33
	}
34
35
	public void run() {
36
		SaveDiffFileWizard.run(getMerger(), getDocument(true),
37
				getDocument(false), getLabel(true), getLabel(false),
38
				getPath(true), getPath(false), viewer.getControl().getShell(),
39
				rightToLeft);
40
	}
41
42
	private String getPath(boolean left) {
43
		try {
44
			Field ciField = null;
45
			if (left) {
46
				ciField = TextMergeViewer.class
47
						.getDeclaredField("fLeftContributor"); //$NON-NLS-1$
48
			} else {
49
				ciField = TextMergeViewer.class
50
						.getDeclaredField("fRightContributor"); //$NON-NLS-1$
51
			}
52
			ciField.setAccessible(true);
53
			Object ciObj = ciField.get(viewer);
54
			Class clazz = ciObj.getClass();
55
			Field field = clazz.getDeclaredField("fDocumentKey"); //$NON-NLS-1$
56
			field.setAccessible(true);
57
			IEditorInput editorInput = (IEditorInput) field.get(ciObj);
58
			if (editorInput instanceof FileEditorInput) {
59
				FileEditorInput fei = (FileEditorInput) editorInput;
60
				String path = fei.getFile().getProjectRelativePath().toString();
61
				return path;
62
			}
63
		} catch (Exception e) {
64
			e.printStackTrace();
65
		}
66
		return ""; //$NON-NLS-1$
67
	}
68
69
	private String getLabel(boolean left) {
70
		try {
71
			Field field = ContentMergeViewer.class
72
					.getDeclaredField("fCompareConfiguration"); //$NON-NLS-1$
73
			field.setAccessible(true);
74
			CompareConfiguration cc = (CompareConfiguration) field.get(viewer);
75
			if (left) {
76
				field = CompareConfiguration.class
77
						.getDeclaredField("fLeftLabel"); //$NON-NLS-1$
78
			} else {
79
				field = CompareConfiguration.class
80
						.getDeclaredField("fRightLabel"); //$NON-NLS-1$
81
			}
82
			field.setAccessible(true);
83
			return (String) field.get(cc);
84
		} catch (Exception e) {
85
			e.printStackTrace();
86
		}
87
		return null;
88
	}
89
90
	public DocumentMerger getMerger() {
91
		try {
92
			Field field = TextMergeViewer.class.getDeclaredField("fMerger"); //$NON-NLS-1$
93
			field.setAccessible(true);
94
			return (DocumentMerger) field.get(viewer);
95
		} catch (Exception e) {
96
			e.printStackTrace();
97
		}
98
		return null;
99
	}
100
101
	private IDocument getDocument(boolean left) {
102
		try {
103
			Field field = null;
104
			if (left) {
105
				field = TextMergeViewer.class.getDeclaredField("fLeft"); //$NON-NLS-1$
106
			} else {
107
				field = TextMergeViewer.class.getDeclaredField("fRight"); //$NON-NLS-1$
108
			}
109
			field.setAccessible(true);
110
			MergeSourceViewer msv = (MergeSourceViewer) field.get(viewer);
111
			field = MergeSourceViewer.class
112
					.getDeclaredField("fRememberedDocument"); //$NON-NLS-1$
113
			field.setAccessible(true);
114
			return (IDocument) field.get(msv);
115
		} catch (Exception e) {
116
			e.printStackTrace();
117
		}
118
		return null;
119
	}
120
121
}
(-)compare/org/eclipse/compare/internal/UnifiedDiffFormatter.java (+303 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Krzysztof Poglodzinski (intuicje@gmail.com) - initial API and implementation
10
 *     Mariusz Tanski (mariusztanski@gmail.com) - initial API and implementation
11
 *     Kacper Zdanowicz (kacper.zdanowicz@gmail.com) - initial API and implementation
12
 *     IBM Corportation - initial API and implementation
13
 *******************************************************************************/
14
package org.eclipse.compare.internal;
15
16
import java.io.ByteArrayOutputStream;
17
import java.io.File;
18
import java.io.FileOutputStream;
19
import java.io.IOException;
20
import java.io.PrintStream;
21
import java.text.SimpleDateFormat;
22
import java.util.ArrayList;
23
import java.util.Arrays;
24
import java.util.Calendar;
25
import java.util.Date;
26
import java.util.Locale;
27
28
import org.eclipse.compare.internal.merge.DocumentMerger;
29
import org.eclipse.compare.internal.merge.DocumentMerger.Diff;
30
import org.eclipse.compare.rangedifferencer.RangeDifference;
31
import org.eclipse.jface.text.BadLocationException;
32
import org.eclipse.jface.text.IDocument;
33
import org.eclipse.swt.dnd.Clipboard;
34
import org.eclipse.swt.dnd.TextTransfer;
35
import org.eclipse.swt.dnd.Transfer;
36
import org.eclipse.swt.widgets.Display;
37
38
public class UnifiedDiffFormatter {
39
40
	public static final char RIGHT_CONTRIBUTOR = 'R';
41
	public static final char LEFT_CONTRIBUTOR = 'L';
42
43
	public final static int FORMAT_UNIFIED = 1;
44
	public final static int FORMAT_CONTEXT = 2;
45
	public final static int FORMAT_STANDARD = 3;
46
47
	public static final String INDEX_MARKER = "Index: "; //$NON-NLS-1$
48
	public static final String DELIMITER = "==================================================================="; //$NON-NLS-1$
49
	public static final String OLD_FILE_PREFIX = "--- "; //$NON-NLS-1$
50
	public static final String NEW_FILE_PREFIX = "+++ "; //$NON-NLS-1$	
51
	public static final String OLD_LINE_PREFIX = "-"; //$NON-NLS-1$
52
	public static final String NEW_LINE_PREFIX = "+"; //$NON-NLS-1$
53
	public static final String CONTEXT_LINE_PREFIX = " "; //$NON-NLS-1$
54
55
	private DocumentMerger merger;
56
	private IDocument leftDoc;
57
	private IDocument rightDoc;
58
	private String resourcePath;
59
	private boolean rightToLeft;
60
61
	public UnifiedDiffFormatter(DocumentMerger merger, IDocument leftDoc,
62
			IDocument rightDoc, String resourcePath, boolean rightToLeft) {
63
		this.merger = merger;
64
		this.leftDoc = leftDoc;
65
		this.rightDoc = rightDoc;
66
		this.resourcePath = resourcePath;
67
		this.rightToLeft = rightToLeft;
68
	}
69
70
	public void generateDiff(Display dis) throws IOException {
71
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
72
		PrintStream ps = new PrintStream(bos);
73
74
		createDiff(ps);
75
		ps.close();
76
77
		TextTransfer plainTextTransfer = TextTransfer.getInstance();
78
		Clipboard clipboard = new Clipboard(dis);
79
		clipboard.setContents(new String[] { bos.toString() },
80
				new Transfer[] { plainTextTransfer });
81
		clipboard.dispose();
82
83
		bos.close();
84
	}
85
86
	public void generateDiff(File file) throws IOException {
87
		FileOutputStream fos = null;
88
		PrintStream ps = null;
89
		try {
90
			fos = new FileOutputStream(file);
91
			try {
92
				ps = new PrintStream(fos);
93
				createDiff(ps);
94
				if (ps.checkError()) {
95
					throw new IOException("Error while writing patch file: " //$NON-NLS-1$
96
							+ file);
97
				}
98
			} finally {
99
				if (ps != null) {
100
					ps.close();
101
				}
102
			}
103
		} finally {
104
			if (fos != null) {
105
				fos.close();
106
			}
107
		}
108
	}
109
110
	public void createDiff(PrintStream output) {
111
		ArrayList allDiffs = merger.getAllDiffs();
112
		// If the first block isn't the only one, or first block is different
113
		if (allDiffs.size() > 1 || isPartDifferent(allDiffs, 0)) {
114
			output.println(INDEX_MARKER + resourcePath);
115
			output.println(DELIMITER);
116
117
			SimpleDateFormat format = new SimpleDateFormat(
118
					"dd MMM yyyy hh:mm:ss", Locale.US); //$NON-NLS-1$
119
			Date oldDate = Calendar.getInstance(Locale.US).getTime();
120
			Date newDate = Calendar.getInstance(Locale.US).getTime();
121
			output.println(OLD_FILE_PREFIX + resourcePath + '\t'
122
					+ format.format(oldDate) + " -0000"); //$NON-NLS-1$
123
			output.println(NEW_FILE_PREFIX + resourcePath + '\t'
124
					+ format.format(newDate) + " -0000"); //$NON-NLS-1$
125
126
			boolean firstHunk = true;
127
			Hunk currentHunk = null;
128
129
			int currentLineNumberOld = 0;
130
			int currentLineNumberNew = 0;
131
132
			for (int partNumber = 0; partNumber < allDiffs.size(); partNumber++) {
133
134
				ArrayList oldPart = getPart(partNumber, 'R');
135
				ArrayList newPart = getPart(partNumber, 'L');
136
137
				if (isPartDifferent(allDiffs, partNumber)) {
138
					// This part has some changes
139
					if (firstHunk) {
140
						// Hunk will start with changed block
141
						currentHunk = new Hunk(0, 0);
142
						firstHunk = false;
143
					}
144
					if (partNumber == (allDiffs.size() - 1)) {
145
						// If it is the last part
146
						currentHunk.addPartRangeToOld(oldPart, 0, oldPart
147
								.size(), true);
148
						currentHunk.addPartRangeToNew(newPart, 0, newPart
149
								.size(), true);
150
					} else {
151
						currentHunk.addPartRangeToOld(oldPart, 0, oldPart
152
								.size(), false);
153
						currentHunk.addPartRangeToNew(newPart, 0, newPart
154
								.size(), false);
155
					}
156
				} else {
157
					if (firstHunk) {
158
						// Hunk will start with context
159
						currentHunk = new Hunk(oldPart.size() - 3, oldPart
160
								.size() - 3);
161
						firstHunk = false;
162
						currentHunk.addPartRangeToBoth(oldPart,
163
								oldPart.size() - 3, oldPart.size(), false);
164
					} else {
165
						if (partNumber == (allDiffs.size() - 1)) {
166
							// If it is the last part
167
							currentHunk.addPartRangeToBoth(oldPart, 0, 3, true);
168
						} else {
169
							if (oldPart.size() < 6) {
170
								// Context too short to start new hunk
171
								currentHunk.addPartRangeToBoth(oldPart, 0,
172
										oldPart.size(), false);
173
							} else {
174
								// Context long enough to start new hunk
175
								currentHunk.addPartRangeToBoth(oldPart, 0, 3,
176
										false);
177
								currentHunk.printTo(output);
178
								currentHunk = new Hunk(currentLineNumberOld
179
										+ oldPart.size() - 3,
180
										currentLineNumberNew + oldPart.size()
181
												- 3);
182
								currentHunk.addPartRangeToBoth(oldPart, oldPart
183
										.size() - 3, oldPart.size(), false);
184
							}
185
						}
186
					}
187
				}
188
				currentLineNumberOld += oldPart.size();
189
				currentLineNumberNew += newPart.size();
190
			}
191
			// Print the last hunk
192
			currentHunk.printTo(output);
193
		}
194
	}
195
196
	private ArrayList getPart(int nr, char side) {
197
		try {
198
			String s = extract(nr, side).replaceAll("\r\n", "\n"); //$NON-NLS-1$ //$NON-NLS-2$
199
			s.replaceAll("\r", "\n"); //$NON-NLS-1$ //$NON-NLS-2$
200
			ArrayList diffLines = new ArrayList(Arrays
201
					.asList(s.split("\n", -1))); //$NON-NLS-1$
202
			return diffLines;
203
		} catch (BadLocationException e) {
204
			CompareUIPlugin.log(e);
205
		}
206
		return null;
207
	}
208
209
	private String extract(int nr, char side) throws BadLocationException {
210
		Diff diff = ((Diff) merger.getAllDiffs().get(nr));
211
		if (side == LEFT_CONTRIBUTOR && !rightToLeft
212
				|| side == RIGHT_CONTRIBUTOR && rightToLeft) {
213
			return leftDoc.get(diff.getPosition(LEFT_CONTRIBUTOR).offset, diff
214
					.getPosition(LEFT_CONTRIBUTOR).length);
215
		}
216
		return rightDoc.get(diff.getPosition(RIGHT_CONTRIBUTOR).offset, diff
217
				.getPosition(RIGHT_CONTRIBUTOR).length);
218
	}
219
220
	public boolean isPartDifferent(ArrayList allDiffs, int nr) {
221
		Diff diff = ((Diff) allDiffs.get(nr));
222
		if (diff.getKind() == RangeDifference.CHANGE) {
223
			return true;
224
		}
225
		return false;
226
	}
227
228
	private class Hunk {
229
		private int oldStart;
230
		private int oldEnd;
231
		private int newStart;
232
		private int newEnd;
233
		ArrayList lines;
234
235
		public Hunk(int oldStart, int newStart) {
236
			if (oldStart < 0)
237
				oldStart = 0;
238
			if (newStart < 0)
239
				newStart = 0;
240
			this.oldStart = oldStart;
241
			this.newStart = newStart;
242
			this.oldEnd = oldStart;
243
			this.newEnd = newStart;
244
			lines = new ArrayList();
245
		}
246
247
		public void addPartRangeToOld(ArrayList part, int start, int end,
248
				boolean lastPart) {
249
			if (start < 0)
250
				start = 0;
251
			if (lastPart)
252
				end = Math.min(end, part.size());
253
			else
254
				end = Math.min(end, part.size() - 1);
255
			for (int lineNr = start; lineNr < end; lineNr++) {
256
				lines.add(OLD_LINE_PREFIX + part.get(lineNr));
257
				oldEnd++;
258
			}
259
		}
260
261
		public void addPartRangeToNew(ArrayList part, int start, int end,
262
				boolean lastPart) {
263
			if (start < 0)
264
				start = 0;
265
			if (lastPart)
266
				end = Math.min(end, part.size());
267
			else
268
				end = Math.min(end, part.size() - 1);
269
			for (int lineNr = start; lineNr < end; lineNr++) {
270
				lines.add(NEW_LINE_PREFIX + part.get(lineNr));
271
				newEnd++;
272
			}
273
		}
274
275
		public void addPartRangeToBoth(ArrayList part, int start, int end,
276
				boolean lastPart) {
277
			if (start < 0)
278
				start = 0;
279
			if (lastPart)
280
				end = Math.min(end, part.size());
281
			else
282
				end = Math.min(end, part.size() - 1);
283
			for (int lineNr = start; lineNr < end; lineNr++) {
284
				lines.add(CONTEXT_LINE_PREFIX + part.get(lineNr));
285
				oldEnd++;
286
				newEnd++;
287
			}
288
		}
289
290
		private void printMarkerTo(PrintStream output) {
291
			output.println("@@ -" + oldStart + "," + oldEnd + " +" + newStart //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
292
					+ "," + newEnd + " @@"); //$NON-NLS-1$ //$NON-NLS-2$
293
		}
294
295
		public void printTo(PrintStream output) {
296
			printMarkerTo(output);
297
			for (int i = 0; i < lines.size(); i++) {
298
				output.println(lines.get(i));
299
			}
300
		}
301
	}
302
303
}

Return to bug 71374