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 (-1676 / +2062 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 170-364 Link Here
170
171
171
/**
172
/**
172
 * A text merge viewer uses the <code>RangeDifferencer</code> to perform a
173
 * A text merge viewer uses the <code>RangeDifferencer</code> to perform a
173
 * textual, line-by-line comparison of two (or three) input documents.
174
 * textual, line-by-line comparison of two (or three) input documents. It is
174
 * It is based on the <code>ContentMergeViewer</code> and uses <code>TextViewer</code>s
175
 * based on the <code>ContentMergeViewer</code> and uses <code>TextViewer</code>
175
 * to implement the ancestor, left, and right content areas.
176
 * s to implement the ancestor, left, and right content areas.
176
 * <p>
177
 * <p>
177
 * In the three-way compare case ranges of differing lines are highlighted and framed
178
 * In the three-way compare case ranges of differing lines are highlighted and
178
 * with different colors to show whether the difference is an incoming, outgoing, or conflicting change.
179
 * framed with different colors to show whether the difference is an incoming,
179
 * The <code>TextMergeViewer</code> supports the notion of a current "differing range"
180
 * outgoing, or conflicting change. The <code>TextMergeViewer</code> supports
180
 * and provides toolbar buttons to navigate from one range to the next (or previous).
181
 * the notion of a current "differing range" and provides toolbar buttons to
182
 * navigate from one range to the next (or previous).
181
 * <p>
183
 * <p>
182
 * If there is a current "differing range" and the underlying document is editable
184
 * If there is a current "differing range" and the underlying document is
183
 * the <code>TextMergeViewer</code> enables actions in context menu and toolbar to
185
 * editable the <code>TextMergeViewer</code> enables actions in context menu and
184
 * copy a range from one side to the other side, thereby performing a merge operation.
186
 * toolbar to copy a range from one side to the other side, thereby performing a
187
 * merge operation.
185
 * <p>
188
 * <p>
186
 * In addition to a line-by-line comparison the <code>TextMergeViewer</code>
189
 * In addition to a line-by-line comparison the <code>TextMergeViewer</code>
187
 * uses a token based compare on differing lines.
190
 * uses a token based compare on differing lines. The token compare is activated
188
 * The token compare is activated when navigating into
191
 * when navigating into a range of differing lines. At first the lines are
189
 * a range of differing lines. At first the lines are selected as a block.
192
 * selected as a block. When navigating into this block the token compare shows
190
 * When navigating into this block the token compare shows for every line
193
 * for every line the differing token by selecting them.
191
 * the differing token by selecting them.
192
 * <p>
194
 * <p>
193
 * The <code>TextMergeViewer</code>'s default token compare works on characters separated
195
 * The <code>TextMergeViewer</code>'s default token compare works on characters
194
 * by whitespace. If a different strategy is needed (for example, Java tokens in
196
 * separated by whitespace. If a different strategy is needed (for example, Java
195
 * a Java-aware merge viewer), clients can create their own token
197
 * tokens in a Java-aware merge viewer), clients can create their own token
196
 * comparators by implementing the <code>ITokenComparator</code> interface and overriding the
198
 * comparators by implementing the <code>ITokenComparator</code> interface and
197
 * <code>TextMergeViewer.createTokenComparator</code> factory method).
199
 * overriding the <code>TextMergeViewer.createTokenComparator</code> factory
200
 * method).
198
 * <p>
201
 * <p>
199
 * Access to the <code>TextMergeViewer</code>'s model is by means of an
202
 * Access to the <code>TextMergeViewer</code>'s model is by means of an
200
 * <code>IMergeViewerContentProvider</code>. Its <code>get<it>X</it></code>Content</code> methods must return
203
 * <code>IMergeViewerContentProvider</code>. Its <code>get<it>X</it></code>
201
 * either an <code>IDocument</code>, an <code>IDocumentRange</code>, or an <code>IStreamContentAccessor</code>.
204
 * Content</code> methods must return either an <code>IDocument</code>, an
202
 * In the <code>IDocumentRange</code> case the <code>TextMergeViewer</code>
205
 * <code>IDocumentRange</code>, or an <code>IStreamContentAccessor</code>. In
203
 * works on a subrange of a document. In the <code>IStreamContentAccessor</code> case
206
 * the <code>IDocumentRange</code> case the <code>TextMergeViewer</code> works
207
 * on a subrange of a document. In the <code>IStreamContentAccessor</code> case
204
 * a document is created internally and initialized from the stream.
208
 * a document is created internally and initialized from the stream.
205
 * <p>
209
 * <p>
206
 * A <code>TextMergeViewer</code> can be used as is. However clients may subclass
210
 * A <code>TextMergeViewer</code> can be used as is. However clients may
207
 * to customize the behavior. For example a <code>MergeTextViewer</code> for Java would override
211
 * subclass to customize the behavior. For example a
208
 * the <code>configureTextViewer</code> method to configure the <code>TextViewer</code> for Java source code,
212
 * <code>MergeTextViewer</code> for Java would override the
209
 * the <code>createTokenComparator</code> method to create a Java specific tokenizer.
213
 * <code>configureTextViewer</code> method to configure the
210
 *
214
 * <code>TextViewer</code> for Java source code, the
215
 * <code>createTokenComparator</code> method to create a Java specific
216
 * tokenizer.
217
 * 
211
 * @see org.eclipse.compare.rangedifferencer.RangeDifferencer
218
 * @see org.eclipse.compare.rangedifferencer.RangeDifferencer
212
 * @see org.eclipse.jface.text.TextViewer
219
 * @see org.eclipse.jface.text.TextViewer
213
 * @see ITokenComparator
220
 * @see ITokenComparator
214
 * @see IDocumentRange
221
 * @see IDocumentRange
215
 * @see org.eclipse.compare.IStreamContentAccessor
222
 * @see org.eclipse.compare.IStreamContentAccessor
216
 */
223
 */
217
public class TextMergeViewer extends ContentMergeViewer implements IAdaptable  {
224
public class TextMergeViewer extends ContentMergeViewer implements IAdaptable {
218
	
225
219
	private static final String COPY_LEFT_TO_RIGHT_INDICATOR = ">"; //$NON-NLS-1$
226
	private static final String COPY_LEFT_TO_RIGHT_INDICATOR = ">"; //$NON-NLS-1$
220
	private static final String COPY_RIGHT_TO_LEFT_INDICATOR = "<"; //$NON-NLS-1$
227
	private static final String COPY_RIGHT_TO_LEFT_INDICATOR = "<"; //$NON-NLS-1$
221
	private static final char ANCESTOR_CONTRIBUTOR = MergeViewerContentProvider.ANCESTOR_CONTRIBUTOR;
228
	private static final char ANCESTOR_CONTRIBUTOR = MergeViewerContentProvider.ANCESTOR_CONTRIBUTOR;
222
	private static final char RIGHT_CONTRIBUTOR = MergeViewerContentProvider.RIGHT_CONTRIBUTOR;
229
	private static final char RIGHT_CONTRIBUTOR = MergeViewerContentProvider.RIGHT_CONTRIBUTOR;
223
	private static final char LEFT_CONTRIBUTOR = MergeViewerContentProvider.LEFT_CONTRIBUTOR;
230
	private static final char LEFT_CONTRIBUTOR = MergeViewerContentProvider.LEFT_CONTRIBUTOR;
224
	
225
	private static final String DIFF_RANGE_CATEGORY = CompareUIPlugin.PLUGIN_ID + ".DIFF_RANGE_CATEGORY"; //$NON-NLS-1$
226
231
227
	static final boolean DEBUG= false;
232
	private static final String DIFF_RANGE_CATEGORY = CompareUIPlugin.PLUGIN_ID
228
	
233
			+ ".DIFF_RANGE_CATEGORY"; //$NON-NLS-1$
229
	private static final boolean FIX_47640= true;
234
230
	
235
	static final boolean DEBUG = false;
231
	private static final String[] GLOBAL_ACTIONS= {
236
232
		ActionFactory.UNDO.getId(),
237
	private static final boolean FIX_47640 = true;
233
		ActionFactory.REDO.getId(),
238
234
		ActionFactory.CUT.getId(),
239
	private static final String[] GLOBAL_ACTIONS = {
235
		ActionFactory.COPY.getId(),
240
			ActionFactory.UNDO.getId(), ActionFactory.REDO.getId(),
236
		ActionFactory.PASTE.getId(),
241
			ActionFactory.CUT.getId(), ActionFactory.COPY.getId(),
237
		ActionFactory.DELETE.getId(),
242
			ActionFactory.PASTE.getId(), ActionFactory.DELETE.getId(),
238
		ActionFactory.SELECT_ALL.getId(),
243
			ActionFactory.SELECT_ALL.getId(), ActionFactory.SAVE.getId(),
239
		ActionFactory.SAVE.getId(),
244
			ActionFactory.FIND.getId(),
240
		ActionFactory.FIND.getId(),
245
			ITextEditorActionDefinitionIds.LINE_GOTO };
241
		ITextEditorActionDefinitionIds.LINE_GOTO
246
	private static final String[] TEXT_ACTIONS = { MergeSourceViewer.UNDO_ID,
242
	};
247
			MergeSourceViewer.REDO_ID, MergeSourceViewer.CUT_ID,
243
	private static final String[] TEXT_ACTIONS= {
248
			MergeSourceViewer.COPY_ID, MergeSourceViewer.PASTE_ID,
244
		MergeSourceViewer.UNDO_ID,
249
			MergeSourceViewer.DELETE_ID, MergeSourceViewer.SELECT_ALL_ID,
245
		MergeSourceViewer.REDO_ID,
250
			MergeSourceViewer.SAVE_ID, MergeSourceViewer.FIND_ID,
246
		MergeSourceViewer.CUT_ID,
251
			MergeSourceViewer.GOTO_LINE_ID };
247
		MergeSourceViewer.COPY_ID,
252
248
		MergeSourceViewer.PASTE_ID,
253
	private static final String BUNDLE_NAME = "org.eclipse.compare.contentmergeviewer.TextMergeViewerResources"; //$NON-NLS-1$
249
		MergeSourceViewer.DELETE_ID,
254
250
		MergeSourceViewer.SELECT_ALL_ID,
255
	// the following symbolic constants must match the IDs in Compare's
251
		MergeSourceViewer.SAVE_ID,
256
	// plugin.xml
252
		MergeSourceViewer.FIND_ID, 
257
	private static final String INCOMING_COLOR = "INCOMING_COLOR"; //$NON-NLS-1$
253
		MergeSourceViewer.GOTO_LINE_ID
258
	private static final String OUTGOING_COLOR = "OUTGOING_COLOR"; //$NON-NLS-1$
254
	};
259
	private static final String CONFLICTING_COLOR = "CONFLICTING_COLOR"; //$NON-NLS-1$
255
					
260
	private static final String RESOLVED_COLOR = "RESOLVED_COLOR"; //$NON-NLS-1$
256
	private static final String BUNDLE_NAME= "org.eclipse.compare.contentmergeviewer.TextMergeViewerResources"; //$NON-NLS-1$
261
257
	
258
	// the following symbolic constants must match the IDs in Compare's plugin.xml
259
	private static final String INCOMING_COLOR= "INCOMING_COLOR"; //$NON-NLS-1$
260
	private static final String OUTGOING_COLOR= "OUTGOING_COLOR"; //$NON-NLS-1$
261
	private static final String CONFLICTING_COLOR= "CONFLICTING_COLOR"; //$NON-NLS-1$
262
	private static final String RESOLVED_COLOR= "RESOLVED_COLOR"; //$NON-NLS-1$
263
	
264
	// constants
262
	// constants
265
	/** Width of left and right vertical bar */
263
	/** Width of left and right vertical bar */
266
	private static final int MARGIN_WIDTH= 6;
264
	private static final int MARGIN_WIDTH = 6;
267
	/** Width of center bar */
265
	/** Width of center bar */
268
	private static final int CENTER_WIDTH= 34;
266
	private static final int CENTER_WIDTH = 34;
269
	/** Width of birds eye view */
267
	/** Width of birds eye view */
270
	private static final int BIRDS_EYE_VIEW_WIDTH= 12;
268
	private static final int BIRDS_EYE_VIEW_WIDTH = 12;
271
	/** Width of birds eye view */
269
	/** Width of birds eye view */
272
	private static final int BIRDS_EYE_VIEW_INSET= 2;
270
	private static final int BIRDS_EYE_VIEW_INSET = 2;
273
	/** */
271
	/** */
274
	private static final int RESOLVE_SIZE= 5;
272
	private static final int RESOLVE_SIZE = 5;
275
273
276
	/** line width of change borders */
274
	/** line width of change borders */
277
	private static final int LW= 1;
275
	private static final int LW = 1;
278
		
276
279
	// determines whether a change between left and right is considered incoming or outgoing
277
	// determines whether a change between left and right is considered incoming
278
	// or outgoing
280
	private boolean fLeftIsLocal;
279
	private boolean fLeftIsLocal;
281
	private boolean fShowCurrentOnly= false;
280
	private boolean fShowCurrentOnly = false;
282
	private boolean fShowCurrentOnly2= false;
281
	private boolean fShowCurrentOnly2 = false;
283
	private int fMarginWidth= MARGIN_WIDTH;
282
	private int fMarginWidth = MARGIN_WIDTH;
284
	private int fTopInset;
283
	private int fTopInset;
285
	
284
286
	// Colors
285
	// Colors
287
	private RGB fBackground;
286
	private RGB fBackground;
288
	private RGB fForeground;
287
	private RGB fForeground;
289
288
290
	private boolean fIsUsingSystemForeground= true;
289
	private boolean fIsUsingSystemForeground = true;
291
	private boolean fIsUsingSystemBackground= true;
290
	private boolean fIsUsingSystemBackground = true;
292
	
291
293
	private RGB SELECTED_INCOMING;
292
	private RGB SELECTED_INCOMING;
294
	private RGB INCOMING;
293
	private RGB INCOMING;
295
	private RGB INCOMING_FILL;
294
	private RGB INCOMING_FILL;
296
	private RGB INCOMING_TEXT_FILL;
295
	private RGB INCOMING_TEXT_FILL;
297
	
296
298
	private RGB SELECTED_CONFLICT;
297
	private RGB SELECTED_CONFLICT;
299
	private RGB CONFLICT;
298
	private RGB CONFLICT;
300
	private RGB CONFLICT_FILL;
299
	private RGB CONFLICT_FILL;
301
	private RGB CONFLICT_TEXT_FILL;
300
	private RGB CONFLICT_TEXT_FILL;
302
	
301
303
	private RGB SELECTED_OUTGOING;
302
	private RGB SELECTED_OUTGOING;
304
	private RGB OUTGOING;
303
	private RGB OUTGOING;
305
	private RGB OUTGOING_FILL;
304
	private RGB OUTGOING_FILL;
306
	private RGB OUTGOING_TEXT_FILL;
305
	private RGB OUTGOING_TEXT_FILL;
307
	
306
308
	private RGB RESOLVED;
307
	private RGB RESOLVED;
309
	
308
310
	private IPreferenceStore fPreferenceStore;
309
	private IPreferenceStore fPreferenceStore;
311
	private IPropertyChangeListener fPreferenceChangeListener;
310
	private IPropertyChangeListener fPreferenceChangeListener;
312
	
311
313
	private HashMap fNewAncestorRanges= new HashMap();
312
	private HashMap fNewAncestorRanges = new HashMap();
314
	private HashMap fNewLeftRanges= new HashMap();
313
	private HashMap fNewLeftRanges = new HashMap();
315
	private HashMap fNewRightRanges= new HashMap();
314
	private HashMap fNewRightRanges = new HashMap();
316
	
315
317
	private MergeSourceViewer fAncestor;
316
	private MergeSourceViewer fAncestor;
318
	private MergeSourceViewer fLeft;
317
	private MergeSourceViewer fLeft;
319
	private MergeSourceViewer fRight;
318
	private MergeSourceViewer fRight;
320
	
319
321
	private int fLeftLineCount;
320
	private int fLeftLineCount;
322
	private int fRightLineCount;
321
	private int fRightLineCount;
323
	
322
324
	private boolean fInScrolling;
323
	private boolean fInScrolling;
325
	
324
326
	private int fPts[]= new int[8];	// scratch area for polygon drawing
325
	private int fPts[] = new int[8]; // scratch area for polygon drawing
327
	
326
328
	private int fInheritedDirection;	// inherited direction
327
	private int fInheritedDirection; // inherited direction
329
	private int fTextDirection;			// requested direction for embedded SourceViewer
328
	private int fTextDirection; // requested direction for embedded SourceViewer
330
	
329
331
	private ActionContributionItem fIgnoreAncestorItem;
330
	private ActionContributionItem fIgnoreAncestorItem;
332
	private boolean fHighlightRanges;
331
	private boolean fHighlightRanges;
333
	
332
334
	private boolean fShowPseudoConflicts= false;
333
	private boolean fShowPseudoConflicts = false;
335
	
334
336
	private boolean fUseSplines= true;
335
	private boolean fUseSplines = true;
337
	private boolean fUseSingleLine= true;
336
	private boolean fUseSingleLine = true;
338
	private boolean fUseResolveUI= true;
337
	private boolean fUseResolveUI = true;
339
	private boolean fHighlightTokenChanges = false;
338
	private boolean fHighlightTokenChanges = false;
340
339
341
	private String fSymbolicFontName;
340
	private String fSymbolicFontName;
342
341
343
	private ActionContributionItem fNextDiff;	// goto next difference
342
	private ActionContributionItem fNextDiff; // goto next difference
344
	private ActionContributionItem fPreviousDiff;	// goto previous difference
343
	private ActionContributionItem fPreviousDiff; // goto previous difference
345
	private ActionContributionItem fCopyDiffLeftToRightItem;
344
	private ActionContributionItem fCopyDiffLeftToRightItem;
346
	private ActionContributionItem fCopyDiffRightToLeftItem;
345
	private ActionContributionItem fCopyDiffRightToLeftItem;
347
	
346
348
	private CompareHandlerService fHandlerService;
347
	private CompareHandlerService fHandlerService;
349
	
348
350
	private boolean fSynchronizedScrolling= true;
349
	private boolean fSynchronizedScrolling = true;
351
	private boolean fShowMoreInfo= false;
350
	private boolean fShowMoreInfo = false;
352
	
351
353
	private MergeSourceViewer fFocusPart;
352
	private MergeSourceViewer fFocusPart;
354
	
353
355
	private boolean fSubDoc= true;
354
	private boolean fSubDoc = true;
356
	private IPositionUpdater fPositionUpdater;
355
	private IPositionUpdater fPositionUpdater;
357
	private boolean fIsMotif;
356
	private boolean fIsMotif;
358
	private boolean fIsCarbon;
357
	private boolean fIsCarbon;
359
	
358
360
	private boolean fHasErrors;
359
	private boolean fHasErrors;
361
		
362
360
363
	// SWT widgets
361
	// SWT widgets
364
	private BufferedCanvas fAncestorCanvas;
362
	private BufferedCanvas fAncestorCanvas;
Lines 369-382 Link Here
369
	private Canvas fBirdsEyeCanvas;
367
	private Canvas fBirdsEyeCanvas;
370
	private Canvas fSummaryHeader;
368
	private Canvas fSummaryHeader;
371
	private HeaderPainter fHeaderPainter;
369
	private HeaderPainter fHeaderPainter;
372
	
370
373
	// SWT resources to be disposed
371
	// SWT resources to be disposed
374
	private Map fColors;
372
	private Map fColors;
375
	private Cursor fBirdsEyeCursor;
373
	private Cursor fBirdsEyeCursor;
376
				
374
377
	// points for center curves
375
	// points for center curves
378
	private double[] fBasicCenterCurve;
376
	private double[] fBasicCenterCurve;
379
	
377
380
	private Button fCenterButton;
378
	private Button fCenterButton;
381
	private Diff fButtonDiff;
379
	private Diff fButtonDiff;
382
380
Lines 395-431 Link Here
395
	private DocumentMerger fMerger;
393
	private DocumentMerger fMerger;
396
	/** The current diff */
394
	/** The current diff */
397
	private Diff fCurrentDiff;
395
	private Diff fCurrentDiff;
398
	
396
399
	/**
397
	/**
400
	 * Preference key for highlighting current line.
398
	 * Preference key for highlighting current line.
401
	 */
399
	 */
402
	private final static String CURRENT_LINE= AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE;
400
	private final static String CURRENT_LINE = AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE;
403
	/**
401
	/**
404
	 * Preference key for highlight color of current line.
402
	 * Preference key for highlight color of current line.
405
	 */
403
	 */
406
	private final static String CURRENT_LINE_COLOR= AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE_COLOR;
404
	private final static String CURRENT_LINE_COLOR = AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE_COLOR;
407
	
405
408
	private List fSourceViewerDecorationSupport = new ArrayList(3);
406
	private List fSourceViewerDecorationSupport = new ArrayList(3);
409
407
410
	private final class InternalOutlineViewerCreator extends OutlineViewerCreator implements ISelectionChangedListener {
408
	private final class InternalOutlineViewerCreator extends
409
			OutlineViewerCreator implements ISelectionChangedListener {
411
		public Viewer findStructureViewer(Viewer oldViewer,
410
		public Viewer findStructureViewer(Viewer oldViewer,
412
				ICompareInput input, Composite parent,
411
				ICompareInput input, Composite parent,
413
				CompareConfiguration configuration) {
412
				CompareConfiguration configuration) {
414
			if (input != getInput())
413
			if (input != getInput())
415
				return null;
414
				return null;
416
			final Viewer v = CompareUI.findStructureViewer(oldViewer, input, parent, configuration);
415
			final Viewer v = CompareUI.findStructureViewer(oldViewer, input,
416
					parent, configuration);
417
			if (v != null) {
417
			if (v != null) {
418
				v.getControl().addDisposeListener(new DisposeListener() {
418
				v.getControl().addDisposeListener(new DisposeListener() {
419
					public void widgetDisposed(DisposeEvent e) {
419
					public void widgetDisposed(DisposeEvent e) {
420
						v.removeSelectionChangedListener(InternalOutlineViewerCreator.this);
420
						v
421
								.removeSelectionChangedListener(InternalOutlineViewerCreator.this);
421
					}
422
					}
422
				});
423
				});
423
				v.addSelectionChangedListener(this);
424
				v.addSelectionChangedListener(this);
424
			}
425
			}
425
				
426
426
			return v;
427
			return v;
427
		}
428
		}
428
		
429
429
		public boolean hasViewerFor(Object input) {
430
		public boolean hasViewerFor(Object input) {
430
			return true;
431
			return true;
431
		}
432
		}
Lines 453-461 Link Here
453
			}
454
			}
454
			return null;
455
			return null;
455
		}
456
		}
456
		
457
457
	    private Diff findDiff(Position p, boolean left) {
458
		private Diff findDiff(Position p, boolean left) {
458
			for (Iterator iterator = fMerger.rangesIterator(); iterator.hasNext();) {
459
			for (Iterator iterator = fMerger.rangesIterator(); iterator
460
					.hasNext();) {
459
				Diff diff = (Diff) iterator.next();
461
				Diff diff = (Diff) iterator.next();
460
				Position diffPos;
462
				Position diffPos;
461
				if (left) {
463
				if (left) {
Lines 464-472 Link Here
464
					diffPos = diff.getPosition(RIGHT_CONTRIBUTOR);
466
					diffPos = diff.getPosition(RIGHT_CONTRIBUTOR);
465
				}
467
				}
466
				// If the element falls within a diff, highlight that diff
468
				// If the element falls within a diff, highlight that diff
467
				if (diffPos.offset + diffPos.length >= p.offset && diff.getKind() != RangeDifference.NOCHANGE)
469
				if (diffPos.offset + diffPos.length >= p.offset
470
						&& diff.getKind() != RangeDifference.NOCHANGE)
468
					return diff;
471
					return diff;
469
				// Otherwise, highlight the first diff after the elements position
472
				// Otherwise, highlight the first diff after the elements
473
				// position
470
				if (diffPos.offset >= p.offset)
474
				if (diffPos.offset >= p.offset)
471
					return diff;
475
					return diff;
472
			}
476
			}
Lines 486-492 Link Here
486
		}
490
		}
487
	}
491
	}
488
492
489
	class ContributorInfo implements IElementStateListener, VerifyListener, IDocumentListener {
493
	class ContributorInfo implements IElementStateListener, VerifyListener,
494
			IDocumentListener {
490
		private final TextMergeViewer fViewer;
495
		private final TextMergeViewer fViewer;
491
		private final Object fElement;
496
		private final Object fElement;
492
		private char fLeg;
497
		private char fLeg;
Lines 497-516 Link Here
497
		private int fTopIndex = -1;
502
		private int fTopIndex = -1;
498
		private boolean fNeedsValidation = false;
503
		private boolean fNeedsValidation = false;
499
		private MergeSourceViewer fSourceViewer;
504
		private MergeSourceViewer fSourceViewer;
500
		
505
501
		public ContributorInfo(TextMergeViewer viewer, Object element, char leg) {
506
		public ContributorInfo(TextMergeViewer viewer, Object element, char leg) {
502
			fViewer = viewer;
507
			fViewer = viewer;
503
			fElement = element;
508
			fElement = element;
504
			fLeg = leg;
509
			fLeg = leg;
505
			if (fElement instanceof IEncodedStreamContentAccessor) {
510
			if (fElement instanceof IEncodedStreamContentAccessor) {
506
				try {
511
				try {
507
					fEncoding = ((IEncodedStreamContentAccessor)fElement).getCharset();
512
					fEncoding = ((IEncodedStreamContentAccessor) fElement)
513
							.getCharset();
508
				} catch (CoreException e) {
514
				} catch (CoreException e) {
509
					// silently ignored
515
					// silently ignored
510
				}
516
				}
511
			}
517
			}
512
		}
518
		}
513
		
519
514
		public String getEncoding() {
520
		public String getEncoding() {
515
			if (fEncoding == null)
521
			if (fEncoding == null)
516
				return ResourcesPlugin.getEncoding();
522
				return ResourcesPlugin.getEncoding();
Lines 521-530 Link Here
521
			if (fEncoding == null)
527
			if (fEncoding == null)
522
				fEncoding = otherContributor.fEncoding;
528
				fEncoding = otherContributor.fEncoding;
523
		}
529
		}
524
		
530
525
		public IDocument getDocument() {
531
		public IDocument getDocument() {
526
			if (fDocumentProvider != null) {
532
			if (fDocumentProvider != null) {
527
				IDocument document = fDocumentProvider.getDocument(getDocumentKey());
533
				IDocument document = fDocumentProvider
534
						.getDocument(getDocumentKey());
528
				if (document != null)
535
				if (document != null)
529
					return document;
536
					return document;
530
			}
537
			}
Lines 536-542 Link Here
536
				return DocumentManager.get(fElement);
543
				return DocumentManager.get(fElement);
537
			return null;
544
			return null;
538
		}
545
		}
539
		
546
540
		public void setDocument(MergeSourceViewer viewer, boolean isEditable) {
547
		public void setDocument(MergeSourceViewer viewer, boolean isEditable) {
541
			// Ensure that this method is only called once
548
			// Ensure that this method is only called once
542
			Assert.isTrue(fSourceViewer == null);
549
			Assert.isTrue(fSourceViewer == null);
Lines 544-550 Link Here
544
			try {
551
			try {
545
				internalSetDocument(viewer);
552
				internalSetDocument(viewer);
546
			} catch (RuntimeException e) {
553
			} catch (RuntimeException e) {
547
				// The error may be due to a stale entry in the DocumentManager (see bug 184489)
554
				// The error may be due to a stale entry in the DocumentManager
555
				// (see bug 184489)
548
				clearCachedDocument();
556
				clearCachedDocument();
549
				throw e;
557
				throw e;
550
			}
558
			}
Lines 555-635 Link Here
555
				viewer.getTextWidget().addVerifyListener(this);
563
				viewer.getTextWidget().addVerifyListener(this);
556
			}
564
			}
557
		}
565
		}
558
		
566
559
		/*
567
		/*
560
		 * Returns true if a new Document could be installed.
568
		 * Returns true if a new Document could be installed.
561
		 */
569
		 */
562
		private boolean internalSetDocument(MergeSourceViewer tp) {
570
		private boolean internalSetDocument(MergeSourceViewer tp) {
563
			
571
564
			if (tp == null)
572
			if (tp == null)
565
				return false;
573
				return false;
566
			
574
567
			IDocument newDocument = null;
575
			IDocument newDocument = null;
568
			Position range= null;
576
			Position range = null;
569
577
570
			if (fElement instanceof IDocumentRange) {
578
			if (fElement instanceof IDocumentRange) {
571
				newDocument= ((IDocumentRange)fElement).getDocument();
579
				newDocument = ((IDocumentRange) fElement).getDocument();
572
				range= ((IDocumentRange)fElement).getRange();
580
				range = ((IDocumentRange) fElement).getRange();
573
				connectToSharedDocument();
581
				connectToSharedDocument();
574
582
575
			} else if (fElement instanceof IDocument) {
583
			} else if (fElement instanceof IDocument) {
576
				newDocument= (IDocument) fElement;
584
				newDocument = (IDocument) fElement;
577
				
585
578
			} else if (fElement instanceof IStreamContentAccessor) {
586
			} else if (fElement instanceof IStreamContentAccessor) {
579
				newDocument= DocumentManager.get(fElement);
587
				newDocument = DocumentManager.get(fElement);
580
				if (newDocument == null) {
588
				if (newDocument == null) {
581
					newDocument = createDocument();
589
					newDocument = createDocument();
582
					DocumentManager.put(fElement, newDocument);
590
					DocumentManager.put(fElement, newDocument);
583
					setupDocument(newDocument);
591
					setupDocument(newDocument);
584
				} else if (fDocumentProvider == null) {
592
				} else if (fDocumentProvider == null) {
585
					// Connect to a shared document so we can get the proper save synchronization
593
					// Connect to a shared document so we can get the proper
594
					// save synchronization
586
					connectToSharedDocument();
595
					connectToSharedDocument();
587
				}
596
				}
588
			} else if (fElement == null) {	// deletion on one side
597
			} else if (fElement == null) { // deletion on one side
589
				
598
590
				ITypedElement parent= this.fViewer.getParent(fLeg);	// we try to find an insertion position within the deletion's parent
599
				ITypedElement parent = this.fViewer.getParent(fLeg); // we try
591
				
600
																		// to
601
																		// find
602
																		// an
603
																		// insertion
604
																		// position
605
																		// within
606
																		// the
607
																		// deletion's
608
																		// parent
609
592
				if (parent instanceof IDocumentRange) {
610
				if (parent instanceof IDocumentRange) {
593
					newDocument= ((IDocumentRange)parent).getDocument();
611
					newDocument = ((IDocumentRange) parent).getDocument();
594
					newDocument.addPositionCategory(DIFF_RANGE_CATEGORY);
612
					newDocument.addPositionCategory(DIFF_RANGE_CATEGORY);
595
					Object input= this.fViewer.getInput();
613
					Object input = this.fViewer.getInput();
596
					range= this.fViewer.getNewRange(fLeg, input);
614
					range = this.fViewer.getNewRange(fLeg, input);
597
					if (range == null) {
615
					if (range == null) {
598
						int pos= 0;
616
						int pos = 0;
599
						if (input instanceof ICompareInput)
617
						if (input instanceof ICompareInput)
600
							pos= this.fViewer.findInsertionPosition(fLeg, (ICompareInput)input);
618
							pos = this.fViewer.findInsertionPosition(fLeg,
601
						range= new Position(pos, 0);
619
									(ICompareInput) input);
620
						range = new Position(pos, 0);
602
						try {
621
						try {
603
							newDocument.addPosition(DIFF_RANGE_CATEGORY, range);
622
							newDocument.addPosition(DIFF_RANGE_CATEGORY, range);
604
						} catch (BadPositionCategoryException ex) {
623
						} catch (BadPositionCategoryException ex) {
605
							// silently ignored
624
							// silently ignored
606
							if (TextMergeViewer.DEBUG) System.out.println("BadPositionCategoryException: " + ex);	//$NON-NLS-1$
625
							if (TextMergeViewer.DEBUG)
626
								System.out
627
										.println("BadPositionCategoryException: " + ex); //$NON-NLS-1$
607
						} catch (BadLocationException ex) {
628
						} catch (BadLocationException ex) {
608
							// silently ignored
629
							// silently ignored
609
							if (TextMergeViewer.DEBUG) System.out.println("BadLocationException: " + ex);	//$NON-NLS-1$
630
							if (TextMergeViewer.DEBUG)
631
								System.out
632
										.println("BadLocationException: " + ex); //$NON-NLS-1$
610
						}
633
						}
611
						this.fViewer.addNewRange(fLeg, input, range);
634
						this.fViewer.addNewRange(fLeg, input, range);
612
					}
635
					}
613
				} else if (parent instanceof IDocument) {
636
				} else if (parent instanceof IDocument) {
614
					newDocument= ((IDocumentRange)fElement).getDocument();
637
					newDocument = ((IDocumentRange) fElement).getDocument();
615
				}
638
				}
616
			}
639
			}
617
640
618
			boolean enabled= true;
641
			boolean enabled = true;
619
			if (newDocument == null) {
642
			if (newDocument == null) {
620
				newDocument= new Document(""); //$NON-NLS-1$
643
				newDocument = new Document(""); //$NON-NLS-1$
621
				enabled= false;
644
				enabled = false;
622
			}
645
			}
623
			
646
624
			// Update the viewer document or range
647
			// Update the viewer document or range
625
			IDocument oldDoc= tp.getDocument();
648
			IDocument oldDoc = tp.getDocument();
626
			if (newDocument != oldDoc) {
649
			if (newDocument != oldDoc) {
627
				updateViewerDocument(tp, newDocument, range);
650
				updateViewerDocument(tp, newDocument, range);
628
			} else {	// same document but different range
651
			} else { // same document but different range
629
				updateViewerDocumentRange(tp, range);
652
				updateViewerDocumentRange(tp, range);
630
			}
653
			}
631
			newDocument.addDocumentListener(this);
654
			newDocument.addDocumentListener(this);
632
			
655
633
			tp.setEnabled(enabled);
656
			tp.setEnabled(enabled);
634
657
635
			return enabled;
658
			return enabled;
Lines 638-648 Link Here
638
		/*
661
		/*
639
		 * The viewer document is the same but the range has changed
662
		 * The viewer document is the same but the range has changed
640
		 */
663
		 */
641
		private void updateViewerDocumentRange(MergeSourceViewer tp, Position range) {
664
		private void updateViewerDocumentRange(MergeSourceViewer tp,
665
				Position range) {
642
			tp.setRegion(range);
666
			tp.setRegion(range);
643
			if (this.fViewer.fSubDoc) {
667
			if (this.fViewer.fSubDoc) {
644
				if (range != null) {
668
				if (range != null) {
645
					IRegion r= this.fViewer.normalizeDocumentRegion(tp.getDocument(), TextMergeViewer.toRegion(range));
669
					IRegion r = this.fViewer.normalizeDocumentRegion(tp
670
							.getDocument(), TextMergeViewer.toRegion(range));
646
					tp.setVisibleRegion(r.getOffset(), r.getLength());
671
					tp.setVisibleRegion(r.getOffset(), r.getLength());
647
				} else
672
				} else
648
					tp.resetVisibleRegion();
673
					tp.resetVisibleRegion();
Lines 653-667 Link Here
653
		/*
678
		/*
654
		 * The viewer has a new document
679
		 * The viewer has a new document
655
		 */
680
		 */
656
		private void updateViewerDocument(MergeSourceViewer tp, IDocument document, Position range) {
681
		private void updateViewerDocument(MergeSourceViewer tp,
682
				IDocument document, Position range) {
657
			unsetDocument(tp);
683
			unsetDocument(tp);
658
			if (document == null)
684
			if (document == null)
659
				return;
685
				return;
660
			
686
661
			// Add a position updater to the document
687
			// Add a position updater to the document
662
			document.addPositionCategory(DIFF_RANGE_CATEGORY);
688
			document.addPositionCategory(DIFF_RANGE_CATEGORY);
663
			if (this.fViewer.fPositionUpdater == null)
689
			if (this.fViewer.fPositionUpdater == null)
664
				this.fViewer.fPositionUpdater= this.fViewer.new ChildPositionUpdater(DIFF_RANGE_CATEGORY);
690
				this.fViewer.fPositionUpdater = this.fViewer.new ChildPositionUpdater(
691
						DIFF_RANGE_CATEGORY);
665
			else
692
			else
666
				document.removePositionUpdater(this.fViewer.fPositionUpdater);
693
				document.removePositionUpdater(this.fViewer.fPositionUpdater);
667
			document.addPositionUpdater(this.fViewer.fPositionUpdater);
694
			document.addPositionUpdater(this.fViewer.fPositionUpdater);
Lines 670-687 Link Here
670
			tp.setRegion(range);
697
			tp.setRegion(range);
671
			if (this.fViewer.fSubDoc) {
698
			if (this.fViewer.fSubDoc) {
672
				if (range != null) {
699
				if (range != null) {
673
					IRegion r= this.fViewer.normalizeDocumentRegion(document, TextMergeViewer.toRegion(range));
700
					IRegion r = this.fViewer.normalizeDocumentRegion(document,
701
							TextMergeViewer.toRegion(range));
674
					tp.setDocument(document, r.getOffset(), r.getLength());
702
					tp.setDocument(document, r.getOffset(), r.getLength());
675
				} else
703
				} else
676
					tp.setDocument(document);
704
					tp.setDocument(document);
677
			} else
705
			} else
678
				tp.setDocument(document);
706
				tp.setDocument(document);
679
							
707
680
			tp.rememberDocument(document);
708
			tp.rememberDocument(document);
681
		}
709
		}
682
		
710
683
		private void unsetDocument(MergeSourceViewer tp) {
711
		private void unsetDocument(MergeSourceViewer tp) {
684
			IDocument oldDoc= internalGetDocument(tp);
712
			IDocument oldDoc = internalGetDocument(tp);
685
			if (oldDoc != null) {
713
			if (oldDoc != null) {
686
				tp.rememberDocument(null);
714
				tp.rememberDocument(null);
687
				try {
715
				try {
Lines 694-708 Link Here
694
				oldDoc.removeDocumentListener(this);
722
				oldDoc.removeDocumentListener(this);
695
			}
723
			}
696
		}
724
		}
697
		
725
698
		private IDocument createDocument() {
726
		private IDocument createDocument() {
699
			// If the content provider is a text content provider, attempt to obtain
727
			// If the content provider is a text content provider, attempt to
728
			// obtain
700
			// a shared document (i.e. file buffer)
729
			// a shared document (i.e. file buffer)
701
			IDocument newDoc = connectToSharedDocument();
730
			IDocument newDoc = connectToSharedDocument();
702
			
731
703
			if (newDoc == null) {
732
			if (newDoc == null) {
704
				IStreamContentAccessor sca= (IStreamContentAccessor) fElement;
733
				IStreamContentAccessor sca = (IStreamContentAccessor) fElement;
705
				String s= null;
734
				String s = null;
706
735
707
				try {
736
				try {
708
					String encoding = getEncoding();
737
					String encoding = getEncoding();
Lines 711-726 Link Here
711
					this.fViewer.setError(fLeg, ex.getMessage());
740
					this.fViewer.setError(fLeg, ex.getMessage());
712
				}
741
				}
713
742
714
				newDoc= new Document(s != null ? s : ""); //$NON-NLS-1$
743
				newDoc = new Document(s != null ? s : ""); //$NON-NLS-1$
715
			}
744
			}
716
			return newDoc;
745
			return newDoc;
717
		}
746
		}
718
747
719
		/**
748
		/**
720
		 * Connect to a shared document if possible. Return <code>null</code>
749
		 * Connect to a shared document if possible. Return <code>null</code> if
721
		 * if the connection was not possible.
750
		 * the connection was not possible.
751
		 * 
722
		 * @return the shared document or <code>null</code> if connection to a
752
		 * @return the shared document or <code>null</code> if connection to a
723
		 * shared document was not possible
753
		 *         shared document was not possible
724
		 */
754
		 */
725
		private IDocument connectToSharedDocument() {
755
		private IDocument connectToSharedDocument() {
726
			IEditorInput key = getDocumentKey();
756
			IEditorInput key = getDocumentKey();
Lines 733-763 Link Here
733
				if (documentProvider != null) {
763
				if (documentProvider != null) {
734
					try {
764
					try {
735
						connect(documentProvider, key);
765
						connect(documentProvider, key);
736
						setCachedDocumentProvider(key,
766
						setCachedDocumentProvider(key, documentProvider);
737
								documentProvider);
738
						IDocument newDoc = documentProvider.getDocument(key);
767
						IDocument newDoc = documentProvider.getDocument(key);
739
						this.fViewer.updateDirtyState(key, documentProvider, fLeg);
768
						this.fViewer.updateDirtyState(key, documentProvider,
769
								fLeg);
740
						return newDoc;
770
						return newDoc;
741
					} catch (CoreException e) {
771
					} catch (CoreException e) {
742
						// Connection failed. Log the error and continue without a shared document
772
						// Connection failed. Log the error and continue without
773
						// a shared document
743
						CompareUIPlugin.log(e);
774
						CompareUIPlugin.log(e);
744
					}
775
					}
745
				}
776
				}
746
			}
777
			}
747
			return null;
778
			return null;
748
		}
779
		}
749
		
780
750
		private void connect(IDocumentProvider documentProvider, IEditorInput input) throws CoreException {
781
		private void connect(IDocumentProvider documentProvider,
751
			final ISharedDocumentAdapter sda = (ISharedDocumentAdapter) Utilities.getAdapter(fElement, ISharedDocumentAdapter.class);
782
				IEditorInput input) throws CoreException {
783
			final ISharedDocumentAdapter sda = (ISharedDocumentAdapter) Utilities
784
					.getAdapter(fElement, ISharedDocumentAdapter.class);
752
			if (sda != null) {
785
			if (sda != null) {
753
				sda.connect(documentProvider, input);
786
				sda.connect(documentProvider, input);
754
			} else {
787
			} else {
755
				documentProvider.connect(input);
788
				documentProvider.connect(input);
756
			}
789
			}
757
		}
790
		}
758
		
791
759
		private void disconnect(IDocumentProvider provider, IEditorInput input) {
792
		private void disconnect(IDocumentProvider provider, IEditorInput input) {
760
			final ISharedDocumentAdapter sda = (ISharedDocumentAdapter) Utilities.getAdapter(fElement, ISharedDocumentAdapter.class);
793
			final ISharedDocumentAdapter sda = (ISharedDocumentAdapter) Utilities
794
					.getAdapter(fElement, ISharedDocumentAdapter.class);
761
			if (sda != null) {
795
			if (sda != null) {
762
				sda.disconnect(provider, input);
796
				sda.disconnect(provider, input);
763
			} else {
797
			} else {
Lines 771-781 Link Here
771
			fDocumentProvider = documentProvider;
805
			fDocumentProvider = documentProvider;
772
			documentProvider.addElementStateListener(this);
806
			documentProvider.addElementStateListener(this);
773
		}
807
		}
774
		
808
775
		public void disconnect() {
809
		public void disconnect() {
776
			IDocumentProvider provider = null;
810
			IDocumentProvider provider = null;
777
			IEditorInput input = getDocumentKey();
811
			IEditorInput input = getDocumentKey();
778
			synchronized(this) {
812
			synchronized (this) {
779
				if (fDocumentProvider != null) {
813
				if (fDocumentProvider != null) {
780
					provider = fDocumentProvider;
814
					provider = fDocumentProvider;
781
					fDocumentProvider = null;
815
					fDocumentProvider = null;
Lines 787-798 Link Here
787
				provider.removeElementStateListener(this);
821
				provider.removeElementStateListener(this);
788
			}
822
			}
789
			// If we have a listener registered with the widget, remove it
823
			// If we have a listener registered with the widget, remove it
790
			if (fSourceViewer != null && !fSourceViewer.getTextWidget().isDisposed()) {
824
			if (fSourceViewer != null
825
					&& !fSourceViewer.getTextWidget().isDisposed()) {
791
				if (fNeedsValidation) {
826
				if (fNeedsValidation) {
792
					fSourceViewer.getTextWidget().removeVerifyListener(this);
827
					fSourceViewer.getTextWidget().removeVerifyListener(this);
793
					fNeedsValidation = false;
828
					fNeedsValidation = false;
794
				}
829
				}
795
				IDocument oldDoc= internalGetDocument(fSourceViewer);
830
				IDocument oldDoc = internalGetDocument(fSourceViewer);
796
				if (oldDoc != null) {
831
				if (oldDoc != null) {
797
					oldDoc.removeDocumentListener(this);
832
					oldDoc.removeDocumentListener(this);
798
				}
833
				}
Lines 806-846 Link Here
806
			if (doc != null)
841
			if (doc != null)
807
				DocumentManager.remove(doc);
842
				DocumentManager.remove(doc);
808
		}
843
		}
809
		
844
810
		private IDocument internalGetDocument(MergeSourceViewer tp) {
845
		private IDocument internalGetDocument(MergeSourceViewer tp) {
811
			IDocument oldDoc= tp.getDocument();
846
			IDocument oldDoc = tp.getDocument();
812
			if (oldDoc == null) {
847
			if (oldDoc == null) {
813
				oldDoc= tp.getRememberedDocument();
848
				oldDoc = tp.getRememberedDocument();
814
			}
849
			}
815
			return oldDoc;
850
			return oldDoc;
816
		}
851
		}
817
		
852
818
		/**
853
		/**
819
		 * Return the document key used to obtain a shared document. A <code>null</code>
854
		 * Return the document key used to obtain a shared document. A
820
		 * is returned in the following cases:
855
		 * <code>null</code> is returned in the following cases:
821
		 * <ol>
856
		 * <ol>
822
		 * <li>This contributor does not have a shared document adapter.</li>
857
		 * <li>This contributor does not have a shared document adapter.</li>
823
		 * <li>This text merge viewer has a document partitioner but uses the default partitioning.</li>
858
		 * <li>This text merge viewer has a document partitioner but uses the
859
		 * default partitioning.</li>
824
		 * <li>This text merge viewer does not use he default content provider.</li>
860
		 * <li>This text merge viewer does not use he default content provider.</li>
825
		 * </ol>
861
		 * </ol>
826
		 * @return the document key used to obtain a shared document or <code>null</code>
862
		 * 
863
		 * @return the document key used to obtain a shared document or
864
		 *         <code>null</code>
827
		 */
865
		 */
828
		private IEditorInput getDocumentKey() {
866
		private IEditorInput getDocumentKey() {
829
			if (fDocumentKey != null)
867
			if (fDocumentKey != null)
830
				return fDocumentKey;
868
				return fDocumentKey;
831
			if (isUsingDefaultContentProvider() && fElement != null && canHaveSharedDocument()) {
869
			if (isUsingDefaultContentProvider() && fElement != null
832
				ISharedDocumentAdapter sda = (ISharedDocumentAdapter)Utilities.getAdapter(fElement, ISharedDocumentAdapter.class, true);
870
					&& canHaveSharedDocument()) {
871
				ISharedDocumentAdapter sda = (ISharedDocumentAdapter) Utilities
872
						.getAdapter(fElement, ISharedDocumentAdapter.class,
873
								true);
833
				if (sda != null) {
874
				if (sda != null) {
834
					return sda.getDocumentKey(fElement);
875
					return sda.getDocumentKey(fElement);
835
				}
876
				}
836
			}
877
			}
837
			return null;
878
			return null;
838
		}
879
		}
839
		
880
840
		private IDocumentProvider getDocumentProvider() {
881
		private IDocumentProvider getDocumentProvider() {
841
			if (fDocumentProvider != null)
882
			if (fDocumentProvider != null)
842
				return fDocumentProvider;
883
				return fDocumentProvider;
843
			// We will only use document providers if the content provider is the
884
			// We will only use document providers if the content provider is
885
			// the
844
			// default content provider
886
			// default content provider
845
			if (isUsingDefaultContentProvider()) {
887
			if (isUsingDefaultContentProvider()) {
846
				IEditorInput input = getDocumentKey();
888
				IEditorInput input = getDocumentKey();
Lines 853-882 Link Here
853
		private boolean isUsingDefaultContentProvider() {
895
		private boolean isUsingDefaultContentProvider() {
854
			return fViewer.isUsingDefaultContentProvider();
896
			return fViewer.isUsingDefaultContentProvider();
855
		}
897
		}
856
		
898
857
		private boolean canHaveSharedDocument() {
899
		private boolean canHaveSharedDocument() {
858
			return fViewer.canHaveSharedDocument();
900
			return fViewer.canHaveSharedDocument();
859
		}
901
		}
860
		
902
861
		boolean hasSharedDocument(Object object) {
903
		boolean hasSharedDocument(Object object) {
862
			return (fElement == object &&
904
			return (fElement == object && fDocumentProvider != null && fDocumentProvider
863
					fDocumentProvider != null
905
					.getDocument(getDocumentKey()) != null);
864
					&& fDocumentProvider.getDocument(getDocumentKey()) != null);
865
		}
906
		}
866
		
907
867
		public boolean flush() throws CoreException {
908
		public boolean flush() throws CoreException {
868
			if (fDocumentProvider != null) {
909
			if (fDocumentProvider != null) {
869
				IEditorInput input = getDocumentKey();
910
				IEditorInput input = getDocumentKey();
870
				IDocument document = fDocumentProvider.getDocument(input);
911
				IDocument document = fDocumentProvider.getDocument(input);
871
				if (document != null) {
912
				if (document != null) {
872
					final ISharedDocumentAdapter sda = (ISharedDocumentAdapter) Utilities.getAdapter(fElement, ISharedDocumentAdapter.class);
913
					final ISharedDocumentAdapter sda = (ISharedDocumentAdapter) Utilities
914
							.getAdapter(fElement, ISharedDocumentAdapter.class);
873
					if (sda != null) {
915
					if (sda != null) {
874
						sda.flushDocument(fDocumentProvider, input, document, false);
916
						sda.flushDocument(fDocumentProvider, input, document,
917
								false);
875
						return true;
918
						return true;
876
					}
919
					}
877
					try {
920
					try {
878
						fDocumentProvider.aboutToChange(input);
921
						fDocumentProvider.aboutToChange(input);
879
						fDocumentProvider.saveDocument(new NullProgressMonitor(), input, document, false);
922
						fDocumentProvider.saveDocument(
923
								new NullProgressMonitor(), input, document,
924
								false);
880
						return true;
925
						return true;
881
					} finally {
926
					} finally {
882
						fDocumentProvider.changed(input);
927
						fDocumentProvider.changed(input);
Lines 885-891 Link Here
885
			}
930
			}
886
			return false;
931
			return false;
887
		}
932
		}
888
		
933
889
		public void elementMoved(Object originalElement, Object movedElement) {
934
		public void elementMoved(Object originalElement, Object movedElement) {
890
			IEditorInput input = getDocumentKey();
935
			IEditorInput input = getDocumentKey();
891
			if (input != null && input.equals(originalElement)) {
936
			if (input != null && input.equals(originalElement)) {
Lines 893-904 Link Here
893
				resetDocument();
938
				resetDocument();
894
			}
939
			}
895
		}
940
		}
941
896
		public void elementDirtyStateChanged(Object element, boolean isDirty) {
942
		public void elementDirtyStateChanged(Object element, boolean isDirty) {
897
			if (!checkState())
943
			if (!checkState())
898
				return;
944
				return;
899
			IEditorInput input = getDocumentKey();
945
			IEditorInput input = getDocumentKey();
900
			if (input != null && input.equals(element)) {
946
			if (input != null && input.equals(element)) {
901
				this.fViewer.updateDirtyState(input, getDocumentProvider(), fLeg);
947
				this.fViewer.updateDirtyState(input, getDocumentProvider(),
948
						fLeg);
902
			}
949
			}
903
		}
950
		}
904
951
Lines 909-920 Link Here
909
				resetDocument();
956
				resetDocument();
910
			}
957
			}
911
		}
958
		}
959
912
		private void resetDocument() {
960
		private void resetDocument() {
913
			// Need to remove the document from the manager before refreshing
961
			// Need to remove the document from the manager before refreshing
914
			// or the old document will still be found
962
			// or the old document will still be found
915
			clearCachedDocument();
963
			clearCachedDocument();
916
			// TODO: This is fine for now but may need to be revisited if a refresh is performed
964
			// TODO: This is fine for now but may need to be revisited if a
917
			// higher up as well (e.g. perhaps a refresh request that waits until after all parties
965
			// refresh is performed
966
			// higher up as well (e.g. perhaps a refresh request that waits
967
			// until after all parties
918
			// have been notified).
968
			// have been notified).
919
			if (checkState())
969
			if (checkState())
920
				fViewer.refresh();
970
				fViewer.refresh();
Lines 934-942 Link Here
934
				return;
984
				return;
935
			IEditorInput input = getDocumentKey();
985
			IEditorInput input = getDocumentKey();
936
			if (input != null && input.equals(element)) {
986
			if (input != null && input.equals(element)) {
937
				this.fViewer.updateDirtyState(input, getDocumentProvider(), fLeg);
987
				this.fViewer.updateDirtyState(input, getDocumentProvider(),
988
						fLeg);
938
			}
989
			}
939
		}
990
		}
991
940
		public void elementContentAboutToBeReplaced(Object element) {
992
		public void elementContentAboutToBeReplaced(Object element) {
941
			// Nothing to do
993
			// Nothing to do
942
		}
994
		}
Lines 955-961 Link Here
955
			}
1007
			}
956
		}
1008
		}
957
1009
958
		public void updateSelection(MergeSourceViewer viewer, boolean includeScroll) {
1010
		public void updateSelection(MergeSourceViewer viewer,
1011
				boolean includeScroll) {
959
			if (fSelection != null)
1012
			if (fSelection != null)
960
				viewer.setSelection(fSelection);
1013
				viewer.setSelection(fSelection);
961
			if (includeScroll && fTopIndex != -1) {
1014
			if (includeScroll && fTopIndex != -1) {
Lines 963-1000 Link Here
963
			}
1016
			}
964
		}
1017
		}
965
1018
966
		public void transferContributorStateFrom(
1019
		public void transferContributorStateFrom(ContributorInfo oldContributor) {
967
				ContributorInfo oldContributor) {
968
			if (oldContributor != null) {
1020
			if (oldContributor != null) {
969
				fSelection = oldContributor.fSelection;
1021
				fSelection = oldContributor.fSelection;
970
				fTopIndex = oldContributor.fTopIndex;
1022
				fTopIndex = oldContributor.fTopIndex;
971
			}
1023
			}
972
				
1024
973
		}
1025
		}
974
1026
975
		public boolean validateChange() {
1027
		public boolean validateChange() {
976
			if (fElement == null)
1028
			if (fElement == null)
977
				return true;
1029
				return true;
978
			if (fDocumentProvider instanceof IDocumentProviderExtension) {
1030
			if (fDocumentProvider instanceof IDocumentProviderExtension) {
979
				IDocumentProviderExtension ext = (IDocumentProviderExtension)fDocumentProvider;
1031
				IDocumentProviderExtension ext = (IDocumentProviderExtension) fDocumentProvider;
980
				if (ext.isReadOnly(fDocumentKey)) {
1032
				if (ext.isReadOnly(fDocumentKey)) {
981
					try {
1033
					try {
982
						ext.validateState(fDocumentKey, getControl().getShell());
1034
						ext
1035
								.validateState(fDocumentKey, getControl()
1036
										.getShell());
983
						ext.updateStateCache(fDocumentKey);
1037
						ext.updateStateCache(fDocumentKey);
984
					} catch (CoreException e) {
1038
					} catch (CoreException e) {
985
						ErrorDialog.openError(getControl().getShell(), CompareMessages.TextMergeViewer_12, CompareMessages.TextMergeViewer_13, e.getStatus());
1039
						ErrorDialog.openError(getControl().getShell(),
1040
								CompareMessages.TextMergeViewer_12,
1041
								CompareMessages.TextMergeViewer_13, e
1042
										.getStatus());
986
						return false;
1043
						return false;
987
					}
1044
					}
988
				}
1045
				}
989
				return !ext.isReadOnly(fDocumentKey);
1046
				return !ext.isReadOnly(fDocumentKey);
990
			}
1047
			}
991
			IEditableContentExtension ext = (IEditableContentExtension)Utilities.getAdapter(fElement, IEditableContentExtension.class);
1048
			IEditableContentExtension ext = (IEditableContentExtension) Utilities
1049
					.getAdapter(fElement, IEditableContentExtension.class);
992
			if (ext != null) {
1050
			if (ext != null) {
993
				if (ext.isReadOnly()) {
1051
				if (ext.isReadOnly()) {
994
					IStatus status = ext.validateEdit(getControl().getShell());
1052
					IStatus status = ext.validateEdit(getControl().getShell());
995
					if (!status.isOK()) {
1053
					if (!status.isOK()) {
996
						if (status.getSeverity() == IStatus.ERROR) {
1054
						if (status.getSeverity() == IStatus.ERROR) {
997
							ErrorDialog.openError(getControl().getShell(), CompareMessages.TextMergeViewer_14, CompareMessages.TextMergeViewer_15, status);
1055
							ErrorDialog.openError(getControl().getShell(),
1056
									CompareMessages.TextMergeViewer_14,
1057
									CompareMessages.TextMergeViewer_15, status);
998
							return false;
1058
							return false;
999
						}
1059
						}
1000
						if (status.getSeverity() == IStatus.CANCEL)
1060
						if (status.getSeverity() == IStatus.CANCEL)
Lines 1005-1028 Link Here
1005
			return true;
1065
			return true;
1006
		}
1066
		}
1007
1067
1008
		/* (non-Javadoc)
1068
		/*
1009
		 * @see org.eclipse.swt.events.VerifyListener#verifyText(org.eclipse.swt.events.VerifyEvent)
1069
		 * (non-Javadoc)
1070
		 * 
1071
		 * @see
1072
		 * org.eclipse.swt.events.VerifyListener#verifyText(org.eclipse.swt.
1073
		 * events.VerifyEvent)
1010
		 */
1074
		 */
1011
		public void verifyText(VerifyEvent e) {
1075
		public void verifyText(VerifyEvent e) {
1012
			if (!validateChange()) {
1076
			if (!validateChange()) {
1013
				e.doit= false;
1077
				e.doit = false;
1014
			}
1078
			}
1015
		}
1079
		}
1016
		
1080
1017
		/* (non-Javadoc)
1081
		/*
1018
		 * @see org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged(org.eclipse.jface.text.DocumentEvent)
1082
		 * (non-Javadoc)
1083
		 * 
1084
		 * @see
1085
		 * org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged
1086
		 * (org.eclipse.jface.text.DocumentEvent)
1019
		 */
1087
		 */
1020
		public void documentAboutToBeChanged(DocumentEvent e) {
1088
		public void documentAboutToBeChanged(DocumentEvent e) {
1021
			// nothing to do
1089
			// nothing to do
1022
		}
1090
		}
1023
		
1091
1024
		/* (non-Javadoc)
1092
		/*
1025
		 * @see org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse.jface.text.DocumentEvent)
1093
		 * (non-Javadoc)
1094
		 * 
1095
		 * @see
1096
		 * org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse
1097
		 * .jface.text.DocumentEvent)
1026
		 */
1098
		 */
1027
		public void documentChanged(DocumentEvent e) {
1099
		public void documentChanged(DocumentEvent e) {
1028
			boolean dirty = true;
1100
			boolean dirty = true;
Lines 1031-1110 Link Here
1031
			}
1103
			}
1032
			TextMergeViewer.this.documentChanged(e, dirty);
1104
			TextMergeViewer.this.documentChanged(e, dirty);
1033
			// Remove our verify listener since the document is now dirty
1105
			// Remove our verify listener since the document is now dirty
1034
			if (fNeedsValidation && fSourceViewer != null && !fSourceViewer.getTextWidget().isDisposed()) {
1106
			if (fNeedsValidation && fSourceViewer != null
1107
					&& !fSourceViewer.getTextWidget().isDisposed()) {
1035
				fSourceViewer.getTextWidget().removeVerifyListener(this);
1108
				fSourceViewer.getTextWidget().removeVerifyListener(this);
1036
				fNeedsValidation = false;
1109
				fNeedsValidation = false;
1037
			}
1110
			}
1038
		}
1111
		}
1039
	}
1112
	}
1040
	
1113
1041
	class HeaderPainter implements PaintListener {
1114
	class HeaderPainter implements PaintListener {
1042
		
1115
1043
		private static final int INSET= BIRDS_EYE_VIEW_INSET;
1116
		private static final int INSET = BIRDS_EYE_VIEW_INSET;
1044
1117
1045
		private RGB fIndicatorColor;
1118
		private RGB fIndicatorColor;
1046
		private Color fSeparatorColor;
1119
		private Color fSeparatorColor;
1047
		
1120
1048
		public HeaderPainter() {
1121
		public HeaderPainter() {
1049
			fSeparatorColor= fSummaryHeader.getDisplay().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
1122
			fSeparatorColor = fSummaryHeader.getDisplay().getSystemColor(
1123
					SWT.COLOR_WIDGET_NORMAL_SHADOW);
1050
		}
1124
		}
1051
		
1125
1052
		/*
1126
		/*
1053
		 * Returns true on color change
1127
		 * Returns true on color change
1054
		 */
1128
		 */
1055
		public boolean setColor(RGB color) {
1129
		public boolean setColor(RGB color) {
1056
			RGB oldColor= fIndicatorColor;
1130
			RGB oldColor = fIndicatorColor;
1057
			fIndicatorColor= color;
1131
			fIndicatorColor = color;
1058
			if (color == null)
1132
			if (color == null)
1059
				return oldColor != null;
1133
				return oldColor != null;
1060
			if (oldColor != null)
1134
			if (oldColor != null)
1061
				return !color.equals(oldColor);
1135
				return !color.equals(oldColor);
1062
			return true;
1136
			return true;
1063
		}
1137
		}
1064
		
1138
1065
		private void drawBevelRect(GC gc, int x, int y, int w, int h, Color topLeft, Color bottomRight) {
1139
		private void drawBevelRect(GC gc, int x, int y, int w, int h,
1140
				Color topLeft, Color bottomRight) {
1066
			gc.setForeground(topLeft);
1141
			gc.setForeground(topLeft);
1067
			gc.drawLine(x, y, x + w -1, y);
1142
			gc.drawLine(x, y, x + w - 1, y);
1068
			gc.drawLine(x, y, x, y + h -1);
1143
			gc.drawLine(x, y, x, y + h - 1);
1069
		
1144
1070
			gc.setForeground(bottomRight);
1145
			gc.setForeground(bottomRight);
1071
			gc.drawLine(x + w, y, x + w, y + h);
1146
			gc.drawLine(x + w, y, x + w, y + h);
1072
			gc.drawLine(x, y + h, x + w, y + h);
1147
			gc.drawLine(x, y + h, x + w, y + h);
1073
		}
1148
		}
1074
		
1149
1075
		public void paintControl(PaintEvent e) {
1150
		public void paintControl(PaintEvent e) {
1076
			
1151
1077
			Point s= fSummaryHeader.getSize();
1152
			Point s = fSummaryHeader.getSize();
1078
			
1153
1079
			if (fIndicatorColor != null) {
1154
			if (fIndicatorColor != null) {
1080
				Display d= fSummaryHeader.getDisplay();
1155
				Display d = fSummaryHeader.getDisplay();
1081
				e.gc.setBackground(getColor(d, fIndicatorColor));
1156
				e.gc.setBackground(getColor(d, fIndicatorColor));
1082
				int min= Math.min(s.x, s.y)-2*INSET;
1157
				int min = Math.min(s.x, s.y) - 2 * INSET;
1083
				Rectangle r= new Rectangle((s.x-min)/2, (s.y-min)/2, min, min);
1158
				Rectangle r = new Rectangle((s.x - min) / 2, (s.y - min) / 2,
1159
						min, min);
1084
				e.gc.fillRectangle(r);
1160
				e.gc.fillRectangle(r);
1085
				if (d != null)
1161
				if (d != null)
1086
					drawBevelRect(e.gc, r.x, r.y, r.width -1, r.height -1, d.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW), d.getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW));
1162
					drawBevelRect(e.gc, r.x, r.y, r.width - 1, r.height - 1, d
1163
							.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW), d
1164
							.getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW));
1087
1165
1088
				e.gc.setForeground(fSeparatorColor);
1166
				e.gc.setForeground(fSeparatorColor);
1089
				e.gc.setLineWidth(0 /* 1 */);
1167
				e.gc.setLineWidth(0 /* 1 */);
1090
				e.gc.drawLine(0+1, s.y-1, s.x-1-1, s.y-1);
1168
				e.gc.drawLine(0 + 1, s.y - 1, s.x - 1 - 1, s.y - 1);
1091
			}
1169
			}
1092
		}
1170
		}
1093
	}
1171
	}
1094
1172
1095
	/*
1173
	/*
1096
	 * The position updater used to adapt the positions representing
1174
	 * The position updater used to adapt the positions representing the child
1097
	 * the child document ranges to changes of the parent document.
1175
	 * document ranges to changes of the parent document.
1098
	 */
1176
	 */
1099
	class ChildPositionUpdater extends DefaultPositionUpdater {
1177
	class ChildPositionUpdater extends DefaultPositionUpdater {
1100
		
1178
1101
		/*
1179
		/*
1102
		 * Creates the position updated.
1180
		 * Creates the position updated.
1103
		 */
1181
		 */
1104
		protected ChildPositionUpdater(String category) {
1182
		protected ChildPositionUpdater(String category) {
1105
			super(category);
1183
			super(category);
1106
		}
1184
		}
1107
		
1185
1108
		/*
1186
		/*
1109
		 * Child document ranges cannot be deleted other then by calling
1187
		 * Child document ranges cannot be deleted other then by calling
1110
		 * freeChildDocument.
1188
		 * freeChildDocument.
Lines 1112-1118 Link Here
1112
		protected boolean notDeleted() {
1190
		protected boolean notDeleted() {
1113
			return true;
1191
			return true;
1114
		}
1192
		}
1115
		
1193
1116
		/*
1194
		/*
1117
		 * If an insertion happens at a child document's start offset, the
1195
		 * If an insertion happens at a child document's start offset, the
1118
		 * position is extended rather than shifted. Also, if something is added
1196
		 * position is extended rather than shifted. Also, if something is added
Lines 1120-1138 Link Here
1120
		 * than kept stable.
1198
		 * than kept stable.
1121
		 */
1199
		 */
1122
		protected void adaptToInsert() {
1200
		protected void adaptToInsert() {
1123
			
1201
1124
			if (fPosition == fLeft.getRegion() || fPosition == fRight.getRegion()) {
1202
			if (fPosition == fLeft.getRegion()
1125
				int myStart= fPosition.offset;
1203
					|| fPosition == fRight.getRegion()) {
1126
				int myEnd=   fPosition.offset + fPosition.length;
1204
				int myStart = fPosition.offset;
1127
				myEnd= Math.max(myStart, myEnd);
1205
				int myEnd = fPosition.offset + fPosition.length;
1128
				
1206
				myEnd = Math.max(myStart, myEnd);
1129
				int yoursStart= fOffset;
1207
1130
				int yoursEnd=   fOffset + fReplaceLength -1;
1208
				int yoursStart = fOffset;
1131
				yoursEnd= Math.max(yoursStart, yoursEnd);
1209
				int yoursEnd = fOffset + fReplaceLength - 1;
1132
				
1210
				yoursEnd = Math.max(yoursStart, yoursEnd);
1211
1133
				if (myEnd < yoursStart)
1212
				if (myEnd < yoursStart)
1134
					return;
1213
					return;
1135
				
1214
1136
				if (myStart <= yoursStart)
1215
				if (myStart <= yoursStart)
1137
					fPosition.length += fReplaceLength;
1216
					fPosition.length += fReplaceLength;
1138
				else
1217
				else
Lines 1142-1148 Link Here
1142
			}
1221
			}
1143
		}
1222
		}
1144
	}
1223
	}
1145
	
1224
1146
	private class ChangeHighlighter implements ITextPresentationListener {
1225
	private class ChangeHighlighter implements ITextPresentationListener {
1147
1226
1148
		private final MergeSourceViewer viewer;
1227
		private final MergeSourceViewer viewer;
Lines 1151-1163 Link Here
1151
			this.viewer = viewer;
1230
			this.viewer = viewer;
1152
		}
1231
		}
1153
1232
1154
		/* (non-Javadoc)
1233
		/*
1155
		 * @see org.eclipse.jface.text.ITextPresentationListener#applyTextPresentation(org.eclipse.jface.text.TextPresentation)
1234
		 * (non-Javadoc)
1235
		 * 
1236
		 * @see
1237
		 * org.eclipse.jface.text.ITextPresentationListener#applyTextPresentation
1238
		 * (org.eclipse.jface.text.TextPresentation)
1156
		 */
1239
		 */
1157
		public void applyTextPresentation(TextPresentation textPresentation) {
1240
		public void applyTextPresentation(TextPresentation textPresentation) {
1158
			if (!fHighlightTokenChanges)
1241
			if (!fHighlightTokenChanges)
1159
				return;
1242
				return;
1160
			IRegion region= textPresentation.getExtent();
1243
			IRegion region = textPresentation.getExtent();
1161
			Diff[] changeDiffs = fMerger.getChangeDiffs(getLeg(viewer), region);
1244
			Diff[] changeDiffs = fMerger.getChangeDiffs(getLeg(viewer), region);
1162
			for (int i = 0; i < changeDiffs.length; i++) {
1245
			for (int i = 0; i < changeDiffs.length; i++) {
1163
				Diff diff = changeDiffs[i];
1246
				Diff diff = changeDiffs[i];
Lines 1168-1174 Link Here
1168
		}
1251
		}
1169
1252
1170
		private StyleRange getStyleRange(Diff diff, IRegion region) {
1253
		private StyleRange getStyleRange(Diff diff, IRegion region) {
1171
			//Color cText = getColor(null, getTextColor());
1254
			// Color cText = getColor(null, getTextColor());
1172
			Color cTextFill = getColor(null, getTextFillColor(diff));
1255
			Color cTextFill = getColor(null, getTextFillColor(diff));
1173
			if (cTextFill == null)
1256
			if (cTextFill == null)
1174
				return null;
1257
				return null;
Lines 1187-1196 Link Here
1187
			}
1270
			}
1188
			if (length < 0)
1271
			if (length < 0)
1189
				return null;
1272
				return null;
1190
			
1273
1191
			return new StyleRange(start, length, null, cTextFill);
1274
			return new StyleRange(start, length, null, cTextFill);
1192
		}
1275
		}
1193
		
1276
1194
		private RGB getTextFillColor(Diff diff) {
1277
		private RGB getTextFillColor(Diff diff) {
1195
			if (isThreeWay() && !isIgnoreAncestor()) {
1278
			if (isThreeWay() && !isIgnoreAncestor()) {
1196
				switch (diff.getKind()) {
1279
				switch (diff.getKind()) {
Lines 1211-1219 Link Here
1211
			}
1294
			}
1212
			return OUTGOING_TEXT_FILL;
1295
			return OUTGOING_TEXT_FILL;
1213
		}
1296
		}
1214
		
1297
1215
	}
1298
	}
1216
	
1299
1217
	private class FindReplaceTarget implements IFindReplaceTarget {
1300
	private class FindReplaceTarget implements IFindReplaceTarget {
1218
1301
1219
		public boolean canPerformFind() {
1302
		public boolean canPerformFind() {
Lines 1222-1228 Link Here
1222
1305
1223
		public int findAndSelect(int widgetOffset, String findString,
1306
		public int findAndSelect(int widgetOffset, String findString,
1224
				boolean searchForward, boolean caseSensitive, boolean wholeWord) {
1307
				boolean searchForward, boolean caseSensitive, boolean wholeWord) {
1225
			return fFocusPart.getFindReplaceTarget().findAndSelect(widgetOffset, findString, searchForward, caseSensitive, wholeWord);
1308
			return fFocusPart.getFindReplaceTarget().findAndSelect(
1309
					widgetOffset, findString, searchForward, caseSensitive,
1310
					wholeWord);
1226
		}
1311
		}
1227
1312
1228
		public Point getSelection() {
1313
		public Point getSelection() {
Lines 1240-1277 Link Here
1240
		public void replaceSelection(String text) {
1325
		public void replaceSelection(String text) {
1241
			fFocusPart.getFindReplaceTarget().replaceSelection(text);
1326
			fFocusPart.getFindReplaceTarget().replaceSelection(text);
1242
		}
1327
		}
1243
		
1328
1244
	}
1329
	}
1245
1330
1246
	//---- MergeTextViewer
1331
	// ---- MergeTextViewer
1247
	
1332
1248
	/**
1333
	/**
1249
	 * Creates a text merge viewer under the given parent control.
1334
	 * Creates a text merge viewer under the given parent control.
1250
	 *
1335
	 * 
1251
	 * @param parent the parent control
1336
	 * @param parent
1252
	 * @param configuration the configuration object
1337
	 *            the parent control
1338
	 * @param configuration
1339
	 *            the configuration object
1253
	 */
1340
	 */
1254
	public TextMergeViewer(Composite parent, CompareConfiguration configuration) {
1341
	public TextMergeViewer(Composite parent, CompareConfiguration configuration) {
1255
		this(parent, SWT.NULL, configuration);
1342
		this(parent, SWT.NULL, configuration);
1256
	}
1343
	}
1257
	
1344
1258
	/**
1345
	/**
1259
	 * Creates a text merge viewer under the given parent control.
1346
	 * Creates a text merge viewer under the given parent control.
1260
	 *
1347
	 * 
1261
	 * @param parent the parent control
1348
	 * @param parent
1262
	 * @param style SWT style bits for top level composite of this viewer
1349
	 *            the parent control
1263
	 * @param configuration the configuration object
1350
	 * @param style
1351
	 *            SWT style bits for top level composite of this viewer
1352
	 * @param configuration
1353
	 *            the configuration object
1264
	 */
1354
	 */
1265
	public TextMergeViewer(Composite parent, int style, CompareConfiguration configuration) {
1355
	public TextMergeViewer(Composite parent, int style,
1356
			CompareConfiguration configuration) {
1266
		super(style, ResourceBundle.getBundle(BUNDLE_NAME), configuration);
1357
		super(style, ResourceBundle.getBundle(BUNDLE_NAME), configuration);
1267
		
1358
1268
		fMerger = new DocumentMerger(new IDocumentMergerInput() {
1359
		fMerger = new DocumentMerger(new IDocumentMergerInput() {
1269
			public ITokenComparator createTokenComparator(String line) {
1360
			public ITokenComparator createTokenComparator(String line) {
1270
				return TextMergeViewer.this.createTokenComparator(line);
1361
				return TextMergeViewer.this.createTokenComparator(line);
1271
			}
1362
			}
1363
1272
			public CompareConfiguration getCompareConfiguration() {
1364
			public CompareConfiguration getCompareConfiguration() {
1273
				return TextMergeViewer.this.getCompareConfiguration();
1365
				return TextMergeViewer.this.getCompareConfiguration();
1274
			}
1366
			}
1367
1275
			public IDocument getDocument(char contributor) {
1368
			public IDocument getDocument(char contributor) {
1276
				switch (contributor) {
1369
				switch (contributor) {
1277
				case LEFT_CONTRIBUTOR:
1370
				case LEFT_CONTRIBUTOR:
Lines 1283-1291 Link Here
1283
				}
1376
				}
1284
				return null;
1377
				return null;
1285
			}
1378
			}
1379
1286
			public int getHunkStart() {
1380
			public int getHunkStart() {
1287
				return TextMergeViewer.this.getHunkStart();
1381
				return TextMergeViewer.this.getHunkStart();
1288
			}
1382
			}
1383
1289
			public Position getRegion(char contributor) {
1384
			public Position getRegion(char contributor) {
1290
				switch (contributor) {
1385
				switch (contributor) {
1291
				case LEFT_CONTRIBUTOR:
1386
				case LEFT_CONTRIBUTOR:
Lines 1297-1309 Link Here
1297
				}
1392
				}
1298
				return null;
1393
				return null;
1299
			}
1394
			}
1395
1300
			public boolean isHunkOnLeft() {
1396
			public boolean isHunkOnLeft() {
1301
				ITypedElement left = ((ICompareInput)getInput()).getRight();
1397
				ITypedElement left = ((ICompareInput) getInput()).getRight();
1302
				return left != null && Utilities.getAdapter(left, IHunk.class) != null;
1398
				return left != null
1399
						&& Utilities.getAdapter(left, IHunk.class) != null;
1303
			}
1400
			}
1401
1304
			public boolean isIgnoreAncestor() {
1402
			public boolean isIgnoreAncestor() {
1305
				return TextMergeViewer.this.isIgnoreAncestor();
1403
				return TextMergeViewer.this.isIgnoreAncestor();
1306
			}
1404
			}
1405
1307
			public boolean isPatchHunk() {
1406
			public boolean isPatchHunk() {
1308
				return TextMergeViewer.this.isPatchHunk();
1407
				return TextMergeViewer.this.isPatchHunk();
1309
			}
1408
			}
Lines 1311-1412 Link Here
1311
			public boolean isShowPseudoConflicts() {
1410
			public boolean isShowPseudoConflicts() {
1312
				return fShowPseudoConflicts;
1411
				return fShowPseudoConflicts;
1313
			}
1412
			}
1413
1314
			public boolean isThreeWay() {
1414
			public boolean isThreeWay() {
1315
				return TextMergeViewer.this.isThreeWay();
1415
				return TextMergeViewer.this.isThreeWay();
1316
			}
1416
			}
1417
1317
			public boolean isPatchHunkOk() {
1418
			public boolean isPatchHunkOk() {
1318
				return TextMergeViewer.this.isPatchHunkOk();
1419
				return TextMergeViewer.this.isPatchHunkOk();
1319
			}
1420
			}
1320
			
1421
1321
		});
1422
		});
1322
		
1423
1323
		int inheritedStyle= parent.getStyle();
1424
		int inheritedStyle = parent.getStyle();
1324
		if ((inheritedStyle & SWT.LEFT_TO_RIGHT) != 0)
1425
		if ((inheritedStyle & SWT.LEFT_TO_RIGHT) != 0)
1325
			fInheritedDirection= SWT.LEFT_TO_RIGHT;
1426
			fInheritedDirection = SWT.LEFT_TO_RIGHT;
1326
		else if ((inheritedStyle & SWT.RIGHT_TO_LEFT) != 0)
1427
		else if ((inheritedStyle & SWT.RIGHT_TO_LEFT) != 0)
1327
			fInheritedDirection= SWT.RIGHT_TO_LEFT;
1428
			fInheritedDirection = SWT.RIGHT_TO_LEFT;
1328
		else
1429
		else
1329
			fInheritedDirection= SWT.NONE;
1430
			fInheritedDirection = SWT.NONE;
1330
		
1431
1331
		if ((style & SWT.LEFT_TO_RIGHT) != 0)
1432
		if ((style & SWT.LEFT_TO_RIGHT) != 0)
1332
			fTextDirection= SWT.LEFT_TO_RIGHT;
1433
			fTextDirection = SWT.LEFT_TO_RIGHT;
1333
		else if ((style & SWT.RIGHT_TO_LEFT) != 0)
1434
		else if ((style & SWT.RIGHT_TO_LEFT) != 0)
1334
			fTextDirection= SWT.RIGHT_TO_LEFT;
1435
			fTextDirection = SWT.RIGHT_TO_LEFT;
1335
		else
1436
		else
1336
			fTextDirection= SWT.NONE;
1437
			fTextDirection = SWT.NONE;
1337
		
1438
1338
		fSymbolicFontName= getSymbolicFontName();
1439
		fSymbolicFontName = getSymbolicFontName();
1339
		
1440
1340
		String platform= SWT.getPlatform();
1441
		String platform = SWT.getPlatform();
1341
		fIsMotif= "motif".equals(platform); //$NON-NLS-1$
1442
		fIsMotif = "motif".equals(platform); //$NON-NLS-1$
1342
		fIsCarbon= "carbon".equals(platform); //$NON-NLS-1$
1443
		fIsCarbon = "carbon".equals(platform); //$NON-NLS-1$
1343
		
1444
1344
		if (fIsMotif)
1445
		if (fIsMotif)
1345
			fMarginWidth= 0;
1446
			fMarginWidth = 0;
1346
		
1447
1347
		fPreferenceChangeListener= new IPropertyChangeListener() {
1448
		fPreferenceChangeListener = new IPropertyChangeListener() {
1348
			public void propertyChange(PropertyChangeEvent event) {
1449
			public void propertyChange(PropertyChangeEvent event) {
1349
				TextMergeViewer.this.handlePropertyChangeEvent(event);
1450
				TextMergeViewer.this.handlePropertyChangeEvent(event);
1350
			}
1451
			}
1351
		};
1452
		};
1352
1453
1353
		fPreferenceStore= createChainedPreferenceStore();
1454
		fPreferenceStore = createChainedPreferenceStore();
1354
		if (fPreferenceStore != null) {
1455
		if (fPreferenceStore != null) {
1355
			fPreferenceStore.addPropertyChangeListener(fPreferenceChangeListener);
1456
			fPreferenceStore
1356
			
1457
					.addPropertyChangeListener(fPreferenceChangeListener);
1357
			fLeftIsLocal= Utilities.getBoolean(getCompareConfiguration(), "LEFT_IS_LOCAL", false); //$NON-NLS-1$
1458
1358
			fSynchronizedScrolling= fPreferenceStore.getBoolean(ComparePreferencePage.SYNCHRONIZE_SCROLLING);
1459
			fLeftIsLocal = Utilities.getBoolean(getCompareConfiguration(),
1359
			fShowMoreInfo= fPreferenceStore.getBoolean(ComparePreferencePage.SHOW_MORE_INFO);
1460
					"LEFT_IS_LOCAL", false); //$NON-NLS-1$
1360
			fShowPseudoConflicts= fPreferenceStore.getBoolean(ComparePreferencePage.SHOW_PSEUDO_CONFLICTS);
1461
			fSynchronizedScrolling = fPreferenceStore
1361
			//fUseSplines= fPreferenceStore.getBoolean(ComparePreferencePage.USE_SPLINES);
1462
					.getBoolean(ComparePreferencePage.SYNCHRONIZE_SCROLLING);
1362
			fUseSingleLine= fPreferenceStore.getBoolean(ComparePreferencePage.USE_SINGLE_LINE);
1463
			fShowMoreInfo = fPreferenceStore
1363
			fHighlightTokenChanges= fPreferenceStore.getBoolean(ComparePreferencePage.HIGHLIGHT_TOKEN_CHANGES);
1464
					.getBoolean(ComparePreferencePage.SHOW_MORE_INFO);
1364
			//fUseResolveUI= fPreferenceStore.getBoolean(ComparePreferencePage.USE_RESOLVE_UI);
1465
			fShowPseudoConflicts = fPreferenceStore
1466
					.getBoolean(ComparePreferencePage.SHOW_PSEUDO_CONFLICTS);
1467
			// fUseSplines=
1468
			// fPreferenceStore.getBoolean(ComparePreferencePage.USE_SPLINES);
1469
			fUseSingleLine = fPreferenceStore
1470
					.getBoolean(ComparePreferencePage.USE_SINGLE_LINE);
1471
			fHighlightTokenChanges = fPreferenceStore
1472
					.getBoolean(ComparePreferencePage.HIGHLIGHT_TOKEN_CHANGES);
1473
			// fUseResolveUI=
1474
			// fPreferenceStore.getBoolean(ComparePreferencePage.USE_RESOLVE_UI);
1365
		}
1475
		}
1366
		
1476
1367
		buildControl(parent);
1477
		buildControl(parent);
1368
		
1478
1369
		setColors();
1479
		setColors();
1370
1480
1371
		INavigatable nav= new INavigatable() {
1481
		INavigatable nav = new INavigatable() {
1372
			public boolean selectChange(int flag) {
1482
			public boolean selectChange(int flag) {
1373
				if (flag == INavigatable.FIRST_CHANGE || flag == INavigatable.LAST_CHANGE) {
1483
				if (flag == INavigatable.FIRST_CHANGE
1484
						|| flag == INavigatable.LAST_CHANGE) {
1374
					selectFirstDiff(flag == INavigatable.FIRST_CHANGE);
1485
					selectFirstDiff(flag == INavigatable.FIRST_CHANGE);
1375
					return false;
1486
					return false;
1376
				}
1487
				}
1377
				return navigate(flag == INavigatable.NEXT_CHANGE, false, false);
1488
				return navigate(flag == INavigatable.NEXT_CHANGE, false, false);
1378
			}
1489
			}
1490
1379
			public Object getInput() {
1491
			public Object getInput() {
1380
				return TextMergeViewer.this.getInput();
1492
				return TextMergeViewer.this.getInput();
1381
			}
1493
			}
1494
1382
			public boolean openSelectedChange() {
1495
			public boolean openSelectedChange() {
1383
				return false;
1496
				return false;
1384
			}
1497
			}
1498
1385
			public boolean hasChange(int flag) {
1499
			public boolean hasChange(int flag) {
1386
				return getNextVisibleDiff(flag == INavigatable.NEXT_CHANGE, false) != null;
1500
				return getNextVisibleDiff(flag == INavigatable.NEXT_CHANGE,
1501
						false) != null;
1387
			}
1502
			}
1388
		};
1503
		};
1389
		fComposite.setData(INavigatable.NAVIGATOR_PROPERTY, nav);
1504
		fComposite.setData(INavigatable.NAVIGATOR_PROPERTY, nav);
1390
		
1505
1391
		fBirdsEyeCursor= new Cursor(parent.getDisplay(), SWT.CURSOR_HAND);
1506
		fBirdsEyeCursor = new Cursor(parent.getDisplay(), SWT.CURSOR_HAND);
1392
		
1507
1393
		JFaceResources.getFontRegistry().addListener(fPreferenceChangeListener);
1508
		JFaceResources.getFontRegistry().addListener(fPreferenceChangeListener);
1394
		JFaceResources.getColorRegistry().addListener(fPreferenceChangeListener);
1509
		JFaceResources.getColorRegistry()
1510
				.addListener(fPreferenceChangeListener);
1395
		updateFont();
1511
		updateFont();
1396
	}
1512
	}
1397
	
1513
1398
	private ChainedPreferenceStore createChainedPreferenceStore() {
1514
	private ChainedPreferenceStore createChainedPreferenceStore() {
1399
    	ArrayList stores= new ArrayList(2);
1515
		ArrayList stores = new ArrayList(2);
1400
		stores.add(getCompareConfiguration().getPreferenceStore());
1516
		stores.add(getCompareConfiguration().getPreferenceStore());
1401
		stores.add(EditorsUI.getPreferenceStore());
1517
		stores.add(EditorsUI.getPreferenceStore());
1402
		return new ChainedPreferenceStore((IPreferenceStore[]) stores.toArray(new IPreferenceStore[stores.size()]));
1518
		return new ChainedPreferenceStore((IPreferenceStore[]) stores
1403
    }
1519
				.toArray(new IPreferenceStore[stores.size()]));
1404
	
1520
	}
1521
1405
	/**
1522
	/**
1406
	 * Creates a color from the information stored in the given preference store.
1523
	 * Creates a color from the information stored in the given preference
1407
	 * Returns <code>null</code> if there is no such information available.
1524
	 * store. Returns <code>null</code> if there is no such information
1408
	 * @param store preference store
1525
	 * available.
1409
	 * @param key preference key
1526
	 * 
1527
	 * @param store
1528
	 *            preference store
1529
	 * @param key
1530
	 *            preference key
1410
	 * @return the color or <code>null</code>
1531
	 * @return the color or <code>null</code>
1411
	 */
1532
	 */
1412
	private static RGB createColor(IPreferenceStore store, String key) {
1533
	private static RGB createColor(IPreferenceStore store, String key) {
Lines 1418-1448 Link Here
1418
	}
1539
	}
1419
1540
1420
	private void setColors() {
1541
	private void setColors() {
1421
		fIsUsingSystemBackground= fPreferenceStore.getBoolean(AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT);
1542
		fIsUsingSystemBackground = fPreferenceStore
1543
				.getBoolean(AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT);
1422
		if (!fIsUsingSystemBackground)
1544
		if (!fIsUsingSystemBackground)
1423
			fBackground= createColor(fPreferenceStore, AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND);
1545
			fBackground = createColor(fPreferenceStore,
1546
					AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND);
1424
1547
1425
		fIsUsingSystemForeground= fPreferenceStore.getBoolean(AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT);
1548
		fIsUsingSystemForeground = fPreferenceStore
1549
				.getBoolean(AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT);
1426
		if (!fIsUsingSystemForeground)
1550
		if (!fIsUsingSystemForeground)
1427
			fForeground= createColor(fPreferenceStore, AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND);
1551
			fForeground = createColor(fPreferenceStore,
1552
					AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND);
1428
1553
1429
		updateColors(null);
1554
		updateColors(null);
1430
	}
1555
	}
1431
1556
1432
	private String getSymbolicFontName() {
1557
	private String getSymbolicFontName() {
1433
		Class clazz= getClass();
1558
		Class clazz = getClass();
1434
		do {
1559
		do {
1435
			String fontName= clazz.getName();
1560
			String fontName = clazz.getName();
1436
			if (JFaceResources.getFontRegistry().hasValueFor(fontName))
1561
			if (JFaceResources.getFontRegistry().hasValueFor(fontName))
1437
				return fontName;
1562
				return fontName;
1438
			clazz= clazz.getSuperclass();
1563
			clazz = clazz.getSuperclass();
1439
		} while (clazz != null);
1564
		} while (clazz != null);
1440
		// use text compare font if no font has been registered for subclass
1565
		// use text compare font if no font has been registered for subclass
1441
		return getClass().getName();
1566
		return getClass().getName();
1442
	}
1567
	}
1443
	
1568
1444
	private void updateFont() {
1569
	private void updateFont() {
1445
		Font f= JFaceResources.getFont(fSymbolicFontName);
1570
		Font f = JFaceResources.getFont(fSymbolicFontName);
1446
		if (f != null) {
1571
		if (f != null) {
1447
			if (fAncestor != null)
1572
			if (fAncestor != null)
1448
				fAncestor.setFont(f);
1573
				fAncestor.setFont(f);
Lines 1452-1503 Link Here
1452
				fRight.setFont(f);
1577
				fRight.setFont(f);
1453
		}
1578
		}
1454
	}
1579
	}
1455
	
1580
1456
	private void checkForColorUpdate(Display display) {
1581
	private void checkForColorUpdate(Display display) {
1457
		if (fIsUsingSystemBackground) {
1582
		if (fIsUsingSystemBackground) {
1458
			RGB bg= display.getSystemColor(SWT.COLOR_LIST_BACKGROUND).getRGB();
1583
			RGB bg = display.getSystemColor(SWT.COLOR_LIST_BACKGROUND).getRGB();
1459
			if (!bg.equals(getBackground(display))) {
1584
			if (!bg.equals(getBackground(display))) {
1460
				updateColors(display);
1585
				updateColors(display);
1461
			}
1586
			}
1462
		}
1587
		}
1463
	}
1588
	}
1464
	
1589
1465
	/**
1590
	/**
1466
	 * Sets the viewer's background color to the given RGB value.
1591
	 * Sets the viewer's background color to the given RGB value. If the value
1467
	 * If the value is <code>null</code> the system's default background color is used.
1592
	 * is <code>null</code> the system's default background color is used.
1468
	 * @param background the background color or <code>null</code> to use the system's default background color
1593
	 * 
1594
	 * @param background
1595
	 *            the background color or <code>null</code> to use the system's
1596
	 *            default background color
1469
	 * @since 2.0
1597
	 * @since 2.0
1470
	 */
1598
	 */
1471
	public void setBackgroundColor(RGB background) {
1599
	public void setBackgroundColor(RGB background) {
1472
		fIsUsingSystemBackground= (background == null);
1600
		fIsUsingSystemBackground = (background == null);
1473
		fBackground= background;
1601
		fBackground = background;
1474
		updateColors(null);
1602
		updateColors(null);
1475
	}
1603
	}
1476
	
1604
1477
	private RGB getBackground(Display display) {
1605
	private RGB getBackground(Display display) {
1478
		if (fBackground != null)
1606
		if (fBackground != null)
1479
			return fBackground;
1607
			return fBackground;
1480
1608
1481
		if (display == null)
1609
		if (display == null)
1482
			display= fComposite.getDisplay();
1610
			display = fComposite.getDisplay();
1483
1611
1484
		return display.getSystemColor(SWT.COLOR_LIST_BACKGROUND).getRGB();
1612
		return display.getSystemColor(SWT.COLOR_LIST_BACKGROUND).getRGB();
1485
	}
1613
	}
1486
	
1614
1487
	/**
1615
	/**
1488
	 * Sets the viewer's foreground color to the given RGB value.
1616
	 * Sets the viewer's foreground color to the given RGB value. If the value
1489
	 * If the value is <code>null</code> the system's default foreground color is used.
1617
	 * is <code>null</code> the system's default foreground color is used.
1490
	 * @param foreground the foreground color or <code>null</code> to use the system's default foreground color
1618
	 * 
1619
	 * @param foreground
1620
	 *            the foreground color or <code>null</code> to use the system's
1621
	 *            default foreground color
1491
	 * @since 2.0
1622
	 * @since 2.0
1492
	 */
1623
	 */
1493
	public void setForegroundColor(RGB foreground) {
1624
	public void setForegroundColor(RGB foreground) {
1494
		fIsUsingSystemForeground= (foreground == null);
1625
		fIsUsingSystemForeground = (foreground == null);
1495
		fForeground= foreground;
1626
		fForeground = foreground;
1496
		updateColors(null);
1627
		updateColors(null);
1497
	}
1628
	}
1498
	
1629
1499
	private void updateColors(Display display) {
1630
	private void updateColors(Display display) {
1500
		
1631
1501
		if (display == null)
1632
		if (display == null)
1502
			display = fComposite.getDisplay();
1633
			display = fComposite.getDisplay();
1503
1634
Lines 1521-1569 Link Here
1521
			fLeft.setForegroundColor(color);
1652
			fLeft.setForegroundColor(color);
1522
		if (fRight != null)
1653
		if (fRight != null)
1523
			fRight.setForegroundColor(color);
1654
			fRight.setForegroundColor(color);
1524
		
1655
1525
		ColorRegistry registry= JFaceResources.getColorRegistry();
1656
		ColorRegistry registry = JFaceResources.getColorRegistry();
1526
		
1657
1527
		RGB bg= getBackground(display);
1658
		RGB bg = getBackground(display);
1528
		SELECTED_INCOMING= registry.getRGB(INCOMING_COLOR);
1659
		SELECTED_INCOMING = registry.getRGB(INCOMING_COLOR);
1529
		if (SELECTED_INCOMING == null)
1660
		if (SELECTED_INCOMING == null)
1530
			SELECTED_INCOMING= new RGB(0, 0, 255);	// BLUE
1661
			SELECTED_INCOMING = new RGB(0, 0, 255); // BLUE
1531
		INCOMING= interpolate(SELECTED_INCOMING, bg, 0.6);
1662
		INCOMING = interpolate(SELECTED_INCOMING, bg, 0.6);
1532
		INCOMING_FILL= interpolate(SELECTED_INCOMING, bg, 0.97);
1663
		INCOMING_FILL = interpolate(SELECTED_INCOMING, bg, 0.97);
1533
		INCOMING_TEXT_FILL= interpolate(SELECTED_INCOMING, bg, 0.85);
1664
		INCOMING_TEXT_FILL = interpolate(SELECTED_INCOMING, bg, 0.85);
1534
1665
1535
		SELECTED_OUTGOING= registry.getRGB(OUTGOING_COLOR);
1666
		SELECTED_OUTGOING = registry.getRGB(OUTGOING_COLOR);
1536
		if (SELECTED_OUTGOING == null)
1667
		if (SELECTED_OUTGOING == null)
1537
			SELECTED_OUTGOING= new RGB(0, 0, 0);	// BLACK
1668
			SELECTED_OUTGOING = new RGB(0, 0, 0); // BLACK
1538
		OUTGOING= interpolate(SELECTED_OUTGOING, bg, 0.6);
1669
		OUTGOING = interpolate(SELECTED_OUTGOING, bg, 0.6);
1539
		OUTGOING_FILL= interpolate(SELECTED_OUTGOING, bg, 0.97);
1670
		OUTGOING_FILL = interpolate(SELECTED_OUTGOING, bg, 0.97);
1540
		OUTGOING_TEXT_FILL= interpolate(SELECTED_OUTGOING, bg, 0.85);
1671
		OUTGOING_TEXT_FILL = interpolate(SELECTED_OUTGOING, bg, 0.85);
1541
		
1672
1542
		SELECTED_CONFLICT= registry.getRGB(CONFLICTING_COLOR);
1673
		SELECTED_CONFLICT = registry.getRGB(CONFLICTING_COLOR);
1543
		if (SELECTED_CONFLICT == null)
1674
		if (SELECTED_CONFLICT == null)
1544
			SELECTED_CONFLICT= new RGB(255, 0, 0);	// RED
1675
			SELECTED_CONFLICT = new RGB(255, 0, 0); // RED
1545
		CONFLICT= interpolate(SELECTED_CONFLICT, bg, 0.6);
1676
		CONFLICT = interpolate(SELECTED_CONFLICT, bg, 0.6);
1546
		CONFLICT_FILL= interpolate(SELECTED_CONFLICT, bg, 0.97);
1677
		CONFLICT_FILL = interpolate(SELECTED_CONFLICT, bg, 0.97);
1547
		CONFLICT_TEXT_FILL= interpolate(SELECTED_CONFLICT, bg, 0.85);
1678
		CONFLICT_TEXT_FILL = interpolate(SELECTED_CONFLICT, bg, 0.85);
1548
	
1679
1549
		RESOLVED= registry.getRGB(RESOLVED_COLOR);
1680
		RESOLVED = registry.getRGB(RESOLVED_COLOR);
1550
		if (RESOLVED == null)
1681
		if (RESOLVED == null)
1551
			RESOLVED= new RGB(0, 255, 0);	// GREEN
1682
			RESOLVED = new RGB(0, 255, 0); // GREEN
1552
					
1683
1553
		updatePresentation(display);
1684
		updatePresentation(display);
1554
	}
1685
	}
1555
1686
1556
	private void updatePresentation(Display display) {
1687
	private void updatePresentation(Display display) {
1557
		if (display == null)
1688
		if (display == null)
1558
			display= fComposite.getDisplay();
1689
			display = fComposite.getDisplay();
1559
		refreshBirdsEyeView();
1690
		refreshBirdsEyeView();
1560
		invalidateLines();
1691
		invalidateLines();
1561
		updateAllDiffBackgrounds(display);
1692
		updateAllDiffBackgrounds(display);
1562
		invalidateTextPresentation();
1693
		invalidateTextPresentation();
1563
	}
1694
	}
1564
	
1695
1565
	/**
1696
	/**
1566
	 * Invalidates the current presentation by invalidating the three text viewers.
1697
	 * Invalidates the current presentation by invalidating the three text
1698
	 * viewers.
1699
	 * 
1567
	 * @since 2.0
1700
	 * @since 2.0
1568
	 */
1701
	 */
1569
	public void invalidateTextPresentation() {
1702
	public void invalidateTextPresentation() {
Lines 1574-1587 Link Here
1574
		if (fRight != null)
1707
		if (fRight != null)
1575
			fRight.invalidateTextPresentation();
1708
			fRight.invalidateTextPresentation();
1576
	}
1709
	}
1577
	
1710
1578
	/**
1711
	/**
1579
	 * Configures the passed text viewer. This method is called after the three
1712
	 * Configures the passed text viewer. This method is called after the three
1580
	 * text viewers have been created for the content areas. The
1713
	 * text viewers have been created for the content areas. The
1581
	 * <code>TextMergeViewer</code> implementation of this method will
1714
	 * <code>TextMergeViewer</code> implementation of this method will configure
1582
	 * configure the viewer with a {@link SourceViewerConfiguration}.
1715
	 * the viewer with a {@link SourceViewerConfiguration}. Subclasses may
1583
	 * Subclasses may reimplement to provide a specific configuration for the
1716
	 * reimplement to provide a specific configuration for the text viewer.
1584
	 * text viewer.
1585
	 * 
1717
	 * 
1586
	 * @param textViewer
1718
	 * @param textViewer
1587
	 *            the text viewer to configure
1719
	 *            the text viewer to configure
Lines 1589-1621 Link Here
1589
	protected void configureTextViewer(TextViewer textViewer) {
1721
	protected void configureTextViewer(TextViewer textViewer) {
1590
		// to get undo for all text files
1722
		// to get undo for all text files
1591
		// bugzilla 131895, 33665
1723
		// bugzilla 131895, 33665
1592
		if(textViewer instanceof MergeSourceViewer){
1724
		if (textViewer instanceof MergeSourceViewer) {
1593
			SourceViewerConfiguration configuration= new SourceViewerConfiguration();
1725
			SourceViewerConfiguration configuration = new SourceViewerConfiguration();
1594
			((MergeSourceViewer)textViewer).configure(configuration);
1726
			((MergeSourceViewer) textViewer).configure(configuration);
1595
		}
1727
		}
1596
	}
1728
	}
1597
				
1729
1598
	/**
1730
	/**
1599
	 * Creates an <code>ITokenComparator</code> which is used to show the
1731
	 * Creates an <code>ITokenComparator</code> which is used to show the intra
1600
	 * intra line differences.
1732
	 * line differences. The <code>TextMergeViewer</code> implementation of this
1601
	 * The <code>TextMergeViewer</code> implementation of this method returns a
1733
	 * method returns a tokenizer that breaks a line into words separated by
1602
	 * tokenizer that breaks a line into words separated by whitespace.
1734
	 * whitespace. Subclasses may reimplement to provide a specific tokenizer.
1603
	 * Subclasses may reimplement to provide a specific tokenizer.
1735
	 * 
1604
	 * @param line the line for which to create the <code>ITokenComparator</code>
1736
	 * @param line
1605
	 * @return a ITokenComparator which is used for a second level token compare.
1737
	 *            the line for which to create the <code>ITokenComparator</code>
1738
	 * @return a ITokenComparator which is used for a second level token
1739
	 *         compare.
1606
	 */
1740
	 */
1607
	protected ITokenComparator createTokenComparator(String line) {
1741
	protected ITokenComparator createTokenComparator(String line) {
1608
		return new TokenComparator(line);
1742
		return new TokenComparator(line);
1609
	}
1743
	}
1610
	
1744
1611
	/**
1745
	/**
1612
	 * Setup the given document for use with this viewer. By default,
1746
	 * Setup the given document for use with this viewer. By default, the
1613
	 * the partitioner returned from {@link #getDocumentPartitioner()}
1747
	 * partitioner returned from {@link #getDocumentPartitioner()} is registered
1614
	 * is registered as the default partitioner for the document.
1748
	 * as the default partitioner for the document. Subclasses that return a
1615
	 * Subclasses that return a partitioner must also override
1749
	 * partitioner must also override {@link #getDocumentPartitioning()} if they
1616
	 * {@link #getDocumentPartitioning()} if they wish to be able to use shared
1750
	 * wish to be able to use shared documents (i.e. file buffers).
1617
	 * documents (i.e. file buffers).
1751
	 * 
1618
	 * @param document the document to be set up
1752
	 * @param document
1753
	 *            the document to be set up
1619
	 * 
1754
	 * 
1620
	 * @since 3.3
1755
	 * @since 3.3
1621
	 */
1756
	 */
Lines 1623-1629 Link Here
1623
		String partitioning = getDocumentPartitioning();
1758
		String partitioning = getDocumentPartitioning();
1624
		if (partitioning == null || !(document instanceof IDocumentExtension3)) {
1759
		if (partitioning == null || !(document instanceof IDocumentExtension3)) {
1625
			if (document.getDocumentPartitioner() == null) {
1760
			if (document.getDocumentPartitioner() == null) {
1626
				IDocumentPartitioner partitioner= getDocumentPartitioner();
1761
				IDocumentPartitioner partitioner = getDocumentPartitioner();
1627
				if (partitioner != null) {
1762
				if (partitioner != null) {
1628
					document.setDocumentPartitioner(partitioner);
1763
					document.setDocumentPartitioner(partitioner);
1629
					partitioner.connect(document);
1764
					partitioner.connect(document);
Lines 1632-1638 Link Here
1632
		} else {
1767
		} else {
1633
			IDocumentExtension3 ex3 = (IDocumentExtension3) document;
1768
			IDocumentExtension3 ex3 = (IDocumentExtension3) document;
1634
			if (ex3.getDocumentPartitioner(partitioning) == null) {
1769
			if (ex3.getDocumentPartitioner(partitioning) == null) {
1635
				IDocumentPartitioner partitioner= getDocumentPartitioner();
1770
				IDocumentPartitioner partitioner = getDocumentPartitioner();
1636
				if (partitioner != null) {
1771
				if (partitioner != null) {
1637
					ex3.setDocumentPartitioner(partitioning, partitioner);
1772
					ex3.setDocumentPartitioner(partitioning, partitioner);
1638
					partitioner.connect(document);
1773
					partitioner.connect(document);
Lines 1640-1672 Link Here
1640
			}
1775
			}
1641
		}
1776
		}
1642
	}
1777
	}
1643
	
1778
1644
	/**
1779
	/**
1645
	 * Returns a document partitioner which is suitable for the underlying content type.
1780
	 * Returns a document partitioner which is suitable for the underlying
1646
	 * This method is only called if the input provided by the content provider is a
1781
	 * content type. This method is only called if the input provided by the
1647
	 * <code>IStreamContentAccessor</code> and an internal document must be obtained. This
1782
	 * content provider is a <code>IStreamContentAccessor</code> and an internal
1648
	 * document is initialized with the partitioner returned from this method.
1783
	 * document must be obtained. This document is initialized with the
1784
	 * partitioner returned from this method.
1649
	 * <p>
1785
	 * <p>
1650
	 * The <code>TextMergeViewer</code> implementation of this method returns
1786
	 * The <code>TextMergeViewer</code> implementation of this method returns
1651
	 * <code>null</code>. Subclasses may reimplement to create a partitioner for a
1787
	 * <code>null</code>. Subclasses may reimplement to create a partitioner for
1652
	 * specific content type. Subclasses that do return a partitioner should also
1788
	 * a specific content type. Subclasses that do return a partitioner should
1653
	 * return a partitioning from {@link #getDocumentPartitioning()} in order to make
1789
	 * also return a partitioning from {@link #getDocumentPartitioning()} in
1654
	 * use of shared documents (e.g. file buffers).
1790
	 * order to make use of shared documents (e.g. file buffers).
1655
	 *
1791
	 * 
1656
	 * @return a document partitioner, or <code>null</code>
1792
	 * @return a document partitioner, or <code>null</code>
1657
	 */
1793
	 */
1658
	protected IDocumentPartitioner getDocumentPartitioner() {
1794
	protected IDocumentPartitioner getDocumentPartitioner() {
1659
		return null;
1795
		return null;
1660
	}
1796
	}
1661
	
1797
1662
	/**
1798
	/**
1663
	 * Return the partitioning to which the partitioner returned from
1799
	 * Return the partitioning to which the partitioner returned from
1664
	 * {@link #getDocumentPartitioner()} is to be associated. Return <code>null</code>
1800
	 * {@link #getDocumentPartitioner()} is to be associated. Return
1665
	 * only if partitioning is not needed or if the subclass
1801
	 * <code>null</code> only if partitioning is not needed or if the subclass
1666
	 * overrode {@link #setupDocument(IDocument)} directly.
1802
	 * overrode {@link #setupDocument(IDocument)} directly. By default,
1667
	 * By default, <code>null</code> is returned which means that shared
1803
	 * <code>null</code> is returned which means that shared documents that
1668
	 * documents that return a partitioner from {@link #getDocumentPartitioner()}
1804
	 * return a partitioner from {@link #getDocumentPartitioner()} will not be
1669
	 * will not be able to use shared documents.
1805
	 * able to use shared documents.
1806
	 * 
1670
	 * @see IDocumentExtension3
1807
	 * @see IDocumentExtension3
1671
	 * @return a partitioning
1808
	 * @return a partitioning
1672
	 * 
1809
	 * 
Lines 1675-1938 Link Here
1675
	protected String getDocumentPartitioning() {
1812
	protected String getDocumentPartitioning() {
1676
		return null;
1813
		return null;
1677
	}
1814
	}
1678
	
1815
1679
	/**
1816
	/**
1680
	 * Called on the viewer disposal.
1817
	 * Called on the viewer disposal. Unregisters from the compare
1681
	 * Unregisters from the compare configuration.
1818
	 * configuration. Clients may extend if they have to do additional cleanup.
1682
	 * Clients may extend if they have to do additional cleanup.
1819
	 * 
1683
	 * @param event
1820
	 * @param event
1684
	 */
1821
	 */
1685
	protected void handleDispose(DisposeEvent event) {
1822
	protected void handleDispose(DisposeEvent event) {
1686
		
1823
1687
		if (fHandlerService != null)
1824
		if (fHandlerService != null)
1688
			fHandlerService.dispose();
1825
			fHandlerService.dispose();
1689
		
1826
1690
		Object input= getInput();
1827
		Object input = getInput();
1691
		removeFromDocumentManager(ANCESTOR_CONTRIBUTOR, input);
1828
		removeFromDocumentManager(ANCESTOR_CONTRIBUTOR, input);
1692
		removeFromDocumentManager(LEFT_CONTRIBUTOR, input);
1829
		removeFromDocumentManager(LEFT_CONTRIBUTOR, input);
1693
		removeFromDocumentManager(RIGHT_CONTRIBUTOR, input);
1830
		removeFromDocumentManager(RIGHT_CONTRIBUTOR, input);
1694
		
1831
1695
		if (DEBUG)
1832
		if (DEBUG)
1696
			DocumentManager.dump();
1833
			DocumentManager.dump();
1697
1834
1698
		if (fPreferenceChangeListener != null) {
1835
		if (fPreferenceChangeListener != null) {
1699
			JFaceResources.getFontRegistry().removeListener(fPreferenceChangeListener);
1836
			JFaceResources.getFontRegistry().removeListener(
1700
			JFaceResources.getColorRegistry().removeListener(fPreferenceChangeListener);
1837
					fPreferenceChangeListener);
1838
			JFaceResources.getColorRegistry().removeListener(
1839
					fPreferenceChangeListener);
1701
			if (fPreferenceStore != null)
1840
			if (fPreferenceStore != null)
1702
				fPreferenceStore.removePropertyChangeListener(fPreferenceChangeListener);
1841
				fPreferenceStore
1703
			fPreferenceChangeListener= null;
1842
						.removePropertyChangeListener(fPreferenceChangeListener);
1843
			fPreferenceChangeListener = null;
1704
		}
1844
		}
1705
		
1845
1706
		fLeftCanvas= null;
1846
		fLeftCanvas = null;
1707
		fRightCanvas= null;
1847
		fRightCanvas = null;
1708
		fVScrollBar= null;
1848
		fVScrollBar = null;
1709
		fBirdsEyeCanvas= null;
1849
		fBirdsEyeCanvas = null;
1710
		fSummaryHeader= null;
1850
		fSummaryHeader = null;
1711
1851
1712
		fAncestorContributor.unsetDocument(fAncestor);
1852
		fAncestorContributor.unsetDocument(fAncestor);
1713
		fLeftContributor.unsetDocument(fLeft);
1853
		fLeftContributor.unsetDocument(fLeft);
1714
		fRightContributor.unsetDocument(fRight);
1854
		fRightContributor.unsetDocument(fRight);
1715
		
1855
1716
		disconnect(fLeftContributor);
1856
		disconnect(fLeftContributor);
1717
		disconnect(fRightContributor);
1857
		disconnect(fRightContributor);
1718
		disconnect(fAncestorContributor);
1858
		disconnect(fAncestorContributor);
1719
		
1859
1720
		if (fColors != null) {
1860
		if (fColors != null) {
1721
			Iterator i= fColors.values().iterator();
1861
			Iterator i = fColors.values().iterator();
1722
			while (i.hasNext()) {
1862
			while (i.hasNext()) {
1723
				Color color= (Color) i.next();
1863
				Color color = (Color) i.next();
1724
				if (!color.isDisposed())
1864
				if (!color.isDisposed())
1725
					color.dispose();
1865
					color.dispose();
1726
			}
1866
			}
1727
			fColors= null;
1867
			fColors = null;
1728
		}
1868
		}
1729
		
1869
1730
		if (fBirdsEyeCursor != null) {
1870
		if (fBirdsEyeCursor != null) {
1731
			fBirdsEyeCursor.dispose();
1871
			fBirdsEyeCursor.dispose();
1732
			fBirdsEyeCursor= null;
1872
			fBirdsEyeCursor = null;
1733
		}
1873
		}
1734
		
1874
1735
		if (showWhitespaceAction != null)
1875
		if (showWhitespaceAction != null)
1736
			showWhitespaceAction.dispose();
1876
			showWhitespaceAction.dispose();
1737
		
1877
1738
		if (toggleLineNumbersAction != null)
1878
		if (toggleLineNumbersAction != null)
1739
			toggleLineNumbersAction.dispose();
1879
			toggleLineNumbersAction.dispose();
1740
		
1880
1741
		if (fIgnoreWhitespace != null)
1881
		if (fIgnoreWhitespace != null)
1742
			fIgnoreWhitespace.dispose();
1882
			fIgnoreWhitespace.dispose();
1743
		
1883
1744
		if (fSourceViewerDecorationSupport != null) {
1884
		if (fSourceViewerDecorationSupport != null) {
1745
			for (Iterator iterator = fSourceViewerDecorationSupport.iterator(); iterator.hasNext();) {
1885
			for (Iterator iterator = fSourceViewerDecorationSupport.iterator(); iterator
1886
					.hasNext();) {
1746
				((SourceViewerDecorationSupport) iterator.next()).dispose();
1887
				((SourceViewerDecorationSupport) iterator.next()).dispose();
1747
			}
1888
			}
1748
			fSourceViewerDecorationSupport = null;
1889
			fSourceViewerDecorationSupport = null;
1749
		}
1890
		}
1750
1891
1751
		super.handleDispose(event);
1892
		super.handleDispose(event);
1752
  	}
1893
	}
1753
  	  	  				 		
1894
1754
	private void disconnect(ContributorInfo legInfo) {
1895
	private void disconnect(ContributorInfo legInfo) {
1755
		if (legInfo != null)
1896
		if (legInfo != null)
1756
			legInfo.disconnect();
1897
			legInfo.disconnect();
1757
	}
1898
	}
1758
1899
1759
	//-------------------------------------------------------------------------------------------------------------
1900
	// -------------------------------------------------------------------------------------------------------------
1760
	//--- internal ------------------------------------------------------------------------------------------------
1901
	// --- internal
1761
	//-------------------------------------------------------------------------------------------------------------
1902
	// ------------------------------------------------------------------------------------------------
1762
	
1903
	// -------------------------------------------------------------------------------------------------------------
1904
1763
	/*
1905
	/*
1764
	 * Creates the specific SWT controls for the content areas.
1906
	 * Creates the specific SWT controls for the content areas. Clients must not
1765
	 * Clients must not call or override this method.
1907
	 * call or override this method.
1766
	 */
1908
	 */
1767
	protected void createControls(Composite composite) {
1909
	protected void createControls(Composite composite) {
1768
		
1910
1769
		PlatformUI.getWorkbench().getHelpSystem().setHelp(composite, ICompareContextIds.TEXT_MERGE_VIEW);
1911
		PlatformUI.getWorkbench().getHelpSystem().setHelp(composite,
1770
		
1912
				ICompareContextIds.TEXT_MERGE_VIEW);
1913
1771
		// 1st row
1914
		// 1st row
1772
		if (fMarginWidth > 0) {
1915
		if (fMarginWidth > 0) {
1773
			fAncestorCanvas= new BufferedCanvas(composite, SWT.NONE) {
1916
			fAncestorCanvas = new BufferedCanvas(composite, SWT.NONE) {
1774
				public void doPaint(GC gc) {
1917
				public void doPaint(GC gc) {
1775
					paintSides(gc, fAncestor, fAncestorCanvas, false);
1918
					paintSides(gc, fAncestor, fAncestorCanvas, false);
1776
				}
1919
				}
1777
			};
1920
			};
1778
			fAncestorCanvas.addMouseListener(
1921
			fAncestorCanvas.addMouseListener(new MouseAdapter() {
1779
				new MouseAdapter() {
1922
				public void mouseDown(MouseEvent e) {
1780
					public void mouseDown(MouseEvent e) {
1923
					setCurrentDiff2(handleMouseInSides(fAncestorCanvas,
1781
						setCurrentDiff2(handleMouseInSides(fAncestorCanvas, fAncestor, e.y), false);
1924
							fAncestor, e.y), false);
1782
					}
1783
				}
1925
				}
1784
			);
1926
			});
1785
		}
1927
		}
1786
									
1928
1787
		fAncestor= createPart(composite);
1929
		fAncestor = createPart(composite);
1788
		fAncestor.setEditable(false);
1930
		fAncestor.setEditable(false);
1789
		fAncestor.getTextWidget().getAccessible().addAccessibleListener(new AccessibleAdapter() {
1931
		fAncestor.getTextWidget().getAccessible().addAccessibleListener(
1790
			public void getName(AccessibleEvent e) {
1932
				new AccessibleAdapter() {
1791
				e.result = NLS.bind(CompareMessages.TextMergeViewer_accessible_ancestor, getCompareConfiguration().getAncestorLabel(getInput()));
1933
					public void getName(AccessibleEvent e) {
1792
			}
1934
						e.result = NLS
1793
		});
1935
								.bind(
1936
										CompareMessages.TextMergeViewer_accessible_ancestor,
1937
										getCompareConfiguration()
1938
												.getAncestorLabel(getInput()));
1939
					}
1940
				});
1794
		fAncestor.addTextPresentationListener(new ChangeHighlighter(fAncestor));
1941
		fAncestor.addTextPresentationListener(new ChangeHighlighter(fAncestor));
1795
		
1942
1796
		fSummaryHeader= new Canvas(composite, SWT.NONE);
1943
		fSummaryHeader = new Canvas(composite, SWT.NONE);
1797
		fHeaderPainter= new HeaderPainter();
1944
		fHeaderPainter = new HeaderPainter();
1798
		fSummaryHeader.addPaintListener(fHeaderPainter);
1945
		fSummaryHeader.addPaintListener(fHeaderPainter);
1799
		updateResolveStatus();
1946
		updateResolveStatus();
1800
				
1947
1801
		// 2nd row
1948
		// 2nd row
1802
		if (fMarginWidth > 0) {
1949
		if (fMarginWidth > 0) {
1803
			fLeftCanvas= new BufferedCanvas(composite, SWT.NONE) {
1950
			fLeftCanvas = new BufferedCanvas(composite, SWT.NONE) {
1804
				public void doPaint(GC gc) {
1951
				public void doPaint(GC gc) {
1805
					paintSides(gc, fLeft, fLeftCanvas, false);
1952
					paintSides(gc, fLeft, fLeftCanvas, false);
1806
				}
1953
				}
1807
			};
1954
			};
1808
			fLeftCanvas.addMouseListener(
1955
			fLeftCanvas.addMouseListener(new MouseAdapter() {
1809
				new MouseAdapter() {
1956
				public void mouseDown(MouseEvent e) {
1810
					public void mouseDown(MouseEvent e) {
1957
					setCurrentDiff2(
1811
						setCurrentDiff2(handleMouseInSides(fLeftCanvas, fLeft, e.y), false);
1958
							handleMouseInSides(fLeftCanvas, fLeft, e.y), false);
1812
					}
1813
				}
1959
				}
1814
			);
1960
			});
1815
		}
1961
		}
1816
		
1962
1817
		fLeft= createPart(composite);
1963
		fLeft = createPart(composite);
1818
		fLeft.getTextWidget().getVerticalBar().setVisible(!fSynchronizedScrolling);
1964
		fLeft.getTextWidget().getVerticalBar().setVisible(
1965
				!fSynchronizedScrolling);
1819
		fLeft.addAction(MergeSourceViewer.SAVE_ID, fLeftSaveAction);
1966
		fLeft.addAction(MergeSourceViewer.SAVE_ID, fLeftSaveAction);
1820
		fLeft.getTextWidget().getAccessible().addAccessibleListener(new AccessibleAdapter() {
1967
		fLeft.getTextWidget().getAccessible().addAccessibleListener(
1821
			public void getName(AccessibleEvent e) {
1968
				new AccessibleAdapter() {
1822
				e.result = NLS.bind(CompareMessages.TextMergeViewer_accessible_left, getCompareConfiguration().getLeftLabel(getInput()));
1969
					public void getName(AccessibleEvent e) {
1823
			}
1970
						e.result = NLS
1824
		});
1971
								.bind(
1972
										CompareMessages.TextMergeViewer_accessible_left,
1973
										getCompareConfiguration().getLeftLabel(
1974
												getInput()));
1975
					}
1976
				});
1825
		fLeft.addTextPresentationListener(new ChangeHighlighter(fLeft));
1977
		fLeft.addTextPresentationListener(new ChangeHighlighter(fLeft));
1826
		
1978
1827
		fRight= createPart(composite);
1979
		fRight = createPart(composite);
1828
		fRight.getTextWidget().getVerticalBar().setVisible(!fSynchronizedScrolling);
1980
		fRight.getTextWidget().getVerticalBar().setVisible(
1981
				!fSynchronizedScrolling);
1829
		fRight.addAction(MergeSourceViewer.SAVE_ID, fRightSaveAction);
1982
		fRight.addAction(MergeSourceViewer.SAVE_ID, fRightSaveAction);
1830
		fRight.getTextWidget().getAccessible().addAccessibleListener(new AccessibleAdapter() {
1983
		fRight.getTextWidget().getAccessible().addAccessibleListener(
1831
			public void getName(AccessibleEvent e) {
1984
				new AccessibleAdapter() {
1832
				e.result = NLS.bind(CompareMessages.TextMergeViewer_accessible_right, getCompareConfiguration().getRightLabel(getInput()));
1985
					public void getName(AccessibleEvent e) {
1833
			}
1986
						e.result = NLS
1834
		});
1987
								.bind(
1988
										CompareMessages.TextMergeViewer_accessible_right,
1989
										getCompareConfiguration()
1990
												.getRightLabel(getInput()));
1991
					}
1992
				});
1835
		fRight.addTextPresentationListener(new ChangeHighlighter(fRight));
1993
		fRight.addTextPresentationListener(new ChangeHighlighter(fRight));
1836
		
1994
1837
		 IWorkbenchPart part = getCompareConfiguration().getContainer().getWorkbenchPart();
1995
		IWorkbenchPart part = getCompareConfiguration().getContainer()
1838
		 // part is not available for contexts different than editor
1996
				.getWorkbenchPart();
1839
		 if (part != null) {
1997
		// part is not available for contexts different than editor
1840
			 ISelectionProvider selectionProvider = part.getSite().getSelectionProvider();
1998
		if (part != null) {
1841
			 if (selectionProvider instanceof CompareEditorSelectionProvider) {
1999
			ISelectionProvider selectionProvider = part.getSite()
1842
				 CompareEditorSelectionProvider cesp = (CompareEditorSelectionProvider) selectionProvider;
2000
					.getSelectionProvider();
1843
				 cesp.setViewers(new TextViewer[] { fLeft, fRight, fAncestor }, fFocusPart /* null */);
2001
			if (selectionProvider instanceof CompareEditorSelectionProvider) {
1844
			 }
2002
				CompareEditorSelectionProvider cesp = (CompareEditorSelectionProvider) selectionProvider;
1845
		 }
2003
				cesp.setViewers(new TextViewer[] { fLeft, fRight, fAncestor },
1846
		
2004
						fFocusPart /* null */);
2005
			}
2006
		}
2007
1847
		hsynchViewport(fAncestor, fLeft, fRight);
2008
		hsynchViewport(fAncestor, fLeft, fRight);
1848
		hsynchViewport(fLeft, fAncestor, fRight);
2009
		hsynchViewport(fLeft, fAncestor, fRight);
1849
		hsynchViewport(fRight, fAncestor, fLeft);
2010
		hsynchViewport(fRight, fAncestor, fLeft);
1850
2011
1851
		if (fMarginWidth > 0) {
2012
		if (fMarginWidth > 0) {
1852
			fRightCanvas= new BufferedCanvas(composite, SWT.NONE) {
2013
			fRightCanvas = new BufferedCanvas(composite, SWT.NONE) {
1853
				public void doPaint(GC gc) {
2014
				public void doPaint(GC gc) {
1854
					paintSides(gc, fRight, fRightCanvas, fSynchronizedScrolling);
2015
					paintSides(gc, fRight, fRightCanvas, fSynchronizedScrolling);
1855
				}
2016
				}
1856
			};
2017
			};
1857
			fRightCanvas.addMouseListener(
2018
			fRightCanvas.addMouseListener(new MouseAdapter() {
1858
				new MouseAdapter() {
2019
				public void mouseDown(MouseEvent e) {
1859
					public void mouseDown(MouseEvent e) {
2020
					setCurrentDiff2(handleMouseInSides(fRightCanvas, fRight,
1860
						setCurrentDiff2(handleMouseInSides(fRightCanvas, fRight, e.y), false);
2021
							e.y), false);
1861
					}
1862
				}
2022
				}
1863
			);
2023
			});
1864
		}
2024
		}
1865
		
2025
1866
		fScrollCanvas= new Canvas(composite, SWT.V_SCROLL);
2026
		fScrollCanvas = new Canvas(composite, SWT.V_SCROLL);
1867
		Rectangle trim= fLeft.getTextWidget().computeTrim(0, 0, 0, 0);
2027
		Rectangle trim = fLeft.getTextWidget().computeTrim(0, 0, 0, 0);
1868
		fTopInset= trim.y;
2028
		fTopInset = trim.y;
1869
		
2029
1870
		fVScrollBar= fScrollCanvas.getVerticalBar();
2030
		fVScrollBar = fScrollCanvas.getVerticalBar();
1871
		fVScrollBar.setIncrement(1);
2031
		fVScrollBar.setIncrement(1);
1872
		fVScrollBar.setVisible(true);
2032
		fVScrollBar.setVisible(true);
1873
		fVScrollBar.addListener(SWT.Selection,
2033
		fVScrollBar.addListener(SWT.Selection, new Listener() {
1874
			new Listener() {
2034
			public void handleEvent(Event e) {
1875
				public void handleEvent(Event e) {
2035
				int vpos = ((ScrollBar) e.widget).getSelection();
1876
					int vpos= ((ScrollBar)e.widget).getSelection();
2036
				synchronizedScrollVertical(vpos);
1877
					synchronizedScrollVertical(vpos);
1878
				}
1879
			}
2037
			}
1880
		);
2038
		});
1881
		
2039
1882
		fBirdsEyeCanvas= new BufferedCanvas(composite, SWT.NONE) {
2040
		fBirdsEyeCanvas = new BufferedCanvas(composite, SWT.NONE) {
1883
			public void doPaint(GC gc) {
2041
			public void doPaint(GC gc) {
1884
				paintBirdsEyeView(this, gc);
2042
				paintBirdsEyeView(this, gc);
1885
			}
2043
			}
1886
		};
2044
		};
1887
		fBirdsEyeCanvas.addMouseListener(
2045
		fBirdsEyeCanvas.addMouseListener(new MouseAdapter() {
1888
			new MouseAdapter() {
2046
			public void mouseDown(MouseEvent e) {
1889
				public void mouseDown(MouseEvent e) {
2047
				setCurrentDiff2(
1890
					setCurrentDiff2(handlemouseInBirdsEyeView(fBirdsEyeCanvas, e.y), true);
2048
						handlemouseInBirdsEyeView(fBirdsEyeCanvas, e.y), true);
1891
				}
1892
			}
2049
			}
1893
		);
2050
		});
1894
		fBirdsEyeCanvas.addMouseMoveListener(
2051
		fBirdsEyeCanvas.addMouseMoveListener(new MouseMoveListener() {
1895
			new MouseMoveListener() {
2052
1896
				
2053
			private Cursor fLastCursor;
1897
				private Cursor fLastCursor;
2054
1898
				
2055
			public void mouseMove(MouseEvent e) {
1899
				public void mouseMove(MouseEvent e) {
2056
				Cursor cursor = null;
1900
					Cursor cursor= null;
2057
				Diff diff = handlemouseInBirdsEyeView(fBirdsEyeCanvas, e.y);
1901
					Diff diff= handlemouseInBirdsEyeView(fBirdsEyeCanvas, e.y);
2058
				if (diff != null && diff.getKind() != RangeDifference.NOCHANGE)
1902
					if (diff != null && diff.getKind() != RangeDifference.NOCHANGE)
2059
					cursor = fBirdsEyeCursor;
1903
						cursor= fBirdsEyeCursor;
2060
				if (fLastCursor != cursor) {
1904
					if (fLastCursor != cursor) {
2061
					fBirdsEyeCanvas.setCursor(cursor);
1905
						fBirdsEyeCanvas.setCursor(cursor);
2062
					fLastCursor = cursor;
1906
						fLastCursor= cursor;
1907
					}
1908
				}
2063
				}
1909
			}
2064
			}
1910
		);
2065
		});
2066
2067
		contributeCreatePatchAction(fAncestor, false);
2068
		contributeCreatePatchAction(fLeft, false);
2069
		contributeCreatePatchAction(fRight, true);
1911
	}
2070
	}
1912
	
2071
1913
	private void hsynchViewport(final TextViewer tv1, final TextViewer tv2, final TextViewer tv3) {
2072
	private void hsynchViewport(final TextViewer tv1, final TextViewer tv2,
1914
		final StyledText st1= tv1.getTextWidget();
2073
			final TextViewer tv3) {
1915
		final StyledText st2= tv2.getTextWidget();
2074
		final StyledText st1 = tv1.getTextWidget();
1916
		final StyledText st3= tv3.getTextWidget();
2075
		final StyledText st2 = tv2.getTextWidget();
1917
		final ScrollBar sb1= st1.getHorizontalBar();
2076
		final StyledText st3 = tv3.getTextWidget();
2077
		final ScrollBar sb1 = st1.getHorizontalBar();
1918
		sb1.addSelectionListener(new SelectionAdapter() {
2078
		sb1.addSelectionListener(new SelectionAdapter() {
1919
			public void widgetSelected(SelectionEvent e) {
2079
			public void widgetSelected(SelectionEvent e) {
1920
			    if (fSynchronizedScrolling) {
2080
				if (fSynchronizedScrolling) {
1921
					int v= sb1.getSelection();
2081
					int v = sb1.getSelection();
1922
					if (st2.isVisible())
2082
					if (st2.isVisible())
1923
						st2.setHorizontalPixel(v);
2083
						st2.setHorizontalPixel(v);
1924
					if (st3.isVisible())
2084
					if (st3.isVisible())
1925
						st3.setHorizontalPixel(v);
2085
						st3.setHorizontalPixel(v);
1926
					workaround65205();
2086
					workaround65205();
1927
			    }
2087
				}
1928
			}
2088
			}
1929
		});
2089
		});
1930
	}
2090
	}
1931
2091
1932
	/**
2092
	/**
1933
	 * A workaround for bug #65205.
2093
	 * A workaround for bug #65205. On MacOS X a Display.update() is required to
1934
	 * On MacOS X a Display.update() is required to flush pending paint requests after
2094
	 * flush pending paint requests after programmatically scrolling.
1935
	 * programmatically scrolling.
1936
	 */
2095
	 */
1937
	private void workaround65205() {
2096
	private void workaround65205() {
1938
		if (fIsCarbon && fComposite != null && !fComposite.isDisposed())
2097
		if (fIsCarbon && fComposite != null && !fComposite.isDisposed())
Lines 1941-1965 Link Here
1941
2100
1942
	private void setCurrentDiff2(Diff diff, boolean reveal) {
2101
	private void setCurrentDiff2(Diff diff, boolean reveal) {
1943
		if (diff != null && diff.getKind() != RangeDifference.NOCHANGE) {
2102
		if (diff != null && diff.getKind() != RangeDifference.NOCHANGE) {
1944
			//fCurrentDiff= null;
2103
			// fCurrentDiff= null;
1945
			setCurrentDiff(diff, reveal);
2104
			setCurrentDiff(diff, reveal);
1946
		}
2105
		}
1947
	}
2106
	}
1948
	
2107
1949
	private Diff handleMouseInSides(Canvas canvas, MergeSourceViewer tp, int my) {
2108
	private Diff handleMouseInSides(Canvas canvas, MergeSourceViewer tp, int my) {
1950
2109
1951
		int lineHeight= tp.getTextWidget().getLineHeight();
2110
		int lineHeight = tp.getTextWidget().getLineHeight();
1952
		int visibleHeight= tp.getViewportHeight();
2111
		int visibleHeight = tp.getViewportHeight();
1953
2112
1954
		if (! fHighlightRanges)
2113
		if (!fHighlightRanges)
1955
			return null;
2114
			return null;
1956
2115
1957
		if (fMerger.hasChanges()) {
2116
		if (fMerger.hasChanges()) {
1958
			int shift= tp.getVerticalScrollOffset() + (2-LW);
2117
			int shift = tp.getVerticalScrollOffset() + (2 - LW);
1959
2118
1960
			Point region= new Point(0, 0);
2119
			Point region = new Point(0, 0);
1961
			char leg = getLeg(tp);
2120
			char leg = getLeg(tp);
1962
			for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) {
2121
			for (Iterator iterator = fMerger.changesIterator(); iterator
2122
					.hasNext();) {
1963
				Diff diff = (Diff) iterator.next();
2123
				Diff diff = (Diff) iterator.next();
1964
				if (diff.isDeleted())
2124
				if (diff.isDeleted())
1965
					continue;
2125
					continue;
Lines 1968-2009 Link Here
1968
					continue;
2128
					continue;
1969
2129
1970
				tp.getLineRange(diff.getPosition(leg), region);
2130
				tp.getLineRange(diff.getPosition(leg), region);
1971
				int y= (region.x * lineHeight) + shift;
2131
				int y = (region.x * lineHeight) + shift;
1972
				int h= region.y * lineHeight;
2132
				int h = region.y * lineHeight;
1973
2133
1974
				if (y+h < 0)
2134
				if (y + h < 0)
1975
					continue;
2135
					continue;
1976
				if (y >= visibleHeight)
2136
				if (y >= visibleHeight)
1977
					break;
2137
					break;
1978
					
2138
1979
				if (my >= y && my < y+h)
2139
				if (my >= y && my < y + h)
1980
					return diff;
2140
					return diff;
1981
			}
2141
			}
1982
		}
2142
		}
1983
		return null;
2143
		return null;
1984
	}
2144
	}
1985
	
2145
1986
	private Diff getDiffUnderMouse(Canvas canvas, int mx, int my, Rectangle r) {
2146
	private Diff getDiffUnderMouse(Canvas canvas, int mx, int my, Rectangle r) {
1987
2147
1988
		if (! fSynchronizedScrolling)
2148
		if (!fSynchronizedScrolling)
1989
			return null;
2149
			return null;
1990
2150
1991
		int lineHeight= fLeft.getTextWidget().getLineHeight();
2151
		int lineHeight = fLeft.getTextWidget().getLineHeight();
1992
		int visibleHeight= fRight.getViewportHeight();
2152
		int visibleHeight = fRight.getViewportHeight();
1993
2153
1994
		Point size= canvas.getSize();
2154
		Point size = canvas.getSize();
1995
		int w= size.x;
2155
		int w = size.x;
1996
2156
1997
		if (! fHighlightRanges)
2157
		if (!fHighlightRanges)
1998
			return null;
2158
			return null;
1999
2159
2000
		if (fMerger.hasChanges()) {
2160
		if (fMerger.hasChanges()) {
2001
			int lshift= fLeft.getVerticalScrollOffset();
2161
			int lshift = fLeft.getVerticalScrollOffset();
2002
			int rshift= fRight.getVerticalScrollOffset();
2162
			int rshift = fRight.getVerticalScrollOffset();
2003
2163
2004
			Point region= new Point(0, 0);
2164
			Point region = new Point(0, 0);
2005
2165
2006
			for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) {
2166
			for (Iterator iterator = fMerger.changesIterator(); iterator
2167
					.hasNext();) {
2007
				Diff diff = (Diff) iterator.next();
2168
				Diff diff = (Diff) iterator.next();
2008
				if (diff.isDeleted())
2169
				if (diff.isDeleted())
2009
					continue;
2170
					continue;
Lines 2012-2038 Link Here
2012
					continue;
2173
					continue;
2013
2174
2014
				fLeft.getLineRange(diff.getPosition(LEFT_CONTRIBUTOR), region);
2175
				fLeft.getLineRange(diff.getPosition(LEFT_CONTRIBUTOR), region);
2015
				int ly= (region.x * lineHeight) + lshift;
2176
				int ly = (region.x * lineHeight) + lshift;
2016
				int lh= region.y * lineHeight;
2177
				int lh = region.y * lineHeight;
2017
2178
2018
				fRight.getLineRange(diff.getPosition(RIGHT_CONTRIBUTOR), region);
2179
				fRight
2019
				int ry= (region.x * lineHeight) + rshift;
2180
						.getLineRange(diff.getPosition(RIGHT_CONTRIBUTOR),
2020
				int rh= region.y * lineHeight;
2181
								region);
2182
				int ry = (region.x * lineHeight) + rshift;
2183
				int rh = region.y * lineHeight;
2021
2184
2022
				if (Math.max(ly+lh, ry+rh) < 0)
2185
				if (Math.max(ly + lh, ry + rh) < 0)
2023
					continue;
2186
					continue;
2024
				if (Math.min(ly, ry) >= visibleHeight)
2187
				if (Math.min(ly, ry) >= visibleHeight)
2025
					break;
2188
					break;
2026
2189
2027
				int cx= (w-RESOLVE_SIZE)/2;
2190
				int cx = (w - RESOLVE_SIZE) / 2;
2028
				int cy= ((ly+lh/2) + (ry+rh/2) - RESOLVE_SIZE)/2;
2191
				int cy = ((ly + lh / 2) + (ry + rh / 2) - RESOLVE_SIZE) / 2;
2029
				if (my >= cy && my < cy+RESOLVE_SIZE && mx >= cx && mx < cx+RESOLVE_SIZE) {
2192
				if (my >= cy && my < cy + RESOLVE_SIZE && mx >= cx
2193
						&& mx < cx + RESOLVE_SIZE) {
2030
					if (r != null) {
2194
					if (r != null) {
2031
						int SIZE= fIsCarbon ? 30 : 20;
2195
						int SIZE = fIsCarbon ? 30 : 20;
2032
						r.x= cx+(RESOLVE_SIZE-SIZE)/2;
2196
						r.x = cx + (RESOLVE_SIZE - SIZE) / 2;
2033
						r.y= cy+(RESOLVE_SIZE-SIZE)/2;
2197
						r.y = cy + (RESOLVE_SIZE - SIZE) / 2;
2034
						r.width= SIZE;
2198
						r.width = SIZE;
2035
						r.height= SIZE;
2199
						r.height = SIZE;
2036
					}
2200
					}
2037
					return diff;
2201
					return diff;
2038
				}
2202
				}
Lines 2042-2088 Link Here
2042
	}
2206
	}
2043
2207
2044
	private Diff handlemouseInBirdsEyeView(Canvas canvas, int my) {
2208
	private Diff handlemouseInBirdsEyeView(Canvas canvas, int my) {
2045
		return fMerger.findDiff(getViewportHeight(), fSynchronizedScrolling, canvas.getSize(), my);
2209
		return fMerger.findDiff(getViewportHeight(), fSynchronizedScrolling,
2210
				canvas.getSize(), my);
2046
	}
2211
	}
2047
	
2212
2048
	private void paintBirdsEyeView(Canvas canvas, GC gc) {
2213
	private void paintBirdsEyeView(Canvas canvas, GC gc) {
2049
		
2214
2050
		Color c;
2215
		Color c;
2051
		Rectangle r= new Rectangle(0, 0, 0, 0);
2216
		Rectangle r = new Rectangle(0, 0, 0, 0);
2052
		int yy, hh;
2217
		int yy, hh;
2053
		
2218
2054
		Point size= canvas.getSize();
2219
		Point size = canvas.getSize();
2055
		
2220
2056
		int virtualHeight= fSynchronizedScrolling ? fMerger.getVirtualHeight() : fMerger.getRightHeight();
2221
		int virtualHeight = fSynchronizedScrolling ? fMerger.getVirtualHeight()
2222
				: fMerger.getRightHeight();
2057
		if (virtualHeight < getViewportHeight())
2223
		if (virtualHeight < getViewportHeight())
2058
			return;
2224
			return;
2059
				
2225
2060
		Display display= canvas.getDisplay();
2226
		Display display = canvas.getDisplay();
2061
		int y= 0;
2227
		int y = 0;
2062
		for (Iterator iterator = fMerger.rangesIterator(); iterator.hasNext();) {
2228
		for (Iterator iterator = fMerger.rangesIterator(); iterator.hasNext();) {
2063
			Diff diff = (Diff) iterator.next();
2229
			Diff diff = (Diff) iterator.next();
2064
			int h= fSynchronizedScrolling ? diff.getMaxDiffHeight()
2230
			int h = fSynchronizedScrolling ? diff.getMaxDiffHeight() : diff
2065
										  : diff.getRightHeight();
2231
					.getRightHeight();
2066
							
2232
2067
			if (fMerger.useChange(diff)) {
2233
			if (fMerger.useChange(diff)) {
2068
				
2234
2069
				yy= (y*size.y)/virtualHeight;
2235
				yy = (y * size.y) / virtualHeight;
2070
				hh= (h*size.y)/virtualHeight;
2236
				hh = (h * size.y) / virtualHeight;
2071
				if (hh < 3)
2237
				if (hh < 3)
2072
					hh= 3;
2238
					hh = 3;
2073
				
2239
2074
				c= getColor(display, getFillColor(diff));
2240
				c = getColor(display, getFillColor(diff));
2075
				if (c != null) {
2241
				if (c != null) {
2076
					gc.setBackground(c);
2242
					gc.setBackground(c);
2077
					gc.fillRectangle(BIRDS_EYE_VIEW_INSET, yy, size.x-(2*BIRDS_EYE_VIEW_INSET),hh);
2243
					gc.fillRectangle(BIRDS_EYE_VIEW_INSET, yy, size.x
2244
							- (2 * BIRDS_EYE_VIEW_INSET), hh);
2078
				}
2245
				}
2079
				c= getColor(display, getStrokeColor(diff));
2246
				c = getColor(display, getStrokeColor(diff));
2080
				if (c != null) {
2247
				if (c != null) {
2081
					gc.setForeground(c);
2248
					gc.setForeground(c);
2082
					r.x= BIRDS_EYE_VIEW_INSET;
2249
					r.x = BIRDS_EYE_VIEW_INSET;
2083
					r.y= yy;
2250
					r.y = yy;
2084
					r.width= size.x-(2*BIRDS_EYE_VIEW_INSET)-1;
2251
					r.width = size.x - (2 * BIRDS_EYE_VIEW_INSET) - 1;
2085
					r.height= hh;
2252
					r.height = hh;
2086
					if (isCurrentDiff(diff)) {
2253
					if (isCurrentDiff(diff)) {
2087
						gc.setLineWidth(2);
2254
						gc.setLineWidth(2);
2088
						r.x++;
2255
						r.x++;
Lines 2095-2223 Link Here
2095
					gc.drawRectangle(r);
2262
					gc.drawRectangle(r);
2096
				}
2263
				}
2097
			}
2264
			}
2098
			
2265
2099
			y+= h;
2266
			y += h;
2100
		}
2267
		}
2101
	}
2268
	}
2102
	
2269
2103
	private void refreshBirdsEyeView() {
2270
	private void refreshBirdsEyeView() {
2104
		if (fBirdsEyeCanvas != null)
2271
		if (fBirdsEyeCanvas != null)
2105
			fBirdsEyeCanvas.redraw();
2272
			fBirdsEyeCanvas.redraw();
2106
	}
2273
	}
2107
	
2274
2108
	/**
2275
	/**
2109
	 * Override to give focus to the pane that previously had focus or to a suitable
2276
	 * Override to give focus to the pane that previously had focus or to a
2110
	 * default pane.
2277
	 * suitable default pane.
2278
	 * 
2111
	 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#handleSetFocus()
2279
	 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#handleSetFocus()
2112
	 * @since 3.3
2280
	 * @since 3.3
2113
	 */
2281
	 */
2114
	protected boolean handleSetFocus() {
2282
	protected boolean handleSetFocus() {
2115
		if (fFocusPart == null) {
2283
		if (fFocusPart == null) {
2116
			if (fLeft != null && fLeft.getEnabled()) {
2284
			if (fLeft != null && fLeft.getEnabled()) {
2117
				fFocusPart= fLeft;
2285
				fFocusPart = fLeft;
2118
			} else if (fRight != null && fRight.getEnabled()) {
2286
			} else if (fRight != null && fRight.getEnabled()) {
2119
				fFocusPart= fRight;
2287
				fFocusPart = fRight;
2120
			} else if (fAncestor != null && fAncestor.getEnabled()) {
2288
			} else if (fAncestor != null && fAncestor.getEnabled()) {
2121
				fFocusPart= fAncestor;
2289
				fFocusPart = fAncestor;
2122
			}
2290
			}
2123
		}
2291
		}
2124
		if (fFocusPart != null) {
2292
		if (fFocusPart != null) {
2125
			StyledText st= fFocusPart.getTextWidget();
2293
			StyledText st = fFocusPart.getTextWidget();
2126
			if (st != null)
2294
			if (st != null)
2127
				return st.setFocus();
2295
				return st.setFocus();
2128
		}
2296
		}
2129
		return false;	// could not set focus
2297
		return false; // could not set focus
2130
	}
2298
	}
2131
	
2299
2132
	
2133
	class HoverResizer extends Resizer {
2300
	class HoverResizer extends Resizer {
2134
		Canvas fCanvas;
2301
		Canvas fCanvas;
2302
2135
		public HoverResizer(Canvas c, int dir) {
2303
		public HoverResizer(Canvas c, int dir) {
2136
			super(c, dir);
2304
			super(c, dir);
2137
			fCanvas= c;
2305
			fCanvas = c;
2138
		}
2306
		}
2307
2139
		public void mouseMove(MouseEvent e) {
2308
		public void mouseMove(MouseEvent e) {
2140
			if (!fIsDown && fUseSingleLine && showResolveUI() && handleMouseMoveOverCenter(fCanvas, e.x, e.y))
2309
			if (!fIsDown && fUseSingleLine && showResolveUI()
2310
					&& handleMouseMoveOverCenter(fCanvas, e.x, e.y))
2141
				return;
2311
				return;
2142
			super.mouseMove(e);
2312
			super.mouseMove(e);
2143
		}
2313
		}
2144
	}
2314
	}
2145
	
2315
2146
	/* (non-Javadoc)
2316
	/*
2147
	 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#createCenterControl(org.eclipse.swt.widgets.Composite)
2317
	 * (non-Javadoc)
2318
	 * 
2319
	 * @see
2320
	 * org.eclipse.compare.contentmergeviewer.ContentMergeViewer#createCenterControl
2321
	 * (org.eclipse.swt.widgets.Composite)
2148
	 */
2322
	 */
2149
	protected final Control createCenterControl(Composite parent) {
2323
	protected final Control createCenterControl(Composite parent) {
2150
		if (fSynchronizedScrolling) {
2324
		if (fSynchronizedScrolling) {
2151
			final Canvas canvas= new BufferedCanvas(parent, SWT.NONE) {
2325
			final Canvas canvas = new BufferedCanvas(parent, SWT.NONE) {
2152
				public void doPaint(GC gc) {
2326
				public void doPaint(GC gc) {
2153
					paintCenter(this, gc);
2327
					paintCenter(this, gc);
2154
				}
2328
				}
2155
			};
2329
			};
2156
			if (fUseResolveUI) {
2330
			if (fUseResolveUI) {
2157
				
2331
2158
				new HoverResizer(canvas, HORIZONTAL);
2332
				new HoverResizer(canvas, HORIZONTAL);
2159
								
2333
2160
				fCenterButton= new Button(canvas, fIsCarbon ? SWT.FLAT : SWT.PUSH);
2334
				fCenterButton = new Button(canvas, fIsCarbon ? SWT.FLAT
2161
				if (fNormalCursor == null) fNormalCursor= new Cursor(canvas.getDisplay(), SWT.CURSOR_ARROW);
2335
						: SWT.PUSH);
2336
				if (fNormalCursor == null)
2337
					fNormalCursor = new Cursor(canvas.getDisplay(),
2338
							SWT.CURSOR_ARROW);
2162
				fCenterButton.setCursor(fNormalCursor);
2339
				fCenterButton.setCursor(fNormalCursor);
2163
				fCenterButton.setText(COPY_RIGHT_TO_LEFT_INDICATOR);
2340
				fCenterButton.setText(COPY_RIGHT_TO_LEFT_INDICATOR);
2164
				fCenterButton.pack();
2341
				fCenterButton.pack();
2165
				fCenterButton.setVisible(false);
2342
				fCenterButton.setVisible(false);
2166
				fCenterButton.addSelectionListener(
2343
				fCenterButton.addSelectionListener(new SelectionAdapter() {
2167
					new SelectionAdapter() {
2344
					public void widgetSelected(SelectionEvent e) {
2168
						public void widgetSelected(SelectionEvent e) {
2345
						fCenterButton.setVisible(false);
2169
							fCenterButton.setVisible(false);
2346
						if (fButtonDiff != null) {
2170
							if (fButtonDiff != null) {
2347
							setCurrentDiff(fButtonDiff, false);
2171
								setCurrentDiff(fButtonDiff, false);
2348
							copy(fCurrentDiff, fCenterButton.getText().equals(
2172
								copy(fCurrentDiff,
2349
									COPY_LEFT_TO_RIGHT_INDICATOR), fCurrentDiff
2173
										fCenterButton.getText().equals(COPY_LEFT_TO_RIGHT_INDICATOR),
2350
									.getKind() != RangeDifference.CONFLICT);
2174
										fCurrentDiff.getKind() != RangeDifference.CONFLICT);
2175
							}
2176
						}
2351
						}
2177
					}
2352
					}
2178
				);
2353
				});
2179
			} else {
2354
			} else {
2180
				new Resizer(canvas, HORIZONTAL);
2355
				new Resizer(canvas, HORIZONTAL);
2181
			}
2356
			}
2182
			
2357
2183
			return canvas;
2358
			return canvas;
2184
		}
2359
		}
2185
		return super.createCenterControl(parent);
2360
		return super.createCenterControl(parent);
2186
	}
2361
	}
2187
	
2362
2188
	private boolean handleMouseMoveOverCenter(Canvas canvas, int x, int y) {
2363
	private boolean handleMouseMoveOverCenter(Canvas canvas, int x, int y) {
2189
		Rectangle r= new Rectangle(0, 0, 0, 0);
2364
		Rectangle r = new Rectangle(0, 0, 0, 0);
2190
		Diff diff= getDiffUnderMouse(canvas, x, y, r);
2365
		Diff diff = getDiffUnderMouse(canvas, x, y, r);
2191
		if (diff != null && !diff.isUnresolvedIncomingOrConflicting())
2366
		if (diff != null && !diff.isUnresolvedIncomingOrConflicting())
2192
			diff= null;
2367
			diff = null;
2193
		if (diff != fButtonDiff) {
2368
		if (diff != fButtonDiff) {
2194
			if (diff != null) {
2369
			if (diff != null) {
2195
				if (fLeft.isEditable()) {
2370
				if (fLeft.isEditable()) {
2196
					fButtonDiff= diff;
2371
					fButtonDiff = diff;
2197
					fCenterButton.setText(COPY_RIGHT_TO_LEFT_INDICATOR);
2372
					fCenterButton.setText(COPY_RIGHT_TO_LEFT_INDICATOR);
2198
					String tt= fCopyDiffRightToLeftItem.getAction().getToolTipText();
2373
					String tt = fCopyDiffRightToLeftItem.getAction()
2374
							.getToolTipText();
2199
					fCenterButton.setToolTipText(tt);
2375
					fCenterButton.setToolTipText(tt);
2200
					fCenterButton.setBounds(r);
2376
					fCenterButton.setBounds(r);
2201
					fCenterButton.setVisible(true);
2377
					fCenterButton.setVisible(true);
2202
				} else if (fRight.isEditable()) {
2378
				} else if (fRight.isEditable()) {
2203
					fButtonDiff= diff;
2379
					fButtonDiff = diff;
2204
					fCenterButton.setText(COPY_LEFT_TO_RIGHT_INDICATOR);
2380
					fCenterButton.setText(COPY_LEFT_TO_RIGHT_INDICATOR);
2205
					String tt= fCopyDiffLeftToRightItem.getAction().getToolTipText();
2381
					String tt = fCopyDiffLeftToRightItem.getAction()
2382
							.getToolTipText();
2206
					fCenterButton.setToolTipText(tt);
2383
					fCenterButton.setToolTipText(tt);
2207
					fCenterButton.setBounds(r);
2384
					fCenterButton.setBounds(r);
2208
					fCenterButton.setVisible(true);
2385
					fCenterButton.setVisible(true);
2209
				} else
2386
				} else
2210
					fButtonDiff= null;
2387
					fButtonDiff = null;
2211
			} else {
2388
			} else {
2212
				fCenterButton.setVisible(false);
2389
				fCenterButton.setVisible(false);
2213
				fButtonDiff= null;
2390
				fButtonDiff = null;
2214
			}
2391
			}
2215
		}
2392
		}
2216
		return fButtonDiff != null;
2393
		return fButtonDiff != null;
2217
	}
2394
	}
2218
	
2395
2219
	/* (non-Javadoc)
2396
	/*
2220
	 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#getCenterWidth()
2397
	 * (non-Javadoc)
2398
	 * 
2399
	 * @see
2400
	 * org.eclipse.compare.contentmergeviewer.ContentMergeViewer#getCenterWidth
2401
	 * ()
2221
	 */
2402
	 */
2222
	protected final int getCenterWidth() {
2403
	protected final int getCenterWidth() {
2223
		if (fSynchronizedScrolling)
2404
		if (fSynchronizedScrolling)
Lines 2235-2356 Link Here
2235
		}
2416
		}
2236
		return fInheritedDirection;
2417
		return fInheritedDirection;
2237
	}
2418
	}
2238
	
2419
2239
	/*
2420
	/*
2240
	 * Creates and initializes a text part.
2421
	 * Creates and initializes a text part.
2241
	 */
2422
	 */
2242
	private MergeSourceViewer createPart(Composite parent) {
2423
	private MergeSourceViewer createPart(Composite parent) {
2243
		
2424
2244
		final MergeSourceViewer part= new MergeSourceViewer(parent, getDirection(), getResourceBundle(), getCompareConfiguration().getContainer());
2425
		final MergeSourceViewer part = new MergeSourceViewer(parent,
2245
		final StyledText te= part.getTextWidget();
2426
				getDirection(), getResourceBundle(), getCompareConfiguration()
2246
		
2427
						.getContainer());
2428
		final StyledText te = part.getTextWidget();
2429
2247
		if (!fConfirmSave)
2430
		if (!fConfirmSave)
2248
			part.hideSaveAction();
2431
			part.hideSaveAction();
2249
		
2432
2250
		te.addPaintListener(
2433
		te.addPaintListener(new PaintListener() {
2251
			new PaintListener() {
2434
			public void paintControl(PaintEvent e) {
2252
				public void paintControl(PaintEvent e) {
2435
				paint(e, part);
2253
					paint(e, part);
2254
				}
2255
			}
2256
		);
2257
		te.addKeyListener(
2258
			new KeyAdapter() {
2259
				public void keyPressed(KeyEvent e) {
2260
					handleSelectionChanged(part);
2261
				}
2262
			}
2263
		);
2264
		te.addMouseListener(
2265
			new MouseAdapter() {
2266
				public void mouseDown(MouseEvent e) {
2267
					//syncViewport(part);
2268
					handleSelectionChanged(part);
2269
				}
2270
			}
2436
			}
2271
		);
2437
		});
2272
					
2438
		te.addKeyListener(new KeyAdapter() {
2273
		te.addFocusListener(
2439
			public void keyPressed(KeyEvent e) {
2274
			new FocusAdapter() {
2440
				handleSelectionChanged(part);
2275
				public void focusGained(FocusEvent fe) {
2276
					fFocusPart= part;
2277
					connectGlobalActions(fFocusPart);
2278
				}
2279
				public void focusLost(FocusEvent fe) {
2280
					connectGlobalActions(null);
2281
				}
2282
			}
2441
			}
2283
		);
2442
		});
2284
		
2443
		te.addMouseListener(new MouseAdapter() {
2285
		part.addViewportListener(
2444
			public void mouseDown(MouseEvent e) {
2286
			new IViewportListener() {
2445
				// syncViewport(part);
2287
				public void viewportChanged(int verticalPosition) {
2446
				handleSelectionChanged(part);
2288
					syncViewport(part);
2447
			}
2289
				}
2448
		});
2449
2450
		te.addFocusListener(new FocusAdapter() {
2451
			public void focusGained(FocusEvent fe) {
2452
				fFocusPart = part;
2453
				connectGlobalActions(fFocusPart);
2454
			}
2455
2456
			public void focusLost(FocusEvent fe) {
2457
				connectGlobalActions(null);
2458
			}
2459
		});
2460
2461
		part.addViewportListener(new IViewportListener() {
2462
			public void viewportChanged(int verticalPosition) {
2463
				syncViewport(part);
2290
			}
2464
			}
2291
		);
2465
		});
2292
		
2466
2293
		Font font= JFaceResources.getFont(fSymbolicFontName);
2467
		Font font = JFaceResources.getFont(fSymbolicFontName);
2294
		if (font != null)
2468
		if (font != null)
2295
			te.setFont(font);
2469
			te.setFont(font);
2296
		
2470
2297
		if (fBackground != null)	// not default
2471
		if (fBackground != null) // not default
2298
			te.setBackground(getColor(parent.getDisplay(), fBackground));
2472
			te.setBackground(getColor(parent.getDisplay(), fBackground));
2299
		
2473
2300
		// Add the find action to the popup menu of the viewer
2474
		// Add the find action to the popup menu of the viewer
2301
		contributeFindAction(part);
2475
		contributeFindAction(part);
2302
		
2476
2303
		contributeGotoLineAction(part);
2477
		contributeGotoLineAction(part);
2304
2478
2305
		configureTextViewer(part);
2479
		configureTextViewer(part);
2306
		
2480
2307
		getSourceViewerDecorationSupport(part).install(fPreferenceStore);
2481
		getSourceViewerDecorationSupport(part).install(fPreferenceStore);
2308
2482
2309
		return part;
2483
		return part;
2310
	}
2484
	}
2311
2485
2312
	private SourceViewerDecorationSupport getSourceViewerDecorationSupport(ISourceViewer viewer) {
2486
	private SourceViewerDecorationSupport getSourceViewerDecorationSupport(
2313
		SourceViewerDecorationSupport support = new SourceViewerDecorationSupport(viewer, null, null, EditorsUI.getSharedTextColors());
2487
			ISourceViewer viewer) {
2314
		support.setCursorLinePainterPreferenceKeys(CURRENT_LINE, CURRENT_LINE_COLOR);
2488
		SourceViewerDecorationSupport support = new SourceViewerDecorationSupport(
2489
				viewer, null, null, EditorsUI.getSharedTextColors());
2490
		support.setCursorLinePainterPreferenceKeys(CURRENT_LINE,
2491
				CURRENT_LINE_COLOR);
2315
		fSourceViewerDecorationSupport.add(support);
2492
		fSourceViewerDecorationSupport.add(support);
2316
		return support;
2493
		return support;
2317
	}
2494
	}
2318
2495
2319
	private void contributeFindAction(MergeSourceViewer viewer) {
2496
	private void contributeFindAction(MergeSourceViewer viewer) {
2320
		IAction action;
2497
		IAction action;
2321
		IWorkbenchPart wp = getCompareConfiguration().getContainer().getWorkbenchPart();
2498
		IWorkbenchPart wp = getCompareConfiguration().getContainer()
2499
				.getWorkbenchPart();
2322
		if (wp != null)
2500
		if (wp != null)
2323
			action = new FindReplaceAction(getResourceBundle(), "Editor.FindReplace.", wp); //$NON-NLS-1$
2501
			action = new FindReplaceAction(getResourceBundle(),
2502
					"Editor.FindReplace.", wp); //$NON-NLS-1$
2324
		else
2503
		else
2325
			action = new FindReplaceAction(getResourceBundle(), "Editor.FindReplace.", viewer.getControl().getShell(), getFindReplaceTarget()); //$NON-NLS-1$
2504
			action = new FindReplaceAction(
2326
		action.setActionDefinitionId(IWorkbenchActionDefinitionIds.FIND_REPLACE);
2505
					getResourceBundle(),
2506
					"Editor.FindReplace.", viewer.getControl().getShell(), getFindReplaceTarget()); //$NON-NLS-1$
2507
		action
2508
				.setActionDefinitionId(IWorkbenchActionDefinitionIds.FIND_REPLACE);
2327
		viewer.addAction(MergeSourceViewer.FIND_ID, action);
2509
		viewer.addAction(MergeSourceViewer.FIND_ID, action);
2328
	}
2510
	}
2329
	
2511
2330
	private void contributeGotoLineAction(MergeSourceViewer viewer) {
2512
	private void contributeGotoLineAction(MergeSourceViewer viewer) {
2331
		IAction action = new GotoLineAction(viewer.getTextEditorAdapter());
2513
		IAction action = new GotoLineAction(viewer.getTextEditorAdapter());
2332
		action.setActionDefinitionId(ITextEditorActionDefinitionIds.LINE_GOTO);
2514
		action.setActionDefinitionId(ITextEditorActionDefinitionIds.LINE_GOTO);
2333
		viewer.addAction(MergeSourceViewer.GOTO_LINE_ID, action);
2515
		viewer.addAction(MergeSourceViewer.GOTO_LINE_ID, action);
2334
	}
2516
	}
2335
2517
2518
	private void contributeCreatePatchAction(MergeSourceViewer viewer,
2519
			boolean rightToLeft) {
2520
		IAction action = new CreatePatchAction(this, rightToLeft);
2521
		viewer.addAction(MergeSourceViewer.CREATE_PATCH_ID, action);
2522
	}
2523
2336
	private void connectGlobalActions(final MergeSourceViewer part) {
2524
	private void connectGlobalActions(final MergeSourceViewer part) {
2337
		if (fHandlerService != null) {
2525
		if (fHandlerService != null) {
2338
			if (part != null)
2526
			if (part != null)
2339
				part.updateActions();
2527
				part.updateActions();
2340
			fHandlerService.updatePaneActionHandlers(new Runnable() {
2528
			fHandlerService.updatePaneActionHandlers(new Runnable() {
2341
				public void run() {
2529
				public void run() {
2342
					for (int i= 0; i < GLOBAL_ACTIONS.length; i++) {
2530
					for (int i = 0; i < GLOBAL_ACTIONS.length; i++) {
2343
						IAction action= null;
2531
						IAction action = null;
2344
						if (part != null) {
2532
						if (part != null) {
2345
							action= part.getAction(TEXT_ACTIONS[i]);
2533
							action = part.getAction(TEXT_ACTIONS[i]);
2346
							if (action == null && TEXT_ACTIONS[i].equals(MergeSourceViewer.SAVE_ID)) {
2534
							if (action == null
2535
									&& TEXT_ACTIONS[i]
2536
											.equals(MergeSourceViewer.SAVE_ID)) {
2347
								if (part == fLeft)
2537
								if (part == fLeft)
2348
									action= fLeftSaveAction;
2538
									action = fLeftSaveAction;
2349
								else
2539
								else
2350
									action= fRightSaveAction;
2540
									action = fRightSaveAction;
2351
							}
2541
							}
2352
						}
2542
						}
2353
						fHandlerService.setGlobalActionHandler(GLOBAL_ACTIONS[i], action);
2543
						fHandlerService.setGlobalActionHandler(
2544
								GLOBAL_ACTIONS[i], action);
2354
					}
2545
					}
2355
				}
2546
				}
2356
			});
2547
			});
Lines 2361-2367 Link Here
2361
		if (element instanceof IDocument) {
2552
		if (element instanceof IDocument) {
2362
			return (IDocument) element;
2553
			return (IDocument) element;
2363
		}
2554
		}
2364
		ITypedElement te= Utilities.getLeg(type, element);
2555
		ITypedElement te = Utilities.getLeg(type, element);
2365
		// First check the contributors for the document
2556
		// First check the contributors for the document
2366
		IDocument document = null;
2557
		IDocument document = null;
2367
		switch (type) {
2558
		switch (type) {
Lines 2377-2591 Link Here
2377
		}
2568
		}
2378
		if (document != null)
2569
		if (document != null)
2379
			return document;
2570
			return document;
2380
		// The document is not associated with the input of the viewer so try to find the document
2571
		// The document is not associated with the input of the viewer so try to
2381
		return Utilities.getDocument(type, element, isUsingDefaultContentProvider(), canHaveSharedDocument());
2572
		// find the document
2573
		return Utilities.getDocument(type, element,
2574
				isUsingDefaultContentProvider(), canHaveSharedDocument());
2382
	}
2575
	}
2383
	
2576
2384
	private boolean isUsingDefaultContentProvider() {
2577
	private boolean isUsingDefaultContentProvider() {
2385
		return getContentProvider() instanceof MergeViewerContentProvider;
2578
		return getContentProvider() instanceof MergeViewerContentProvider;
2386
	}
2579
	}
2387
	
2580
2388
	private boolean canHaveSharedDocument() {
2581
	private boolean canHaveSharedDocument() {
2389
		return getDocumentPartitioning() != null
2582
		return getDocumentPartitioning() != null
2390
			|| getDocumentPartitioner() == null;
2583
				|| getDocumentPartitioner() == null;
2391
	}
2584
	}
2392
	
2585
2393
	private IDocument getDocument(ITypedElement te, ContributorInfo info) {
2586
	private IDocument getDocument(ITypedElement te, ContributorInfo info) {
2394
		if (info != null && info.getElement() == te)
2587
		if (info != null && info.getElement() == te)
2395
			return info.getDocument();
2588
			return info.getDocument();
2396
		return null;
2589
		return null;
2397
	}
2590
	}
2398
	
2591
2399
	IDocument getDocument(char type, Object input) {
2592
	IDocument getDocument(char type, Object input) {
2400
		IDocument doc= getElementDocument(type, input);
2593
		IDocument doc = getElementDocument(type, input);
2401
		if (doc != null)
2594
		if (doc != null)
2402
			return doc;
2595
			return doc;
2403
			
2596
2404
		if (input instanceof IDiffElement) {
2597
		if (input instanceof IDiffElement) {
2405
			IDiffContainer parent= ((IDiffElement)input).getParent();
2598
			IDiffContainer parent = ((IDiffElement) input).getParent();
2406
			return getElementDocument(type, parent);
2599
			return getElementDocument(type, parent);
2407
		}
2600
		}
2408
		return null;
2601
		return null;
2409
	}
2602
	}
2410
	
2603
2411
	/*
2604
	/*
2412
	 * Returns true if the given inputs map to the same documents
2605
	 * Returns true if the given inputs map to the same documents
2413
	 */
2606
	 */
2414
	boolean sameDoc(char type, Object newInput, Object oldInput) {
2607
	boolean sameDoc(char type, Object newInput, Object oldInput) {
2415
		IDocument newDoc= getDocument(type, newInput);
2608
		IDocument newDoc = getDocument(type, newInput);
2416
		IDocument oldDoc= getDocument(type, oldInput);
2609
		IDocument oldDoc = getDocument(type, oldInput);
2417
		return newDoc == oldDoc;
2610
		return newDoc == oldDoc;
2418
	}
2611
	}
2419
	
2612
2420
	/**
2613
	/**
2421
	 * Overridden to prevent save confirmation if new input is sub document of current input.
2614
	 * Overridden to prevent save confirmation if new input is sub document of
2422
	 * @param newInput the new input of this viewer, or <code>null</code> if there is no new input
2615
	 * current input.
2423
	 * @param oldInput the old input element, or <code>null</code> if there was previously no input
2616
	 * 
2424
	 * @return <code>true</code> if saving was successful, or if the user didn't want to save (by pressing 'NO' in the confirmation dialog).
2617
	 * @param newInput
2618
	 *            the new input of this viewer, or <code>null</code> if there is
2619
	 *            no new input
2620
	 * @param oldInput
2621
	 *            the old input element, or <code>null</code> if there was
2622
	 *            previously no input
2623
	 * @return <code>true</code> if saving was successful, or if the user didn't
2624
	 *         want to save (by pressing 'NO' in the confirmation dialog).
2425
	 * @since 2.0
2625
	 * @since 2.0
2426
	 */
2626
	 */
2427
	protected boolean doSave(Object newInput, Object oldInput) {
2627
	protected boolean doSave(Object newInput, Object oldInput) {
2428
		// TODO: Would be good if this could be restated in terms of Saveables and moved up
2628
		// TODO: Would be good if this could be restated in terms of Saveables
2629
		// and moved up
2429
		if (oldInput != null && newInput != null) {
2630
		if (oldInput != null && newInput != null) {
2430
			// check whether underlying documents have changed.
2631
			// check whether underlying documents have changed.
2431
			if (sameDoc(ANCESTOR_CONTRIBUTOR, newInput, oldInput) &&
2632
			if (sameDoc(ANCESTOR_CONTRIBUTOR, newInput, oldInput)
2432
					sameDoc(LEFT_CONTRIBUTOR, newInput, oldInput) &&
2633
					&& sameDoc(LEFT_CONTRIBUTOR, newInput, oldInput)
2433
						sameDoc(RIGHT_CONTRIBUTOR, newInput, oldInput)) {
2634
					&& sameDoc(RIGHT_CONTRIBUTOR, newInput, oldInput)) {
2434
				if (DEBUG) System.out.println("----- Same docs !!!!");	//$NON-NLS-1$
2635
				if (DEBUG)
2636
					System.out.println("----- Same docs !!!!"); //$NON-NLS-1$
2435
				return false;
2637
				return false;
2436
			}
2638
			}
2437
		}
2639
		}
2438
		
2640
2439
		if (DEBUG) System.out.println("***** New docs !!!!");	//$NON-NLS-1$
2641
		if (DEBUG)
2440
		
2642
			System.out.println("***** New docs !!!!"); //$NON-NLS-1$
2643
2441
		removeFromDocumentManager(ANCESTOR_CONTRIBUTOR, oldInput);
2644
		removeFromDocumentManager(ANCESTOR_CONTRIBUTOR, oldInput);
2442
		removeFromDocumentManager(LEFT_CONTRIBUTOR, oldInput);
2645
		removeFromDocumentManager(LEFT_CONTRIBUTOR, oldInput);
2443
		removeFromDocumentManager(RIGHT_CONTRIBUTOR, oldInput);
2646
		removeFromDocumentManager(RIGHT_CONTRIBUTOR, oldInput);
2444
		
2647
2445
		if (DEBUG)
2648
		if (DEBUG)
2446
			DocumentManager.dump();
2649
			DocumentManager.dump();
2447
		
2650
2448
		return super.doSave(newInput, oldInput);
2651
		return super.doSave(newInput, oldInput);
2449
	}
2652
	}
2450
	
2653
2451
	private void removeFromDocumentManager(char leg, Object oldInput) {
2654
	private void removeFromDocumentManager(char leg, Object oldInput) {
2452
		IDocument document= getDocument(leg, oldInput);
2655
		IDocument document = getDocument(leg, oldInput);
2453
		if (document != null)
2656
		if (document != null)
2454
			DocumentManager.remove(document);
2657
			DocumentManager.remove(document);
2455
	}
2658
	}
2456
	
2659
2457
	private ITypedElement getParent(char type) {
2660
	private ITypedElement getParent(char type) {
2458
		Object input= getInput();
2661
		Object input = getInput();
2459
		if (input instanceof IDiffElement) {
2662
		if (input instanceof IDiffElement) {
2460
			IDiffContainer parent= ((IDiffElement)input).getParent();
2663
			IDiffContainer parent = ((IDiffElement) input).getParent();
2461
			return Utilities.getLeg(type, parent);
2664
			return Utilities.getLeg(type, parent);
2462
		}
2665
		}
2463
		return null;
2666
		return null;
2464
	}
2667
	}
2465
		
2668
2466
	/*
2669
	/*
2467
	 * Initializes the text viewers of the three content areas with the given input objects.
2670
	 * Initializes the text viewers of the three content areas with the given
2468
	 * Subclasses may extend.
2671
	 * input objects. Subclasses may extend.
2469
	 */
2672
	 */
2470
	protected void updateContent(Object ancestor, Object left, Object right) {
2673
	protected void updateContent(Object ancestor, Object left, Object right) {
2471
		
2472
		boolean emptyInput= (ancestor == null && left == null && right == null);
2473
2674
2474
		Object input= getInput();
2675
		boolean emptyInput = (ancestor == null && left == null && right == null);
2676
2677
		Object input = getInput();
2678
2679
		Position leftRange = null;
2680
		Position rightRange = null;
2475
2681
2476
		Position leftRange= null;
2477
		Position rightRange= null;
2478
		
2479
		// if one side is empty use container
2682
		// if one side is empty use container
2480
		if (FIX_47640 && !emptyInput && (left == null || right == null)) {
2683
		if (FIX_47640 && !emptyInput && (left == null || right == null)) {
2481
			if (input instanceof IDiffElement) {
2684
			if (input instanceof IDiffElement) {
2482
				IDiffContainer parent= ((IDiffElement)input).getParent();
2685
				IDiffContainer parent = ((IDiffElement) input).getParent();
2483
				if (parent instanceof ICompareInput) {
2686
				if (parent instanceof ICompareInput) {
2484
				    ICompareInput ci= (ICompareInput) parent;
2687
					ICompareInput ci = (ICompareInput) parent;
2485
				    
2688
2486
				    if (ci.getAncestor() instanceof IDocumentRange
2689
					if (ci.getAncestor() instanceof IDocumentRange
2487
				            || ci.getLeft() instanceof IDocumentRange
2690
							|| ci.getLeft() instanceof IDocumentRange
2488
				            		|| ci.getRight() instanceof IDocumentRange) {
2691
							|| ci.getRight() instanceof IDocumentRange) {
2489
				    
2692
2490
				        	if (left instanceof IDocumentRange)
2693
						if (left instanceof IDocumentRange)
2491
				        	    leftRange= ((IDocumentRange)left).getRange();
2694
							leftRange = ((IDocumentRange) left).getRange();
2492
				        	if (right instanceof IDocumentRange)
2695
						if (right instanceof IDocumentRange)
2493
				        	    rightRange= ((IDocumentRange)right).getRange();
2696
							rightRange = ((IDocumentRange) right).getRange();
2494
					    
2697
2495
					    ancestor= ci.getAncestor();
2698
						ancestor = ci.getAncestor();
2496
					    left= ci.getLeft();
2699
						left = ci.getLeft();
2497
					    right= ci.getRight();
2700
						right = ci.getRight();
2498
				    }
2701
					}
2499
				}
2702
				}
2500
			}
2703
			}
2501
		}
2704
		}
2502
2705
2503
		int n= 0;
2706
		int n = 0;
2504
		if (left != null)
2707
		if (left != null)
2505
			n++;
2708
			n++;
2506
		if (right != null)
2709
		if (right != null)
2507
			n++;
2710
			n++;
2508
		fHighlightRanges= n > 1;
2711
		fHighlightRanges = n > 1;
2509
		
2712
2510
		resetDiffs();
2713
		resetDiffs();
2511
		fHasErrors= false; // start with no errors
2714
		fHasErrors = false; // start with no errors
2512
		
2715
2513
		CompareConfiguration cc= getCompareConfiguration();
2716
		CompareConfiguration cc = getCompareConfiguration();
2514
		IMergeViewerContentProvider cp= getMergeContentProvider();
2717
		IMergeViewerContentProvider cp = getMergeContentProvider();
2515
		
2718
2516
		if (cp instanceof MergeViewerContentProvider) {
2719
		if (cp instanceof MergeViewerContentProvider) {
2517
			MergeViewerContentProvider mcp= (MergeViewerContentProvider) cp;
2720
			MergeViewerContentProvider mcp = (MergeViewerContentProvider) cp;
2518
			mcp.setAncestorError(null);
2721
			mcp.setAncestorError(null);
2519
			mcp.setLeftError(null);
2722
			mcp.setLeftError(null);
2520
			mcp.setRightError(null);
2723
			mcp.setRightError(null);
2521
		}
2724
		}
2522
2725
2523
		// Record current contributors so we disconnect after creating the new ones.
2726
		// Record current contributors so we disconnect after creating the new
2727
		// ones.
2524
		// This is done in case the old and new use the same document.
2728
		// This is done in case the old and new use the same document.
2525
		ContributorInfo oldLeftContributor = fLeftContributor;
2729
		ContributorInfo oldLeftContributor = fLeftContributor;
2526
		ContributorInfo oldRightContributor = fRightContributor;
2730
		ContributorInfo oldRightContributor = fRightContributor;
2527
		ContributorInfo oldAncestorContributor = fAncestorContributor;
2731
		ContributorInfo oldAncestorContributor = fAncestorContributor;
2528
		
2732
2529
		// Create the new contributor
2733
		// Create the new contributor
2530
		fLeftContributor = createLegInfoFor(left, LEFT_CONTRIBUTOR);
2734
		fLeftContributor = createLegInfoFor(left, LEFT_CONTRIBUTOR);
2531
		fRightContributor = createLegInfoFor(right, RIGHT_CONTRIBUTOR);
2735
		fRightContributor = createLegInfoFor(right, RIGHT_CONTRIBUTOR);
2532
		fAncestorContributor = createLegInfoFor(ancestor, ANCESTOR_CONTRIBUTOR);
2736
		fAncestorContributor = createLegInfoFor(ancestor, ANCESTOR_CONTRIBUTOR);
2533
		
2737
2534
		fLeftContributor.transferContributorStateFrom(oldLeftContributor);
2738
		fLeftContributor.transferContributorStateFrom(oldLeftContributor);
2535
		fRightContributor.transferContributorStateFrom(oldRightContributor);
2739
		fRightContributor.transferContributorStateFrom(oldRightContributor);
2536
		fAncestorContributor.transferContributorStateFrom(oldAncestorContributor);
2740
		fAncestorContributor
2537
		
2741
				.transferContributorStateFrom(oldAncestorContributor);
2742
2538
		// Now disconnect the old ones
2743
		// Now disconnect the old ones
2539
		disconnect(oldLeftContributor);
2744
		disconnect(oldLeftContributor);
2540
		disconnect(oldRightContributor);
2745
		disconnect(oldRightContributor);
2541
		disconnect(oldAncestorContributor);
2746
		disconnect(oldAncestorContributor);
2542
		
2747
2543
		// Get encodings from streams. If an encoding is null, abide by the other one
2748
		// Get encodings from streams. If an encoding is null, abide by the
2749
		// other one
2544
		// Defaults to workbench encoding only if both encodings are null
2750
		// Defaults to workbench encoding only if both encodings are null
2545
		fLeftContributor.setEncodingIfAbsent(fRightContributor);
2751
		fLeftContributor.setEncodingIfAbsent(fRightContributor);
2546
		fRightContributor.setEncodingIfAbsent(fLeftContributor);
2752
		fRightContributor.setEncodingIfAbsent(fLeftContributor);
2547
		fAncestorContributor.setEncodingIfAbsent(fLeftContributor);
2753
		fAncestorContributor.setEncodingIfAbsent(fLeftContributor);
2548
		
2754
2549
		// set new documents
2755
		// set new documents
2550
		fLeftContributor.setDocument(fLeft, cc.isLeftEditable() && cp.isLeftEditable(input));
2756
		fLeftContributor.setDocument(fLeft, cc.isLeftEditable()
2551
		fLeftLineCount= fLeft.getLineCount();
2757
				&& cp.isLeftEditable(input));
2552
		
2758
		fLeftLineCount = fLeft.getLineCount();
2553
		fRightContributor.setDocument(fRight, cc.isRightEditable() && cp.isRightEditable(input));
2759
2554
		fRightLineCount= fRight.getLineCount();
2760
		fRightContributor.setDocument(fRight, cc.isRightEditable()
2555
		
2761
				&& cp.isRightEditable(input));
2762
		fRightLineCount = fRight.getLineCount();
2763
2556
		fAncestorContributor.setDocument(fAncestor, false);
2764
		fAncestorContributor.setDocument(fAncestor, false);
2557
2765
2558
		//if the input is part of a patch hunk, toggle synchronized scrolling
2766
		// if the input is part of a patch hunk, toggle synchronized scrolling
2559
		/*if (isPatchHunk()){
2767
		/*
2560
			setSyncScrolling(false);
2768
		 * if (isPatchHunk()){ setSyncScrolling(false); } else {
2561
		} else {
2769
		 * setSyncScrolling
2562
			setSyncScrolling(fPreferenceStore.getBoolean(ComparePreferencePage.SYNCHRONIZE_SCROLLING));
2770
		 * (fPreferenceStore.getBoolean(ComparePreferencePage.SYNCHRONIZE_SCROLLING
2563
		}*/
2771
		 * )); }
2564
		setSyncScrolling(fPreferenceStore.getBoolean(ComparePreferencePage.SYNCHRONIZE_SCROLLING));
2772
		 */
2565
		
2773
		setSyncScrolling(fPreferenceStore
2774
				.getBoolean(ComparePreferencePage.SYNCHRONIZE_SCROLLING));
2775
2566
		update(false);
2776
		update(false);
2567
		
2777
2568
		if (!fHasErrors && !emptyInput && !fComposite.isDisposed()) {
2778
		if (!fHasErrors && !emptyInput && !fComposite.isDisposed()) {
2569
			if (isRefreshing()) {
2779
			if (isRefreshing()) {
2570
				fLeftContributor.updateSelection(fLeft, !fSynchronizedScrolling);
2780
				fLeftContributor
2571
				fRightContributor.updateSelection(fRight, !fSynchronizedScrolling);
2781
						.updateSelection(fLeft, !fSynchronizedScrolling);
2572
				fAncestorContributor.updateSelection(fAncestor, !fSynchronizedScrolling);
2782
				fRightContributor.updateSelection(fRight,
2783
						!fSynchronizedScrolling);
2784
				fAncestorContributor.updateSelection(fAncestor,
2785
						!fSynchronizedScrolling);
2573
				if (fSynchronizedScrolling && fSynchronziedScrollPosition != -1) {
2786
				if (fSynchronizedScrolling && fSynchronziedScrollPosition != -1) {
2574
					synchronizedScrollVertical(fSynchronziedScrollPosition);
2787
					synchronizedScrollVertical(fSynchronziedScrollPosition);
2575
				}
2788
				}
2576
			} else {
2789
			} else {
2577
				if (isPatchHunk()) {
2790
				if (isPatchHunk()) {
2578
					if (right != null && Utilities.getAdapter(right, IHunk.class) != null)
2791
					if (right != null
2792
							&& Utilities.getAdapter(right, IHunk.class) != null)
2579
						fLeft.setTopIndex(getHunkStart());
2793
						fLeft.setTopIndex(getHunkStart());
2580
					else
2794
					else
2581
						fRight.setTopIndex(getHunkStart());
2795
						fRight.setTopIndex(getHunkStart());
2582
				} else {
2796
				} else {
2583
					Diff selectDiff= null;
2797
					Diff selectDiff = null;
2584
					if (FIX_47640) {
2798
					if (FIX_47640) {
2585
						if (leftRange != null)
2799
						if (leftRange != null)
2586
						    selectDiff= fMerger.findDiff(LEFT_CONTRIBUTOR, leftRange);
2800
							selectDiff = fMerger.findDiff(LEFT_CONTRIBUTOR,
2801
									leftRange);
2587
						else if (rightRange != null)
2802
						else if (rightRange != null)
2588
						    selectDiff= fMerger.findDiff(RIGHT_CONTRIBUTOR, rightRange);
2803
							selectDiff = fMerger.findDiff(RIGHT_CONTRIBUTOR,
2804
									rightRange);
2589
					}
2805
					}
2590
					if (selectDiff != null)
2806
					if (selectDiff != null)
2591
						setCurrentDiff(selectDiff, true);
2807
						setCurrentDiff(selectDiff, true);
Lines 2594-2600 Link Here
2594
				}
2810
				}
2595
			}
2811
			}
2596
		}
2812
		}
2597
		
2813
2598
	}
2814
	}
2599
2815
2600
	private boolean isRefreshing() {
2816
	private boolean isRefreshing() {
Lines 2604-2654 Link Here
2604
	private ContributorInfo createLegInfoFor(Object element, char leg) {
2820
	private ContributorInfo createLegInfoFor(Object element, char leg) {
2605
		return new ContributorInfo(this, element, leg);
2821
		return new ContributorInfo(this, element, leg);
2606
	}
2822
	}
2607
	
2823
2608
	private void updateDiffBackground(Diff diff) {
2824
	private void updateDiffBackground(Diff diff) {
2609
		
2825
2610
		if (! fHighlightRanges)
2826
		if (!fHighlightRanges)
2611
			return;
2827
			return;
2612
		
2828
2613
		if (diff == null || diff.isToken())
2829
		if (diff == null || diff.isToken())
2614
			return;
2830
			return;
2615
			
2831
2616
		if (fShowCurrentOnly && !isCurrentDiff(diff))
2832
		if (fShowCurrentOnly && !isCurrentDiff(diff))
2617
			return;
2833
			return;
2618
						
2834
2619
		Color c= getColor(null, getFillColor(diff));
2835
		Color c = getColor(null, getFillColor(diff));
2620
		if (c == null)
2836
		if (c == null)
2621
			return;
2837
			return;
2622
			
2838
2623
		if (isThreeWay())
2839
		if (isThreeWay())
2624
			fAncestor.setLineBackground(diff.getPosition(ANCESTOR_CONTRIBUTOR), c);
2840
			fAncestor.setLineBackground(diff.getPosition(ANCESTOR_CONTRIBUTOR),
2841
					c);
2625
		fLeft.setLineBackground(diff.getPosition(LEFT_CONTRIBUTOR), c);
2842
		fLeft.setLineBackground(diff.getPosition(LEFT_CONTRIBUTOR), c);
2626
		fRight.setLineBackground(diff.getPosition(RIGHT_CONTRIBUTOR), c);
2843
		fRight.setLineBackground(diff.getPosition(RIGHT_CONTRIBUTOR), c);
2627
	}
2844
	}
2628
	
2845
2629
	private void updateAllDiffBackgrounds(Display display) {
2846
	private void updateAllDiffBackgrounds(Display display) {
2630
		if (fMerger.hasChanges()) {
2847
		if (fMerger.hasChanges()) {
2631
			boolean threeWay= isThreeWay();
2848
			boolean threeWay = isThreeWay();
2632
			for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) {
2849
			for (Iterator iterator = fMerger.changesIterator(); iterator
2850
					.hasNext();) {
2633
				Diff diff = (Diff) iterator.next();
2851
				Diff diff = (Diff) iterator.next();
2634
				Color c= getColor(display, getFillColor(diff));
2852
				Color c = getColor(display, getFillColor(diff));
2635
				if (threeWay)
2853
				if (threeWay)
2636
					fAncestor.setLineBackground(diff.getPosition(ANCESTOR_CONTRIBUTOR), c);
2854
					fAncestor.setLineBackground(diff
2855
							.getPosition(ANCESTOR_CONTRIBUTOR), c);
2637
				fLeft.setLineBackground(diff.getPosition(LEFT_CONTRIBUTOR), c);
2856
				fLeft.setLineBackground(diff.getPosition(LEFT_CONTRIBUTOR), c);
2638
				fRight.setLineBackground(diff.getPosition(RIGHT_CONTRIBUTOR), c);
2857
				fRight
2858
						.setLineBackground(diff.getPosition(RIGHT_CONTRIBUTOR),
2859
								c);
2639
			}
2860
			}
2640
		}
2861
		}
2641
	}
2862
	}
2642
	
2863
2643
	/*
2864
	/*
2644
	 * Called whenever one of the documents changes.
2865
	 * Called whenever one of the documents changes. Sets the dirty state of
2645
	 * Sets the dirty state of this viewer and updates the lines.
2866
	 * this viewer and updates the lines. Implements IDocumentListener.
2646
	 * Implements IDocumentListener.
2647
	 */
2867
	 */
2648
	private void documentChanged(DocumentEvent e, boolean dirty) {
2868
	private void documentChanged(DocumentEvent e, boolean dirty) {
2649
		
2869
2650
		IDocument doc= e.getDocument();
2870
		IDocument doc = e.getDocument();
2651
		
2871
2652
		if (doc == fLeft.getDocument()) {
2872
		if (doc == fLeft.getDocument()) {
2653
			setLeftDirty(dirty);
2873
			setLeftDirty(dirty);
2654
		} else if (doc == fRight.getDocument()) {
2874
		} else if (doc == fRight.getDocument()) {
Lines 2657-2720 Link Here
2657
2877
2658
		updateLines(doc);
2878
		updateLines(doc);
2659
	}
2879
	}
2660
		
2880
2661
	/*
2881
	/*
2662
	 * This method is called if a range of text on one side is copied into an empty sub-document
2882
	 * This method is called if a range of text on one side is copied into an
2663
	 * on the other side. The method returns the position where the sub-document is placed into the base document.
2883
	 * empty sub-document on the other side. The method returns the position
2664
	 * This default implementation determines the position by using the text range differencer.
2884
	 * where the sub-document is placed into the base document. This default
2665
	 * However this position is not always optimal for specific types of text.
2885
	 * implementation determines the position by using the text range
2666
	 * So subclasses (which are aware of the type of text they are dealing with)
2886
	 * differencer. However this position is not always optimal for specific
2667
	 * may override this method to find a better position where to insert a newly added
2887
	 * types of text. So subclasses (which are aware of the type of text they
2668
	 * piece of text.
2888
	 * are dealing with) may override this method to find a better position
2669
	 * @param type the side for which the insertion position should be determined: 'A' for ancestor, 'L' for left hand side, 'R' for right hand side.
2889
	 * where to insert a newly added piece of text.
2890
	 * 
2891
	 * @param type the side for which the insertion position should be
2892
	 * determined: 'A' for ancestor, 'L' for left hand side, 'R' for right hand
2893
	 * side.
2894
	 * 
2670
	 * @param input the current input object of this viewer
2895
	 * @param input the current input object of this viewer
2896
	 * 
2671
	 * @since 2.0
2897
	 * @since 2.0
2672
	 */
2898
	 */
2673
	protected int findInsertionPosition(char type, ICompareInput input) {
2899
	protected int findInsertionPosition(char type, ICompareInput input) {
2674
			
2900
2675
		ITypedElement other= null;
2901
		ITypedElement other = null;
2676
		char otherType= 0;
2902
		char otherType = 0;
2677
		
2903
2678
		switch (type) {
2904
		switch (type) {
2679
		case ANCESTOR_CONTRIBUTOR:
2905
		case ANCESTOR_CONTRIBUTOR:
2680
			other= input.getLeft();
2906
			other = input.getLeft();
2681
			otherType= LEFT_CONTRIBUTOR;
2907
			otherType = LEFT_CONTRIBUTOR;
2682
			if (other == null) {
2908
			if (other == null) {
2683
				other= input.getRight();
2909
				other = input.getRight();
2684
				otherType= RIGHT_CONTRIBUTOR;
2910
				otherType = RIGHT_CONTRIBUTOR;
2685
			}
2911
			}
2686
			break;
2912
			break;
2687
		case LEFT_CONTRIBUTOR:
2913
		case LEFT_CONTRIBUTOR:
2688
			other= input.getRight();
2914
			other = input.getRight();
2689
			otherType= RIGHT_CONTRIBUTOR;
2915
			otherType = RIGHT_CONTRIBUTOR;
2690
			if (other == null) {
2916
			if (other == null) {
2691
				other= input.getAncestor();
2917
				other = input.getAncestor();
2692
				otherType= ANCESTOR_CONTRIBUTOR;
2918
				otherType = ANCESTOR_CONTRIBUTOR;
2693
			}
2919
			}
2694
			break;
2920
			break;
2695
		case RIGHT_CONTRIBUTOR:
2921
		case RIGHT_CONTRIBUTOR:
2696
			other= input.getLeft();
2922
			other = input.getLeft();
2697
			otherType= LEFT_CONTRIBUTOR;
2923
			otherType = LEFT_CONTRIBUTOR;
2698
			if (other == null) {
2924
			if (other == null) {
2699
				other= input.getAncestor();
2925
				other = input.getAncestor();
2700
				otherType= ANCESTOR_CONTRIBUTOR;
2926
				otherType = ANCESTOR_CONTRIBUTOR;
2701
			}
2927
			}
2702
			break;
2928
			break;
2703
		}
2929
		}
2704
		
2930
2705
		if (other instanceof IDocumentRange) {
2931
		if (other instanceof IDocumentRange) {
2706
			IDocumentRange dr= (IDocumentRange) other;
2932
			IDocumentRange dr = (IDocumentRange) other;
2707
			Position p= dr.getRange();
2933
			Position p = dr.getRange();
2708
			Diff diff= findDiff(otherType, p.offset);
2934
			Diff diff = findDiff(otherType, p.offset);
2709
			return fMerger.findInsertionPoint(diff, type);
2935
			return fMerger.findInsertionPoint(diff, type);
2710
		}
2936
		}
2711
		return 0;
2937
		return 0;
2712
	}
2938
	}
2713
	
2939
2714
	private void setError(char type, String message) {
2940
	private void setError(char type, String message) {
2715
		IMergeViewerContentProvider cp= getMergeContentProvider();
2941
		IMergeViewerContentProvider cp = getMergeContentProvider();
2716
		if (cp instanceof MergeViewerContentProvider) {
2942
		if (cp instanceof MergeViewerContentProvider) {
2717
			MergeViewerContentProvider mcp= (MergeViewerContentProvider) cp;
2943
			MergeViewerContentProvider mcp = (MergeViewerContentProvider) cp;
2718
			switch (type) {
2944
			switch (type) {
2719
			case ANCESTOR_CONTRIBUTOR:
2945
			case ANCESTOR_CONTRIBUTOR:
2720
				mcp.setAncestorError(message);
2946
				mcp.setAncestorError(message);
Lines 2727-2733 Link Here
2727
				break;
2953
				break;
2728
			}
2954
			}
2729
		}
2955
		}
2730
		fHasErrors= true;
2956
		fHasErrors = true;
2731
	}
2957
	}
2732
2958
2733
	private void updateDirtyState(IEditorInput key,
2959
	private void updateDirtyState(IEditorInput key,
Lines 2750-2756 Link Here
2750
		}
2976
		}
2751
		return null;
2977
		return null;
2752
	}
2978
	}
2753
	
2979
2754
	private void addNewRange(char type, Object input, Position range) {
2980
	private void addNewRange(char type, Object input, Position range) {
2755
		switch (type) {
2981
		switch (type) {
2756
		case ANCESTOR_CONTRIBUTOR:
2982
		case ANCESTOR_CONTRIBUTOR:
Lines 2764-2789 Link Here
2764
			break;
2990
			break;
2765
		}
2991
		}
2766
	}
2992
	}
2767
	
2993
2768
	/**
2994
	/**
2769
	 * Returns the contents of the underlying document as an array of bytes using the current workbench encoding.
2995
	 * Returns the contents of the underlying document as an array of bytes
2996
	 * using the current workbench encoding.
2770
	 * 
2997
	 * 
2771
	 * @param left if <code>true</code> the contents of the left side is returned; otherwise the right side
2998
	 * @param left
2999
	 *            if <code>true</code> the contents of the left side is
3000
	 *            returned; otherwise the right side
2772
	 * @return the contents of the left or right document or null
3001
	 * @return the contents of the left or right document or null
2773
	 */
3002
	 */
2774
	protected byte[] getContents(boolean left) {
3003
	protected byte[] getContents(boolean left) {
2775
		MergeSourceViewer v= left ? fLeft : fRight;
3004
		MergeSourceViewer v = left ? fLeft : fRight;
2776
		if (v != null) {
3005
		if (v != null) {
2777
			IDocument d= v.getDocument();
3006
			IDocument d = v.getDocument();
2778
			if (d != null) {
3007
			if (d != null) {
2779
				String contents= d.get();
3008
				String contents = d.get();
2780
				if (contents != null) {
3009
				if (contents != null) {
2781
					byte[] bytes;
3010
					byte[] bytes;
2782
					try {
3011
					try {
2783
						bytes= contents.getBytes(left ? fLeftContributor.getEncoding() : fRightContributor.getEncoding());
3012
						bytes = contents.getBytes(left ? fLeftContributor
2784
					} catch(UnsupportedEncodingException ex) {
3013
								.getEncoding() : fRightContributor
3014
								.getEncoding());
3015
					} catch (UnsupportedEncodingException ex) {
2785
						// use default encoding
3016
						// use default encoding
2786
						bytes= contents.getBytes();
3017
						bytes = contents.getBytes();
2787
					}
3018
					}
2788
					return bytes;
3019
					return bytes;
2789
				}
3020
				}
Lines 2791-2936 Link Here
2791
		}
3022
		}
2792
		return null;
3023
		return null;
2793
	}
3024
	}
2794
		
3025
2795
	private IRegion normalizeDocumentRegion(IDocument doc, IRegion region) {
3026
	private IRegion normalizeDocumentRegion(IDocument doc, IRegion region) {
2796
		
3027
2797
		if (region == null || doc == null)
3028
		if (region == null || doc == null)
2798
			return region;
3029
			return region;
2799
			
3030
2800
		int maxLength= doc.getLength();
3031
		int maxLength = doc.getLength();
2801
		
3032
2802
		int start= region.getOffset();
3033
		int start = region.getOffset();
2803
		if (start < 0)
3034
		if (start < 0)
2804
			start= 0;
3035
			start = 0;
2805
		else if (start > maxLength)
3036
		else if (start > maxLength)
2806
			start= maxLength;
3037
			start = maxLength;
2807
			
3038
2808
		int length= region.getLength();
3039
		int length = region.getLength();
2809
		if (length < 0)
3040
		if (length < 0)
2810
			length= 0;
3041
			length = 0;
2811
		else if (start + length > maxLength)
3042
		else if (start + length > maxLength)
2812
			length= maxLength - start;
3043
			length = maxLength - start;
2813
			
3044
2814
		return new Region(start, length);
3045
		return new Region(start, length);
2815
	}
3046
	}
2816
		
3047
2817
	/* (non-Javadoc)
3048
	/*
2818
	 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#handleResizeAncestor(int, int, int, int)
3049
	 * (non-Javadoc)
3050
	 * 
3051
	 * @seeorg.eclipse.compare.contentmergeviewer.ContentMergeViewer#
3052
	 * handleResizeAncestor(int, int, int, int)
2819
	 */
3053
	 */
2820
	protected final void handleResizeAncestor(int x, int y, int width, int height) {
3054
	protected final void handleResizeAncestor(int x, int y, int width,
3055
			int height) {
2821
		if (width > 0) {
3056
		if (width > 0) {
2822
			Rectangle trim= fLeft.getTextWidget().computeTrim(0, 0, 0, 0);
3057
			Rectangle trim = fLeft.getTextWidget().computeTrim(0, 0, 0, 0);
2823
			int scrollbarHeight= trim.height;
3058
			int scrollbarHeight = trim.height;
2824
			if (Utilities.okToUse(fAncestorCanvas))
3059
			if (Utilities.okToUse(fAncestorCanvas))
2825
				fAncestorCanvas.setVisible(true);
3060
				fAncestorCanvas.setVisible(true);
2826
			if (fAncestor.isControlOkToUse())
3061
			if (fAncestor.isControlOkToUse())
2827
				fAncestor.getTextWidget().setVisible(true);
3062
				fAncestor.getTextWidget().setVisible(true);
2828
			
3063
2829
			if (fAncestorCanvas != null) {
3064
			if (fAncestorCanvas != null) {
2830
				fAncestorCanvas.setBounds(x, y, fMarginWidth, height-scrollbarHeight);
3065
				fAncestorCanvas.setBounds(x, y, fMarginWidth, height
2831
				x+= fMarginWidth;
3066
						- scrollbarHeight);
2832
				width-= fMarginWidth;
3067
				x += fMarginWidth;
3068
				width -= fMarginWidth;
2833
			}
3069
			}
2834
			fAncestor.setBounds(x, y, width, height);
3070
			fAncestor.setBounds(x, y, width, height);
2835
		} else {
3071
		} else {
2836
			if (Utilities.okToUse(fAncestorCanvas))
3072
			if (Utilities.okToUse(fAncestorCanvas))
2837
				fAncestorCanvas.setVisible(false);
3073
				fAncestorCanvas.setVisible(false);
2838
			if (fAncestor.isControlOkToUse()) {
3074
			if (fAncestor.isControlOkToUse()) {
2839
				StyledText t= fAncestor.getTextWidget();
3075
				StyledText t = fAncestor.getTextWidget();
2840
				t.setVisible(false);
3076
				t.setVisible(false);
2841
				fAncestor.setBounds(0, 0, 0, 0);
3077
				fAncestor.setBounds(0, 0, 0, 0);
2842
				if (fFocusPart == fAncestor) {
3078
				if (fFocusPart == fAncestor) {
2843
					fFocusPart= fLeft;
3079
					fFocusPart = fLeft;
2844
					fFocusPart.getTextWidget().setFocus();
3080
					fFocusPart.getTextWidget().setFocus();
2845
				}
3081
				}
2846
			}
3082
			}
2847
		}
3083
		}
2848
	}
3084
	}
2849
3085
2850
  	/* (non-Javadoc)
3086
	/*
2851
  	 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#handleResizeLeftRight(int, int, int, int, int, int)
3087
	 * (non-Javadoc)
2852
  	 */
3088
	 * 
2853
  	protected final void handleResizeLeftRight(int x, int y, int width1, int centerWidth, int width2,  int height) {
3089
	 * @seeorg.eclipse.compare.contentmergeviewer.ContentMergeViewer#
2854
  				
3090
	 * handleResizeLeftRight(int, int, int, int, int, int)
2855
  		if (fBirdsEyeCanvas != null)
3091
	 */
2856
  			width2-= BIRDS_EYE_VIEW_WIDTH;
3092
	protected final void handleResizeLeftRight(int x, int y, int width1,
2857
  			
3093
			int centerWidth, int width2, int height) {
2858
		Rectangle trim= fLeft.getTextWidget().computeTrim(0, 0, 0, 0);
3094
2859
		int scrollbarHeight= trim.height + trim.x;
3095
		if (fBirdsEyeCanvas != null)
3096
			width2 -= BIRDS_EYE_VIEW_WIDTH;
3097
3098
		Rectangle trim = fLeft.getTextWidget().computeTrim(0, 0, 0, 0);
3099
		int scrollbarHeight = trim.height + trim.x;
2860
3100
2861
		Composite composite= (Composite) getControl();
3101
		Composite composite = (Composite) getControl();
2862
3102
2863
		int leftTextWidth= width1;
3103
		int leftTextWidth = width1;
2864
		if (fLeftCanvas != null) {
3104
		if (fLeftCanvas != null) {
2865
			fLeftCanvas.setBounds(x, y, fMarginWidth, height-scrollbarHeight);
3105
			fLeftCanvas.setBounds(x, y, fMarginWidth, height - scrollbarHeight);
2866
			x+= fMarginWidth;
3106
			x += fMarginWidth;
2867
			leftTextWidth-= fMarginWidth;
3107
			leftTextWidth -= fMarginWidth;
2868
		}
3108
		}
2869
		
3109
2870
		fLeft.setBounds(x, y, leftTextWidth, height);
3110
		fLeft.setBounds(x, y, leftTextWidth, height);
2871
		x+= leftTextWidth;
3111
		x += leftTextWidth;
2872
		
3112
2873
		if (fCenter == null || fCenter.isDisposed())
3113
		if (fCenter == null || fCenter.isDisposed())
2874
			fCenter= createCenterControl(composite);
3114
			fCenter = createCenterControl(composite);
2875
		fCenter.setBounds(x, y, centerWidth, height-scrollbarHeight);
3115
		fCenter.setBounds(x, y, centerWidth, height - scrollbarHeight);
2876
		x+= centerWidth;
3116
		x += centerWidth;
2877
		
3117
2878
		if (!fSynchronizedScrolling) {	// canvas is to the left of text
3118
		if (!fSynchronizedScrolling) { // canvas is to the left of text
2879
			if (fRightCanvas != null) {
3119
			if (fRightCanvas != null) {
2880
				fRightCanvas.setBounds(x, y, fMarginWidth, height-scrollbarHeight);
3120
				fRightCanvas.setBounds(x, y, fMarginWidth, height
3121
						- scrollbarHeight);
2881
				fRightCanvas.redraw();
3122
				fRightCanvas.redraw();
2882
				x+= fMarginWidth;
3123
				x += fMarginWidth;
2883
			}
3124
			}
2884
			// we draw the canvas to the left of the text widget
3125
			// we draw the canvas to the left of the text widget
2885
		}
3126
		}
2886
		
3127
2887
		int scrollbarWidth= 0;
3128
		int scrollbarWidth = 0;
2888
		if (fSynchronizedScrolling && fScrollCanvas != null) {
3129
		if (fSynchronizedScrolling && fScrollCanvas != null) {
2889
			trim= fLeft.getTextWidget().computeTrim(0, 0, 0, 0);
3130
			trim = fLeft.getTextWidget().computeTrim(0, 0, 0, 0);
2890
	  		// one pixel was cut off
3131
			// one pixel was cut off
2891
			scrollbarWidth= trim.width + 2*trim.x+1;
3132
			scrollbarWidth = trim.width + 2 * trim.x + 1;
2892
		}
3133
		}
2893
		int rightTextWidth= width2-scrollbarWidth;
3134
		int rightTextWidth = width2 - scrollbarWidth;
2894
		if (fRightCanvas != null)
3135
		if (fRightCanvas != null)
2895
			rightTextWidth-= fMarginWidth;
3136
			rightTextWidth -= fMarginWidth;
2896
		fRight.setBounds(x, y, rightTextWidth, height);
3137
		fRight.setBounds(x, y, rightTextWidth, height);
2897
		x+= rightTextWidth;
3138
		x += rightTextWidth;
2898
			
3139
2899
		if (fSynchronizedScrolling) {
3140
		if (fSynchronizedScrolling) {
2900
			if (fRightCanvas != null) {	// canvas is to the right of the text
3141
			if (fRightCanvas != null) { // canvas is to the right of the text
2901
				fRightCanvas.setBounds(x, y, fMarginWidth, height-scrollbarHeight);
3142
				fRightCanvas.setBounds(x, y, fMarginWidth, height
2902
				x+= fMarginWidth;
3143
						- scrollbarHeight);
3144
				x += fMarginWidth;
2903
			}
3145
			}
2904
			if (fScrollCanvas != null)
3146
			if (fScrollCanvas != null)
2905
				fScrollCanvas.setBounds(x, y, scrollbarWidth, height-scrollbarHeight);
3147
				fScrollCanvas.setBounds(x, y, scrollbarWidth, height
3148
						- scrollbarHeight);
2906
		}
3149
		}
2907
		
3150
2908
  		if (fBirdsEyeCanvas != null) {
3151
		if (fBirdsEyeCanvas != null) {
2909
  			int verticalScrollbarButtonHeight= scrollbarWidth;
3152
			int verticalScrollbarButtonHeight = scrollbarWidth;
2910
			int horizontalScrollbarButtonHeight= scrollbarHeight;
3153
			int horizontalScrollbarButtonHeight = scrollbarHeight;
2911
			if (fIsCarbon) {
3154
			if (fIsCarbon) {
2912
				verticalScrollbarButtonHeight+= 2;
3155
				verticalScrollbarButtonHeight += 2;
2913
				horizontalScrollbarButtonHeight= 18;
3156
				horizontalScrollbarButtonHeight = 18;
2914
			}
3157
			}
2915
  			if (fSummaryHeader != null)
3158
			if (fSummaryHeader != null)
2916
				fSummaryHeader.setBounds(x+scrollbarWidth, y, BIRDS_EYE_VIEW_WIDTH, verticalScrollbarButtonHeight);
3159
				fSummaryHeader.setBounds(x + scrollbarWidth, y,
2917
  			y+= verticalScrollbarButtonHeight;
3160
						BIRDS_EYE_VIEW_WIDTH, verticalScrollbarButtonHeight);
2918
  			fBirdsEyeCanvas.setBounds(x+scrollbarWidth, y, BIRDS_EYE_VIEW_WIDTH, height-(2*verticalScrollbarButtonHeight+horizontalScrollbarButtonHeight));
3161
			y += verticalScrollbarButtonHeight;
2919
   		}
3162
			fBirdsEyeCanvas
2920
		
3163
					.setBounds(
3164
							x + scrollbarWidth,
3165
							y,
3166
							BIRDS_EYE_VIEW_WIDTH,
3167
							height
3168
									- (2 * verticalScrollbarButtonHeight + horizontalScrollbarButtonHeight));
3169
		}
3170
2921
		// doesn't work since TextEditors don't have their correct size yet.
3171
		// doesn't work since TextEditors don't have their correct size yet.
2922
		updateVScrollBar();
3172
		updateVScrollBar();
2923
		refreshBirdsEyeView();
3173
		refreshBirdsEyeView();
2924
	}
3174
	}
2925
							
3175
2926
	/*
3176
	/*
2927
	 * Track selection changes to update the current Diff.
3177
	 * Track selection changes to update the current Diff.
2928
	 */
3178
	 */
2929
	private void handleSelectionChanged(MergeSourceViewer tw) {
3179
	private void handleSelectionChanged(MergeSourceViewer tw) {
2930
		Point p= tw.getSelectedRange();
3180
		Point p = tw.getSelectedRange();
2931
		Diff d= findDiff(tw, p.x, p.x+p.y);
3181
		Diff d = findDiff(tw, p.x, p.x + p.y);
2932
		updateStatus(d);
3182
		updateStatus(d);
2933
		setCurrentDiff(d, false);	// don't select or reveal
3183
		setCurrentDiff(d, false); // don't select or reveal
2934
	}
3184
	}
2935
3185
2936
	private static IRegion toRegion(Position position) {
3186
	private static IRegion toRegion(Position position) {
Lines 2938-2992 Link Here
2938
			return new Region(position.getOffset(), position.getLength());
3188
			return new Region(position.getOffset(), position.getLength());
2939
		return null;
3189
		return null;
2940
	}
3190
	}
2941
	
3191
2942
	//---- the differencing
3192
	// ---- the differencing
2943
	
3193
2944
	/**
3194
	/**
2945
	 * Perform a two level 2- or 3-way diff.
3195
	 * Perform a two level 2- or 3-way diff. The first level is based on line
2946
	 * The first level is based on line comparison, the second level on token comparison.
3196
	 * comparison, the second level on token comparison.
2947
	 */
3197
	 */
2948
	private void doDiff() {
3198
	private void doDiff() {
2949
		IDocument lDoc= fLeft.getDocument();
3199
		IDocument lDoc = fLeft.getDocument();
2950
		IDocument rDoc= fRight.getDocument();
3200
		IDocument rDoc = fRight.getDocument();
2951
		if (lDoc == null || rDoc == null)
3201
		if (lDoc == null || rDoc == null)
2952
			return;
3202
			return;
2953
		fAncestor.resetLineBackground();
3203
		fAncestor.resetLineBackground();
2954
		fLeft.resetLineBackground();
3204
		fLeft.resetLineBackground();
2955
		fRight.resetLineBackground();
3205
		fRight.resetLineBackground();
2956
		
3206
2957
		fCurrentDiff= null;
3207
		fCurrentDiff = null;
2958
		try {
3208
		try {
2959
			fMerger.doDiff();
3209
			fMerger.doDiff();
2960
		} catch (CoreException e) {
3210
		} catch (CoreException e) {
2961
			CompareUIPlugin.log(e.getStatus());
3211
			CompareUIPlugin.log(e.getStatus());
2962
			String title= Utilities.getString(getResourceBundle(), "tooComplexError.title"); //$NON-NLS-1$
3212
			String title = Utilities.getString(getResourceBundle(),
2963
			String format= Utilities.getString(getResourceBundle(), "tooComplexError.format"); //$NON-NLS-1$
3213
					"tooComplexError.title"); //$NON-NLS-1$
2964
			String msg= MessageFormat.format(format, new Object[] { Integer.toString(PlatformUI.getWorkbench().getProgressService().getLongOperationTime()/1000) } );
3214
			String format = Utilities.getString(getResourceBundle(),
3215
					"tooComplexError.format"); //$NON-NLS-1$
3216
			String msg = MessageFormat.format(format, new Object[] { Integer
3217
					.toString(PlatformUI.getWorkbench().getProgressService()
3218
							.getLongOperationTime() / 1000) });
2965
			MessageDialog.openError(fComposite.getShell(), title, msg);
3219
			MessageDialog.openError(fComposite.getShell(), title, msg);
2966
		}
3220
		}
2967
		
3221
2968
		if (fMerger.hasChanges()) {
3222
		if (fMerger.hasChanges()) {
2969
			for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) {
3223
			for (Iterator iterator = fMerger.changesIterator(); iterator
3224
					.hasNext();) {
2970
				Diff diff = (Diff) iterator.next();
3225
				Diff diff = (Diff) iterator.next();
2971
				updateDiffBackground(diff);
3226
				updateDiffBackground(diff);
2972
			}
3227
			}
2973
		}
3228
		}
2974
		invalidateTextPresentation();
3229
		invalidateTextPresentation();
2975
	}
3230
	}
2976
	
3231
2977
	private Diff findDiff(char type, int pos) {
3232
	private Diff findDiff(char type, int pos) {
2978
		try {
3233
		try {
2979
			return fMerger.findDiff(type, pos);
3234
			return fMerger.findDiff(type, pos);
2980
		} catch (CoreException e) {
3235
		} catch (CoreException e) {
2981
			CompareUIPlugin.log(e.getStatus());
3236
			CompareUIPlugin.log(e.getStatus());
2982
			String title= Utilities.getString(getResourceBundle(), "tooComplexError.title"); //$NON-NLS-1$
3237
			String title = Utilities.getString(getResourceBundle(),
2983
			String format= Utilities.getString(getResourceBundle(), "tooComplexError.format"); //$NON-NLS-1$
3238
					"tooComplexError.title"); //$NON-NLS-1$
2984
			String msg= MessageFormat.format(format, new Object[] { Integer.toString(PlatformUI.getWorkbench().getProgressService().getLongOperationTime()/1000) } );
3239
			String format = Utilities.getString(getResourceBundle(),
3240
					"tooComplexError.format"); //$NON-NLS-1$
3241
			String msg = MessageFormat.format(format, new Object[] { Integer
3242
					.toString(PlatformUI.getWorkbench().getProgressService()
3243
							.getLongOperationTime() / 1000) });
2985
			MessageDialog.openError(fComposite.getShell(), title, msg);
3244
			MessageDialog.openError(fComposite.getShell(), title, msg);
2986
			return null;
3245
			return null;
2987
		}
3246
		}
2988
	}
3247
	}
2989
	
3248
2990
	private void resetPositions(IDocument doc) {
3249
	private void resetPositions(IDocument doc) {
2991
		if (doc == null)
3250
		if (doc == null)
2992
			return;
3251
			return;
Lines 2997-3160 Link Here
2997
		}
3256
		}
2998
		doc.addPositionCategory(DIFF_RANGE_CATEGORY);
3257
		doc.addPositionCategory(DIFF_RANGE_CATEGORY);
2999
	}
3258
	}
3000
	
3259
3001
	//---- update UI stuff
3260
	// ---- update UI stuff
3002
	
3261
3003
	private void updateControls() {
3262
	private void updateControls() {
3004
		
3263
3005
		boolean leftToRight= false;
3264
		boolean leftToRight = false;
3006
		boolean rightToLeft= false;
3265
		boolean rightToLeft = false;
3007
		
3266
3008
		updateStatus(fCurrentDiff);
3267
		updateStatus(fCurrentDiff);
3009
		updateResolveStatus();
3268
		updateResolveStatus();
3010
3269
3011
		if (fCurrentDiff != null) {
3270
		if (fCurrentDiff != null) {
3012
			IMergeViewerContentProvider cp= getMergeContentProvider();
3271
			IMergeViewerContentProvider cp = getMergeContentProvider();
3013
			if (cp != null) {
3272
			if (cp != null) {
3014
				if (!isPatchHunk()) {
3273
				if (!isPatchHunk()) {
3015
					rightToLeft= cp.isLeftEditable(getInput());
3274
					rightToLeft = cp.isLeftEditable(getInput());
3016
					leftToRight= cp.isRightEditable(getInput());
3275
					leftToRight = cp.isRightEditable(getInput());
3017
				}
3276
				}
3018
			}
3277
			}
3019
		}
3278
		}
3020
		
3279
3021
		if (fDirectionLabel != null) {
3280
		if (fDirectionLabel != null) {
3022
			if (fHighlightRanges && fCurrentDiff != null && isThreeWay() && !isIgnoreAncestor()) {
3281
			if (fHighlightRanges && fCurrentDiff != null && isThreeWay()
3282
					&& !isIgnoreAncestor()) {
3023
				fDirectionLabel.setImage(fCurrentDiff.getImage());
3283
				fDirectionLabel.setImage(fCurrentDiff.getImage());
3024
			} else {
3284
			} else {
3025
				fDirectionLabel.setImage(null);
3285
				fDirectionLabel.setImage(null);
3026
			}
3286
			}
3027
		}
3287
		}
3028
		
3288
3029
		if (fCopyDiffLeftToRightItem != null)
3289
		if (fCopyDiffLeftToRightItem != null)
3030
			((Action)fCopyDiffLeftToRightItem.getAction()).setEnabled(leftToRight);
3290
			((Action) fCopyDiffLeftToRightItem.getAction())
3291
					.setEnabled(leftToRight);
3031
		if (fCopyDiffRightToLeftItem != null)
3292
		if (fCopyDiffRightToLeftItem != null)
3032
			((Action)fCopyDiffRightToLeftItem.getAction()).setEnabled(rightToLeft);
3293
			((Action) fCopyDiffRightToLeftItem.getAction())
3033
			
3294
					.setEnabled(rightToLeft);
3034
		boolean enableNavigation= isNavigationPossible();
3295
3296
		boolean enableNavigation = isNavigationPossible();
3035
3297
3036
		if (fNextDiff != null) {
3298
		if (fNextDiff != null) {
3037
			IAction a= fNextDiff.getAction();
3299
			IAction a = fNextDiff.getAction();
3038
			a.setEnabled(enableNavigation || hasNextElement(true));
3300
			a.setEnabled(enableNavigation || hasNextElement(true));
3039
		}
3301
		}
3040
		if (fPreviousDiff != null) {
3302
		if (fPreviousDiff != null) {
3041
			IAction a= fPreviousDiff.getAction();
3303
			IAction a = fPreviousDiff.getAction();
3042
			a.setEnabled(enableNavigation || hasNextElement(false));
3304
			a.setEnabled(enableNavigation || hasNextElement(false));
3043
		}
3305
		}
3044
		if (fNextChange != null) {
3306
		if (fNextChange != null) {
3045
			IAction a= fNextChange.getAction();
3307
			IAction a = fNextChange.getAction();
3046
			a.setEnabled(enableNavigation);
3308
			a.setEnabled(enableNavigation);
3047
		}
3309
		}
3048
		if (fPreviousChange != null) {
3310
		if (fPreviousChange != null) {
3049
			IAction a= fPreviousChange.getAction();
3311
			IAction a = fPreviousChange.getAction();
3050
			a.setEnabled(enableNavigation);
3312
			a.setEnabled(enableNavigation);
3051
		}
3313
		}
3052
	}
3314
	}
3053
	
3315
3054
	private void updateResolveStatus() {
3316
	private void updateResolveStatus() {
3055
			
3317
3056
		RGB rgb= null;
3318
		RGB rgb = null;
3057
		
3319
3058
		if (showResolveUI()) {
3320
		if (showResolveUI()) {
3059
			// we only show red or green if there is at least one incoming or conflicting change
3321
			// we only show red or green if there is at least one incoming or
3060
			int incomingOrConflicting= 0;
3322
			// conflicting change
3061
			int unresolvedIncoming= 0;
3323
			int incomingOrConflicting = 0;
3062
			int unresolvedConflicting= 0;
3324
			int unresolvedIncoming = 0;
3325
			int unresolvedConflicting = 0;
3063
3326
3064
			if (fMerger.hasChanges()) {
3327
			if (fMerger.hasChanges()) {
3065
				for (Iterator iterator = fMerger.changesIterator(); iterator
3328
				for (Iterator iterator = fMerger.changesIterator(); iterator
3066
						.hasNext();) {
3329
						.hasNext();) {
3067
					Diff d = (Diff) iterator.next();
3330
					Diff d = (Diff) iterator.next();
3068
					if (d.isIncomingOrConflicting() /* && useChange(d.fDirection) && !d.fIsWhitespace */) {
3331
					if (d.isIncomingOrConflicting() /*
3332
													 * &&
3333
													 * useChange(d.fDirection)
3334
													 * && !d.fIsWhitespace
3335
													 */) {
3069
						incomingOrConflicting++;
3336
						incomingOrConflicting++;
3070
						if (!d.isResolved()) {
3337
						if (!d.isResolved()) {
3071
							if (d.getKind() == RangeDifference.CONFLICT) {
3338
							if (d.getKind() == RangeDifference.CONFLICT) {
3072
								unresolvedConflicting++;
3339
								unresolvedConflicting++;
3073
								break; // we can stop here because a conflict has the maximum priority
3340
								break; // we can stop here because a conflict
3341
										// has the maximum priority
3074
							}
3342
							}
3075
							unresolvedIncoming++;
3343
							unresolvedIncoming++;
3076
						}
3344
						}
3077
					}
3345
					}
3078
				}
3346
				}
3079
			}
3347
			}
3080
		
3348
3081
			if (incomingOrConflicting > 0) {
3349
			if (incomingOrConflicting > 0) {
3082
				if (unresolvedConflicting > 0)
3350
				if (unresolvedConflicting > 0)
3083
					rgb= SELECTED_CONFLICT;
3351
					rgb = SELECTED_CONFLICT;
3084
				else if (unresolvedIncoming > 0)
3352
				else if (unresolvedIncoming > 0)
3085
					rgb= SELECTED_INCOMING;
3353
					rgb = SELECTED_INCOMING;
3086
				else
3354
				else
3087
					rgb= RESOLVED;
3355
					rgb = RESOLVED;
3088
			}
3356
			}
3089
		}
3357
		}
3090
		
3358
3091
		if (fHeaderPainter.setColor(rgb))
3359
		if (fHeaderPainter.setColor(rgb))
3092
			fSummaryHeader.redraw();
3360
			fSummaryHeader.redraw();
3093
	}
3361
	}
3094
3362
3095
	private void updateStatus(Diff diff) {
3363
	private void updateStatus(Diff diff) {
3096
		
3364
3097
		if (! fShowMoreInfo)
3365
		if (!fShowMoreInfo)
3098
			return;
3366
			return;
3099
					
3367
3100
		String diffDescription;
3368
		String diffDescription;
3101
		
3369
3102
		if (diff == null) {
3370
		if (diff == null) {
3103
			diffDescription= CompareMessages.TextMergeViewer_diffDescription_noDiff_format;
3371
			diffDescription = CompareMessages.TextMergeViewer_diffDescription_noDiff_format;
3104
		} else {
3372
		} else {
3105
			
3373
3106
			if (diff.isToken())		// we don't show special info for token diffs
3374
			if (diff.isToken()) // we don't show special info for token diffs
3107
				diff= diff.getParent();
3375
				diff = diff.getParent();
3108
		
3376
3109
			String format= CompareMessages.TextMergeViewer_diffDescription_diff_format;
3377
			String format = CompareMessages.TextMergeViewer_diffDescription_diff_format;
3110
			diffDescription= MessageFormat.format(format,
3378
			diffDescription = MessageFormat.format(format, new String[] {
3111
				new String[] {
3379
					getDiffType(diff), // 0: diff type
3112
					getDiffType(diff),						// 0: diff type
3380
					getDiffNumber(diff), // 1: diff number
3113
					getDiffNumber(diff),					// 1: diff number
3381
					getDiffRange(fLeft, diff.getPosition(LEFT_CONTRIBUTOR)), // 2:
3114
					getDiffRange(fLeft, diff.getPosition(LEFT_CONTRIBUTOR)),		// 2: left start line
3382
																				// left
3115
					getDiffRange(fRight, diff.getPosition(RIGHT_CONTRIBUTOR))	// 3: left end line
3383
																				// start
3116
				}
3384
																				// line
3117
			);
3385
					getDiffRange(fRight, diff.getPosition(RIGHT_CONTRIBUTOR)) // 3:
3118
		}
3386
																				// left
3119
		
3387
																				// end
3120
		String format= CompareMessages.TextMergeViewer_statusLine_format;
3388
																				// line
3121
		String s= MessageFormat.format(format,
3389
					});
3122
			new String[] {
3390
		}
3123
				getCursorPosition(fLeft),	// 0: left column
3391
3124
				getCursorPosition(fRight),	// 1: right column
3392
		String format = CompareMessages.TextMergeViewer_statusLine_format;
3125
				diffDescription				// 2: diff description
3393
		String s = MessageFormat.format(format, new String[] {
3126
			}
3394
				getCursorPosition(fLeft), // 0: left column
3127
		);
3395
				getCursorPosition(fRight), // 1: right column
3128
	
3396
				diffDescription // 2: diff description
3397
				});
3398
3129
		getCompareConfiguration().getContainer().setStatusMessage(s);
3399
		getCompareConfiguration().getContainer().setStatusMessage(s);
3130
	}
3400
	}
3131
3401
3132
	private void clearStatus() {
3402
	private void clearStatus() {
3133
		getCompareConfiguration().getContainer().setStatusMessage(null);
3403
		getCompareConfiguration().getContainer().setStatusMessage(null);
3134
	}
3404
	}
3135
	
3405
3136
	private String getDiffType(Diff diff) {
3406
	private String getDiffType(Diff diff) {
3137
		String s= ""; 	//$NON-NLS-1$
3407
		String s = ""; //$NON-NLS-1$
3138
		switch(diff.getKind()) {
3408
		switch (diff.getKind()) {
3139
		case RangeDifference.LEFT:
3409
		case RangeDifference.LEFT:
3140
			s= CompareMessages.TextMergeViewer_direction_outgoing;
3410
			s = CompareMessages.TextMergeViewer_direction_outgoing;
3141
			break;
3411
			break;
3142
		case RangeDifference.RIGHT:
3412
		case RangeDifference.RIGHT:
3143
			s= CompareMessages.TextMergeViewer_direction_incoming;
3413
			s = CompareMessages.TextMergeViewer_direction_incoming;
3144
			break;
3414
			break;
3145
		case RangeDifference.CONFLICT:
3415
		case RangeDifference.CONFLICT:
3146
			s= CompareMessages.TextMergeViewer_direction_conflicting;
3416
			s = CompareMessages.TextMergeViewer_direction_conflicting;
3147
			break;
3417
			break;
3148
		}
3418
		}
3149
		String format= CompareMessages.TextMergeViewer_diffType_format;
3419
		String format = CompareMessages.TextMergeViewer_diffType_format;
3150
		return MessageFormat.format(format, new String[] { s, diff.changeType() } );
3420
		return MessageFormat.format(format,
3421
				new String[] { s, diff.changeType() });
3151
	}
3422
	}
3152
	
3423
3153
	private String getDiffNumber(Diff diff) {
3424
	private String getDiffNumber(Diff diff) {
3154
		// find the diff's number
3425
		// find the diff's number
3155
		int diffNumber= 0;
3426
		int diffNumber = 0;
3156
		if (fMerger.hasChanges()) {
3427
		if (fMerger.hasChanges()) {
3157
			for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) {
3428
			for (Iterator iterator = fMerger.changesIterator(); iterator
3429
					.hasNext();) {
3158
				Diff d = (Diff) iterator.next();
3430
				Diff d = (Diff) iterator.next();
3159
				diffNumber++;
3431
				diffNumber++;
3160
				if (d == diff)
3432
				if (d == diff)
Lines 3163-3184 Link Here
3163
		}
3435
		}
3164
		return Integer.toString(diffNumber);
3436
		return Integer.toString(diffNumber);
3165
	}
3437
	}
3166
	
3438
3167
	private String getDiffRange(MergeSourceViewer v, Position pos) {
3439
	private String getDiffRange(MergeSourceViewer v, Position pos) {
3168
		Point p= v.getLineRange(pos, new Point(0, 0));
3440
		Point p = v.getLineRange(pos, new Point(0, 0));
3169
		int startLine= p.x+1;
3441
		int startLine = p.x + 1;
3170
		int endLine= p.x+p.y;
3442
		int endLine = p.x + p.y;
3171
		
3443
3172
		String format;
3444
		String format;
3173
		if (endLine < startLine)
3445
		if (endLine < startLine)
3174
			format= CompareMessages.TextMergeViewer_beforeLine_format;
3446
			format = CompareMessages.TextMergeViewer_beforeLine_format;
3175
		else
3447
		else
3176
			format= CompareMessages.TextMergeViewer_range_format;
3448
			format = CompareMessages.TextMergeViewer_range_format;
3177
		return MessageFormat.format(format,
3449
		return MessageFormat.format(format, new String[] {
3178
					new String[] { Integer.toString(startLine),
3450
				Integer.toString(startLine), Integer.toString(endLine) });
3179
									Integer.toString(endLine) } );
3180
	}
3451
	}
3181
	
3452
3182
	/*
3453
	/*
3183
	 * Returns a description of the cursor position.
3454
	 * Returns a description of the cursor position.
3184
	 * 
3455
	 * 
Lines 3186-3260 Link Here
3186
	 */
3457
	 */
3187
	private String getCursorPosition(MergeSourceViewer v) {
3458
	private String getCursorPosition(MergeSourceViewer v) {
3188
		if (v != null) {
3459
		if (v != null) {
3189
			StyledText styledText= v.getTextWidget();
3460
			StyledText styledText = v.getTextWidget();
3190
			
3461
3191
			IDocument document= v.getDocument();
3462
			IDocument document = v.getDocument();
3192
			if (document != null) {
3463
			if (document != null) {
3193
				int offset= v.getVisibleRegion().getOffset();
3464
				int offset = v.getVisibleRegion().getOffset();
3194
				int caret= offset + styledText.getCaretOffset();
3465
				int caret = offset + styledText.getCaretOffset();
3195
				
3466
3196
				try {
3467
				try {
3197
					
3468
3198
					int line=document.getLineOfOffset(caret);
3469
					int line = document.getLineOfOffset(caret);
3199
					
3470
3200
					int lineOffset= document.getLineOffset(line);
3471
					int lineOffset = document.getLineOffset(line);
3201
					int occurrences= 0;
3472
					int occurrences = 0;
3202
					for (int i= lineOffset; i < caret; i++)
3473
					for (int i = lineOffset; i < caret; i++)
3203
						if ('\t' == document.getChar(i))
3474
						if ('\t' == document.getChar(i))
3204
							++ occurrences;
3475
							++occurrences;
3205
							
3476
3206
					int tabWidth= styledText.getTabs();
3477
					int tabWidth = styledText.getTabs();
3207
					int column= caret - lineOffset + (tabWidth -1) * occurrences;
3478
					int column = caret - lineOffset + (tabWidth - 1)
3208
					
3479
							* occurrences;
3209
					String format= CompareMessages.TextMergeViewer_cursorPosition_format;
3480
3210
					return MessageFormat.format(format,
3481
					String format = CompareMessages.TextMergeViewer_cursorPosition_format;
3211
						new String[] { Integer.toString(line + 1), Integer.toString(column + 1) } );
3482
					return MessageFormat.format(format, new String[] {
3212
					
3483
							Integer.toString(line + 1),
3484
							Integer.toString(column + 1) });
3485
3213
				} catch (BadLocationException x) {
3486
				} catch (BadLocationException x) {
3214
					// silently ignored
3487
					// silently ignored
3215
				}
3488
				}
3216
			}
3489
			}
3217
		}
3490
		}
3218
		return "";	//$NON-NLS-1$
3491
		return ""; //$NON-NLS-1$
3219
	}
3492
	}
3220
3493
3221
	protected void updateHeader() {
3494
	protected void updateHeader() {
3222
		
3495
3223
		super.updateHeader();
3496
		super.updateHeader();
3224
				
3497
3225
		updateControls();
3498
		updateControls();
3226
	}
3499
	}
3227
3500
3228
	/*
3501
	/*
3229
	 * Creates the two items for copying a difference range from one side to the other
3502
	 * Creates the two items for copying a difference range from one side to the
3230
	 * and adds them to the given toolbar manager.
3503
	 * other and adds them to the given toolbar manager.
3231
	 */
3504
	 */
3232
	protected void createToolItems(ToolBarManager tbm) {
3505
	protected void createToolItems(ToolBarManager tbm) {
3233
3506
3234
		fHandlerService= CompareHandlerService.createFor(getCompareConfiguration().getContainer(), fLeft.getControl().getShell());
3507
		fHandlerService = CompareHandlerService.createFor(
3235
		
3508
				getCompareConfiguration().getContainer(), fLeft.getControl()
3236
		final String ignoreAncestorActionKey= "action.IgnoreAncestor.";	//$NON-NLS-1$
3509
						.getShell());
3237
		Action ignoreAncestorAction= new Action() {
3510
3511
		final String ignoreAncestorActionKey = "action.IgnoreAncestor."; //$NON-NLS-1$
3512
		Action ignoreAncestorAction = new Action() {
3238
			public void run() {
3513
			public void run() {
3239
				// First make sure the ancestor is hidden
3514
				// First make sure the ancestor is hidden
3240
				if (!isIgnoreAncestor())
3515
				if (!isIgnoreAncestor())
3241
					getCompareConfiguration().setProperty(ICompareUIConstants.PROP_ANCESTOR_VISIBLE, Boolean.FALSE);
3516
					getCompareConfiguration().setProperty(
3517
							ICompareUIConstants.PROP_ANCESTOR_VISIBLE,
3518
							Boolean.FALSE);
3242
				// Then set the property to ignore the ancestor
3519
				// Then set the property to ignore the ancestor
3243
				getCompareConfiguration().setProperty(ICompareUIConstants.PROP_IGNORE_ANCESTOR, Boolean.valueOf(!isIgnoreAncestor()));
3520
				getCompareConfiguration().setProperty(
3244
				Utilities.initToggleAction(this, getResourceBundle(), ignoreAncestorActionKey, isIgnoreAncestor());
3521
						ICompareUIConstants.PROP_IGNORE_ANCESTOR,
3522
						Boolean.valueOf(!isIgnoreAncestor()));
3523
				Utilities.initToggleAction(this, getResourceBundle(),
3524
						ignoreAncestorActionKey, isIgnoreAncestor());
3245
			}
3525
			}
3246
		};
3526
		};
3247
		ignoreAncestorAction.setChecked(isIgnoreAncestor());
3527
		ignoreAncestorAction.setChecked(isIgnoreAncestor());
3248
		Utilities.initAction(ignoreAncestorAction, getResourceBundle(), ignoreAncestorActionKey);
3528
		Utilities.initAction(ignoreAncestorAction, getResourceBundle(),
3249
		Utilities.initToggleAction(ignoreAncestorAction, getResourceBundle(), ignoreAncestorActionKey, isIgnoreAncestor());
3529
				ignoreAncestorActionKey);
3250
		
3530
		Utilities.initToggleAction(ignoreAncestorAction, getResourceBundle(),
3251
		fIgnoreAncestorItem= new ActionContributionItem(ignoreAncestorAction);
3531
				ignoreAncestorActionKey, isIgnoreAncestor());
3532
3533
		fIgnoreAncestorItem = new ActionContributionItem(ignoreAncestorAction);
3252
		fIgnoreAncestorItem.setVisible(false);
3534
		fIgnoreAncestorItem.setVisible(false);
3253
		tbm.appendToGroup("modes", fIgnoreAncestorItem); //$NON-NLS-1$
3535
		tbm.appendToGroup("modes", fIgnoreAncestorItem); //$NON-NLS-1$
3254
3536
3255
		tbm.add(new Separator());
3537
		tbm.add(new Separator());
3256
		
3538
3257
		Action a= new Action() {
3539
		Action a = new Action() {
3258
			public void run() {
3540
			public void run() {
3259
				if (navigate(true, false, false)) {
3541
				if (navigate(true, false, false)) {
3260
					endOfDocumentReached(true);
3542
					endOfDocumentReached(true);
Lines 3262-3272 Link Here
3262
			}
3544
			}
3263
		};
3545
		};
3264
		Utilities.initAction(a, getResourceBundle(), "action.NextDiff."); //$NON-NLS-1$
3546
		Utilities.initAction(a, getResourceBundle(), "action.NextDiff."); //$NON-NLS-1$
3265
		fNextDiff= new ActionContributionItem(a);
3547
		fNextDiff = new ActionContributionItem(a);
3266
		tbm.appendToGroup("navigation", fNextDiff); //$NON-NLS-1$
3548
		tbm.appendToGroup("navigation", fNextDiff); //$NON-NLS-1$
3267
		// Don't register this action since it is probably registered by the container
3549
		// Don't register this action since it is probably registered by the
3268
		
3550
		// container
3269
		a= new Action() {
3551
3552
		a = new Action() {
3270
			public void run() {
3553
			public void run() {
3271
				if (navigate(false, false, false)) {
3554
				if (navigate(false, false, false)) {
3272
					endOfDocumentReached(false);
3555
					endOfDocumentReached(false);
Lines 3274-3284 Link Here
3274
			}
3557
			}
3275
		};
3558
		};
3276
		Utilities.initAction(a, getResourceBundle(), "action.PrevDiff."); //$NON-NLS-1$
3559
		Utilities.initAction(a, getResourceBundle(), "action.PrevDiff."); //$NON-NLS-1$
3277
		fPreviousDiff= new ActionContributionItem(a);
3560
		fPreviousDiff = new ActionContributionItem(a);
3278
		tbm.appendToGroup("navigation", fPreviousDiff); //$NON-NLS-1$
3561
		tbm.appendToGroup("navigation", fPreviousDiff); //$NON-NLS-1$
3279
		// Don't register this action since it is probably registered by the container
3562
		// Don't register this action since it is probably registered by the
3280
		
3563
		// container
3281
		a= new Action() {
3564
3565
		a = new Action() {
3282
			public void run() {
3566
			public void run() {
3283
				if (navigate(true, false, true)) {
3567
				if (navigate(true, false, true)) {
3284
					endOfDocumentReached(true);
3568
					endOfDocumentReached(true);
Lines 3286-3296 Link Here
3286
			}
3570
			}
3287
		};
3571
		};
3288
		Utilities.initAction(a, getResourceBundle(), "action.NextChange."); //$NON-NLS-1$
3572
		Utilities.initAction(a, getResourceBundle(), "action.NextChange."); //$NON-NLS-1$
3289
		fNextChange= new ActionContributionItem(a);
3573
		fNextChange = new ActionContributionItem(a);
3290
		tbm.appendToGroup("navigation", fNextChange); //$NON-NLS-1$
3574
		tbm.appendToGroup("navigation", fNextChange); //$NON-NLS-1$
3291
		fHandlerService.registerAction(a, "org.eclipse.compare.selectNextChange");	//$NON-NLS-1$
3575
		fHandlerService.registerAction(a,
3292
		
3576
				"org.eclipse.compare.selectNextChange"); //$NON-NLS-1$
3293
		a= new Action() {
3577
3578
		a = new Action() {
3294
			public void run() {
3579
			public void run() {
3295
				if (navigate(false, false, true)) {
3580
				if (navigate(false, false, true)) {
3296
					endOfDocumentReached(false);
3581
					endOfDocumentReached(false);
Lines 3298-3407 Link Here
3298
			}
3583
			}
3299
		};
3584
		};
3300
		Utilities.initAction(a, getResourceBundle(), "action.PrevChange."); //$NON-NLS-1$
3585
		Utilities.initAction(a, getResourceBundle(), "action.PrevChange."); //$NON-NLS-1$
3301
		fPreviousChange= new ActionContributionItem(a);
3586
		fPreviousChange = new ActionContributionItem(a);
3302
		tbm.appendToGroup("navigation", fPreviousChange); //$NON-NLS-1$
3587
		tbm.appendToGroup("navigation", fPreviousChange); //$NON-NLS-1$
3303
		fHandlerService.registerAction(a, "org.eclipse.compare.selectPreviousChange");	//$NON-NLS-1$
3588
		fHandlerService.registerAction(a,
3589
				"org.eclipse.compare.selectPreviousChange"); //$NON-NLS-1$
3590
3591
		CompareConfiguration cc = getCompareConfiguration();
3304
3592
3305
		CompareConfiguration cc= getCompareConfiguration();
3306
		
3307
		if (cc.isRightEditable()) {
3593
		if (cc.isRightEditable()) {
3308
			a= new Action() {
3594
			a = new Action() {
3309
				public void run() {
3595
				public void run() {
3310
					copyDiffLeftToRight();
3596
					copyDiffLeftToRight();
3311
				}
3597
				}
3312
			};
3598
			};
3313
			Utilities.initAction(a, getResourceBundle(), "action.CopyDiffLeftToRight."); //$NON-NLS-1$
3599
			Utilities.initAction(a, getResourceBundle(),
3314
			fCopyDiffLeftToRightItem= new ActionContributionItem(a);
3600
					"action.CopyDiffLeftToRight."); //$NON-NLS-1$
3601
			fCopyDiffLeftToRightItem = new ActionContributionItem(a);
3315
			fCopyDiffLeftToRightItem.setVisible(true);
3602
			fCopyDiffLeftToRightItem.setVisible(true);
3316
			tbm.appendToGroup("merge", fCopyDiffLeftToRightItem); //$NON-NLS-1$
3603
			tbm.appendToGroup("merge", fCopyDiffLeftToRightItem); //$NON-NLS-1$
3317
			fHandlerService.registerAction(a, "org.eclipse.compare.copyLeftToRight");	//$NON-NLS-1$
3604
			fHandlerService.registerAction(a,
3605
					"org.eclipse.compare.copyLeftToRight"); //$NON-NLS-1$
3318
		}
3606
		}
3319
		
3607
3320
		if (cc.isLeftEditable()) {
3608
		if (cc.isLeftEditable()) {
3321
			a= new Action() {
3609
			a = new Action() {
3322
				public void run() {
3610
				public void run() {
3323
					copyDiffRightToLeft();
3611
					copyDiffRightToLeft();
3324
				}
3612
				}
3325
			};
3613
			};
3326
			Utilities.initAction(a, getResourceBundle(), "action.CopyDiffRightToLeft."); //$NON-NLS-1$
3614
			Utilities.initAction(a, getResourceBundle(),
3327
			fCopyDiffRightToLeftItem= new ActionContributionItem(a);
3615
					"action.CopyDiffRightToLeft."); //$NON-NLS-1$
3616
			fCopyDiffRightToLeftItem = new ActionContributionItem(a);
3328
			fCopyDiffRightToLeftItem.setVisible(true);
3617
			fCopyDiffRightToLeftItem.setVisible(true);
3329
			tbm.appendToGroup("merge", fCopyDiffRightToLeftItem); //$NON-NLS-1$
3618
			tbm.appendToGroup("merge", fCopyDiffRightToLeftItem); //$NON-NLS-1$
3330
			fHandlerService.registerAction(a, "org.eclipse.compare.copyRightToLeft");	//$NON-NLS-1$
3619
			fHandlerService.registerAction(a,
3620
					"org.eclipse.compare.copyRightToLeft"); //$NON-NLS-1$
3331
		}
3621
		}
3332
		
3622
3333
		fIgnoreWhitespace= ChangePropertyAction.createIgnoreWhiteSpaceAction(getResourceBundle(), getCompareConfiguration());
3623
		fIgnoreWhitespace = ChangePropertyAction.createIgnoreWhiteSpaceAction(
3334
		fIgnoreWhitespace.setActionDefinitionId(ICompareUIConstants.COMMAND_IGNORE_WHITESPACE);
3624
				getResourceBundle(), getCompareConfiguration());
3625
		fIgnoreWhitespace
3626
				.setActionDefinitionId(ICompareUIConstants.COMMAND_IGNORE_WHITESPACE);
3335
		fLeft.addTextAction(fIgnoreWhitespace);
3627
		fLeft.addTextAction(fIgnoreWhitespace);
3336
		fRight.addTextAction(fIgnoreWhitespace);
3628
		fRight.addTextAction(fIgnoreWhitespace);
3337
		fAncestor.addTextAction(fIgnoreWhitespace);
3629
		fAncestor.addTextAction(fIgnoreWhitespace);
3338
		fHandlerService.registerAction(fIgnoreWhitespace, fIgnoreWhitespace.getActionDefinitionId());
3630
		fHandlerService.registerAction(fIgnoreWhitespace, fIgnoreWhitespace
3339
		
3631
				.getActionDefinitionId());
3340
		showWhitespaceAction = new ShowWhitespaceAction(new MergeSourceViewer[] {
3632
3341
				fLeft, fRight, fAncestor
3633
		showWhitespaceAction = new ShowWhitespaceAction(
3342
		});
3634
				new MergeSourceViewer[] { fLeft, fRight, fAncestor });
3343
		fHandlerService.registerAction(showWhitespaceAction, ITextEditorActionDefinitionIds.SHOW_WHITESPACE_CHARACTERS);
3635
		fHandlerService.registerAction(showWhitespaceAction,
3344
		
3636
				ITextEditorActionDefinitionIds.SHOW_WHITESPACE_CHARACTERS);
3345
		toggleLineNumbersAction = new TextEditorPropertyAction(CompareMessages.TextMergeViewer_16, new MergeSourceViewer[] {
3637
3346
				fLeft, fRight, fAncestor
3638
		toggleLineNumbersAction = new TextEditorPropertyAction(
3347
		}, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_LINE_NUMBER_RULER);
3639
				CompareMessages.TextMergeViewer_16,
3348
		fHandlerService.registerAction(toggleLineNumbersAction, ITextEditorActionDefinitionIds.LINENUMBER_TOGGLE);
3640
				new MergeSourceViewer[] { fLeft, fRight, fAncestor },
3349
	}
3641
				AbstractDecoratedTextEditorPreferenceConstants.EDITOR_LINE_NUMBER_RULER);
3350
	
3642
		fHandlerService.registerAction(toggleLineNumbersAction,
3351
	/* (non-Javadoc)
3643
				ITextEditorActionDefinitionIds.LINENUMBER_TOGGLE);
3352
	 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#handlePropertyChangeEvent(org.eclipse.jface.util.PropertyChangeEvent)
3644
	}
3645
3646
	/*
3647
	 * (non-Javadoc)
3648
	 * 
3649
	 * @seeorg.eclipse.compare.contentmergeviewer.ContentMergeViewer#
3650
	 * handlePropertyChangeEvent(org.eclipse.jface.util.PropertyChangeEvent)
3353
	 */
3651
	 */
3354
	protected void handlePropertyChangeEvent(PropertyChangeEvent event) {
3652
	protected void handlePropertyChangeEvent(PropertyChangeEvent event) {
3355
		
3653
3356
		String key= event.getProperty();
3654
		String key = event.getProperty();
3357
		
3655
3358
		if (key.equals(CompareConfiguration.IGNORE_WHITESPACE)
3656
		if (key.equals(CompareConfiguration.IGNORE_WHITESPACE)
3359
				|| key.equals(ComparePreferencePage.SHOW_PSEUDO_CONFLICTS)) {
3657
				|| key.equals(ComparePreferencePage.SHOW_PSEUDO_CONFLICTS)) {
3360
					
3658
3361
			fShowPseudoConflicts= fPreferenceStore.getBoolean(ComparePreferencePage.SHOW_PSEUDO_CONFLICTS);
3659
			fShowPseudoConflicts = fPreferenceStore
3362
			
3660
					.getBoolean(ComparePreferencePage.SHOW_PSEUDO_CONFLICTS);
3661
3363
			update(true);
3662
			update(true);
3364
			selectFirstDiff(true);
3663
			selectFirstDiff(true);
3365
			
3664
3366
//		} else if (key.equals(ComparePreferencePage.USE_SPLINES)) {
3665
			// } else if (key.equals(ComparePreferencePage.USE_SPLINES)) {
3367
//			fUseSplines= fPreferenceStore.getBoolean(ComparePreferencePage.USE_SPLINES);
3666
			// fUseSplines=
3368
//			invalidateLines();
3667
			// fPreferenceStore.getBoolean(ComparePreferencePage.USE_SPLINES);
3668
			// invalidateLines();
3369
3669
3370
		} else if (key.equals(ComparePreferencePage.USE_SINGLE_LINE)) {
3670
		} else if (key.equals(ComparePreferencePage.USE_SINGLE_LINE)) {
3371
			fUseSingleLine= fPreferenceStore.getBoolean(ComparePreferencePage.USE_SINGLE_LINE);
3671
			fUseSingleLine = fPreferenceStore
3372
//			fUseResolveUI= fUseSingleLine;
3672
					.getBoolean(ComparePreferencePage.USE_SINGLE_LINE);
3373
			fBasicCenterCurve= null;
3673
			// fUseResolveUI= fUseSingleLine;
3674
			fBasicCenterCurve = null;
3374
			updateResolveStatus();
3675
			updateResolveStatus();
3375
			invalidateLines();
3676
			invalidateLines();
3376
	
3677
3377
		} else if (key.equals(ComparePreferencePage.HIGHLIGHT_TOKEN_CHANGES)) {
3678
		} else if (key.equals(ComparePreferencePage.HIGHLIGHT_TOKEN_CHANGES)) {
3378
			fHighlightTokenChanges= fPreferenceStore.getBoolean(ComparePreferencePage.HIGHLIGHT_TOKEN_CHANGES);
3679
			fHighlightTokenChanges = fPreferenceStore
3680
					.getBoolean(ComparePreferencePage.HIGHLIGHT_TOKEN_CHANGES);
3379
			updateResolveStatus();
3681
			updateResolveStatus();
3380
			updatePresentation(null);
3682
			updatePresentation(null);
3381
			
3683
3382
//		} else if (key.equals(ComparePreferencePage.USE_RESOLVE_UI)) {
3684
			// } else if (key.equals(ComparePreferencePage.USE_RESOLVE_UI)) {
3383
//			fUseResolveUI= fPreferenceStore.getBoolean(ComparePreferencePage.USE_RESOLVE_UI);
3685
			// fUseResolveUI=
3384
//			updateResolveStatus();
3686
			// fPreferenceStore.getBoolean(ComparePreferencePage.USE_RESOLVE_UI);
3385
//			invalidateLines();
3687
			// updateResolveStatus();
3386
		
3688
			// invalidateLines();
3689
3387
		} else if (key.equals(fSymbolicFontName)) {
3690
		} else if (key.equals(fSymbolicFontName)) {
3388
			updateFont();
3691
			updateFont();
3389
			invalidateLines();
3692
			invalidateLines();
3390
3693
3391
		} else if (key.equals(INCOMING_COLOR) || key.equals(OUTGOING_COLOR) || key.equals(CONFLICTING_COLOR) || key.equals(RESOLVED_COLOR)) {
3694
		} else if (key.equals(INCOMING_COLOR) || key.equals(OUTGOING_COLOR)
3695
				|| key.equals(CONFLICTING_COLOR) || key.equals(RESOLVED_COLOR)) {
3392
			updateColors(null);
3696
			updateColors(null);
3393
			invalidateLines();
3697
			invalidateLines();
3394
			invalidateTextPresentation();
3698
			invalidateTextPresentation();
3395
			
3699
3396
		} else if (key.equals(ComparePreferencePage.SYNCHRONIZE_SCROLLING)) {
3700
		} else if (key.equals(ComparePreferencePage.SYNCHRONIZE_SCROLLING)) {
3397
			boolean b= fPreferenceStore.getBoolean(ComparePreferencePage.SYNCHRONIZE_SCROLLING);
3701
			boolean b = fPreferenceStore
3702
					.getBoolean(ComparePreferencePage.SYNCHRONIZE_SCROLLING);
3398
			setSyncScrolling(b);
3703
			setSyncScrolling(b);
3399
		
3704
3400
		} else if (key.equals(ComparePreferencePage.SHOW_MORE_INFO)) {
3705
		} else if (key.equals(ComparePreferencePage.SHOW_MORE_INFO)) {
3401
			
3706
3402
			boolean b= fPreferenceStore.getBoolean(ComparePreferencePage.SHOW_MORE_INFO);
3707
			boolean b = fPreferenceStore
3708
					.getBoolean(ComparePreferencePage.SHOW_MORE_INFO);
3403
			if (b != fShowMoreInfo) {
3709
			if (b != fShowMoreInfo) {
3404
				fShowMoreInfo= b;
3710
				fShowMoreInfo = b;
3405
				if (fShowMoreInfo)
3711
				if (fShowMoreInfo)
3406
					updateStatus(fCurrentDiff);
3712
					updateStatus(fCurrentDiff);
3407
				else
3713
				else
Lines 3409-3527 Link Here
3409
			}
3715
			}
3410
		} else if (key.equals(AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND)) {
3716
		} else if (key.equals(AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND)) {
3411
			if (!fIsUsingSystemBackground) {
3717
			if (!fIsUsingSystemBackground) {
3412
				setBackgroundColor(createColor(fPreferenceStore, AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND));
3718
				setBackgroundColor(createColor(fPreferenceStore,
3719
						AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND));
3413
			}
3720
			}
3414
3721
3415
		} else if (key.equals(AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT)) {
3722
		} else if (key
3416
			fIsUsingSystemBackground= fPreferenceStore.getBoolean(AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT);
3723
				.equals(AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT)) {
3724
			fIsUsingSystemBackground = fPreferenceStore
3725
					.getBoolean(AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT);
3417
			if (fIsUsingSystemBackground) {
3726
			if (fIsUsingSystemBackground) {
3418
				setBackgroundColor(null);
3727
				setBackgroundColor(null);
3419
			} else {
3728
			} else {
3420
				setBackgroundColor(createColor(fPreferenceStore, AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND));
3729
				setBackgroundColor(createColor(fPreferenceStore,
3730
						AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND));
3421
			}
3731
			}
3422
		} else if (key.equals(AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND)) {
3732
		} else if (key.equals(AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND)) {
3423
			if (!fIsUsingSystemForeground) {
3733
			if (!fIsUsingSystemForeground) {
3424
				setForegroundColor(createColor(fPreferenceStore, AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND));
3734
				setForegroundColor(createColor(fPreferenceStore,
3735
						AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND));
3425
			}
3736
			}
3426
3737
3427
		} else if (key.equals(AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT)) {
3738
		} else if (key
3428
			fIsUsingSystemForeground= fPreferenceStore.getBoolean(AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT);
3739
				.equals(AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT)) {
3740
			fIsUsingSystemForeground = fPreferenceStore
3741
					.getBoolean(AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT);
3429
			if (fIsUsingSystemForeground) {
3742
			if (fIsUsingSystemForeground) {
3430
				setForegroundColor(null);
3743
				setForegroundColor(null);
3431
			} else {
3744
			} else {
3432
				setForegroundColor(createColor(fPreferenceStore, AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND));
3745
				setForegroundColor(createColor(fPreferenceStore,
3746
						AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND));
3433
			}
3747
			}
3434
		} else {
3748
		} else {
3435
			super.handlePropertyChangeEvent(event);
3749
			super.handlePropertyChangeEvent(event);
3436
			
3750
3437
			if (key.equals(ICompareUIConstants.PROP_IGNORE_ANCESTOR)) {
3751
			if (key.equals(ICompareUIConstants.PROP_IGNORE_ANCESTOR)) {
3438
				update(false);
3752
				update(false);
3439
				selectFirstDiff(true);
3753
				selectFirstDiff(true);
3440
			}
3754
			}
3441
		}
3755
		}
3442
	}
3756
	}
3443
	
3757
3444
	private void selectFirstDiff(boolean first) {
3758
	private void selectFirstDiff(boolean first) {
3445
		
3759
3446
		if (fLeft == null || fRight == null) {
3760
		if (fLeft == null || fRight == null) {
3447
			return;
3761
			return;
3448
		}
3762
		}
3449
		if (fLeft.getDocument() == null || fRight.getDocument() == null) {
3763
		if (fLeft.getDocument() == null || fRight.getDocument() == null) {
3450
			return;
3764
			return;
3451
		}
3765
		}
3452
		
3766
3453
		Diff firstDiff= null;
3767
		Diff firstDiff = null;
3454
		if (first)
3768
		if (first)
3455
			firstDiff= findNext(fRight, -1, -1, false);
3769
			firstDiff = findNext(fRight, -1, -1, false);
3456
		else
3770
		else
3457
			firstDiff= findPrev(fRight, 9999999, 9999999, false);
3771
			firstDiff = findPrev(fRight, 9999999, 9999999, false);
3458
		setCurrentDiff(firstDiff, true);
3772
		setCurrentDiff(firstDiff, true);
3459
	}
3773
	}
3460
	
3774
3461
	
3462
	
3463
	private void setSyncScrolling(boolean newMode) {
3775
	private void setSyncScrolling(boolean newMode) {
3464
		if (fSynchronizedScrolling != newMode) {
3776
		if (fSynchronizedScrolling != newMode) {
3465
			fSynchronizedScrolling= newMode;
3777
			fSynchronizedScrolling = newMode;
3466
			
3778
3467
			scrollVertical(0, 0, 0, null);
3779
			scrollVertical(0, 0, 0, null);
3468
			
3780
3469
			// throw away central control (Sash or Canvas)
3781
			// throw away central control (Sash or Canvas)
3470
			Control center= getCenterControl();
3782
			Control center = getCenterControl();
3471
			if (center != null && !center.isDisposed())
3783
			if (center != null && !center.isDisposed())
3472
				center.dispose();
3784
				center.dispose();
3473
			
3785
3474
			fLeft.getTextWidget().getVerticalBar().setVisible(!fSynchronizedScrolling);
3786
			fLeft.getTextWidget().getVerticalBar().setVisible(
3475
			fRight.getTextWidget().getVerticalBar().setVisible(!fSynchronizedScrolling);
3787
					!fSynchronizedScrolling);
3476
	
3788
			fRight.getTextWidget().getVerticalBar().setVisible(
3789
					!fSynchronizedScrolling);
3790
3477
			fComposite.layout(true);
3791
			fComposite.layout(true);
3478
		}
3792
		}
3479
	}
3793
	}
3480
					
3794
3481
	protected void updateToolItems() {
3795
	protected void updateToolItems() {
3482
		//only update toolbar items if diffs need to be calculated (which
3796
		// only update toolbar items if diffs need to be calculated (which
3483
		//dictates whether a toolbar gets added at all)
3797
		// dictates whether a toolbar gets added at all)
3484
		if (!isPatchHunk()){
3798
		if (!isPatchHunk()) {
3485
			if (fIgnoreAncestorItem != null)
3799
			if (fIgnoreAncestorItem != null)
3486
				fIgnoreAncestorItem.setVisible(isThreeWay());
3800
				fIgnoreAncestorItem.setVisible(isThreeWay());
3487
			
3801
3488
			if (fCopyDiffLeftToRightItem != null) {
3802
			if (fCopyDiffLeftToRightItem != null) {
3489
				IAction a= fCopyDiffLeftToRightItem.getAction();
3803
				IAction a = fCopyDiffLeftToRightItem.getAction();
3490
				if (a != null)
3804
				if (a != null)
3491
					a.setEnabled(a.isEnabled() && !fHasErrors);
3805
					a.setEnabled(a.isEnabled() && !fHasErrors);
3492
			}
3806
			}
3493
			if (fCopyDiffRightToLeftItem != null) {
3807
			if (fCopyDiffRightToLeftItem != null) {
3494
				IAction a= fCopyDiffRightToLeftItem.getAction();
3808
				IAction a = fCopyDiffRightToLeftItem.getAction();
3495
				if (a != null)
3809
				if (a != null)
3496
					a.setEnabled(a.isEnabled() && !fHasErrors);
3810
					a.setEnabled(a.isEnabled() && !fHasErrors);
3497
			}
3811
			}
3498
			
3812
3499
			super.updateToolItems();
3813
			super.updateToolItems();
3500
		}
3814
		}
3501
	}
3815
	}
3502
	
3816
3503
	//---- painting lines
3817
	// ---- painting lines
3504
	
3818
3505
	private void updateLines(IDocument d) {
3819
	private void updateLines(IDocument d) {
3506
3820
3507
		boolean left= false;
3821
		boolean left = false;
3508
		boolean right= false;
3822
		boolean right = false;
3509
		
3823
3510
		// FIXME: this optimization is incorrect because
3824
		// FIXME: this optimization is incorrect because
3511
		// it doesn't take replace operations into account where
3825
		// it doesn't take replace operations into account where
3512
		// the old and new line count does not differ
3826
		// the old and new line count does not differ
3513
		if (d == fLeft.getDocument()) {
3827
		if (d == fLeft.getDocument()) {
3514
			int l= fLeft.getLineCount();
3828
			int l = fLeft.getLineCount();
3515
			left= fLeftLineCount != l;
3829
			left = fLeftLineCount != l;
3516
			fLeftLineCount= l;
3830
			fLeftLineCount = l;
3517
		} else if (d == fRight.getDocument()) {
3831
		} else if (d == fRight.getDocument()) {
3518
			int l= fRight.getLineCount();
3832
			int l = fRight.getLineCount();
3519
			right= fRightLineCount != l;
3833
			right = fRightLineCount != l;
3520
			fRightLineCount= l;
3834
			fRightLineCount = l;
3521
		}
3835
		}
3522
		
3836
3523
		if (left || right) {
3837
		if (left || right) {
3524
			
3838
3525
			if (left) {
3839
			if (left) {
3526
				if (fLeftCanvas != null)
3840
				if (fLeftCanvas != null)
3527
					fLeftCanvas.redraw();
3841
					fLeftCanvas.redraw();
Lines 3529-3535 Link Here
3529
				if (fRightCanvas != null)
3843
				if (fRightCanvas != null)
3530
					fRightCanvas.redraw();
3844
					fRightCanvas.redraw();
3531
			}
3845
			}
3532
			Control center= getCenterControl();
3846
			Control center = getCenterControl();
3533
			if (center != null)
3847
			if (center != null)
3534
				center.redraw();
3848
				center.redraw();
3535
3849
Lines 3537-3543 Link Here
3537
			refreshBirdsEyeView();
3851
			refreshBirdsEyeView();
3538
		}
3852
		}
3539
	}
3853
	}
3540
	
3854
3541
	private void invalidateLines() {
3855
	private void invalidateLines() {
3542
		if (isThreeWay()) {
3856
		if (isThreeWay()) {
3543
			if (Utilities.okToUse(fAncestorCanvas))
3857
			if (Utilities.okToUse(fAncestorCanvas))
Lines 3545-3661 Link Here
3545
			if (fAncestor != null && fAncestor.isControlOkToUse())
3859
			if (fAncestor != null && fAncestor.isControlOkToUse())
3546
				fAncestor.getTextWidget().redraw();
3860
				fAncestor.getTextWidget().redraw();
3547
		}
3861
		}
3548
		
3862
3549
		if (Utilities.okToUse(fLeftCanvas))
3863
		if (Utilities.okToUse(fLeftCanvas))
3550
			fLeftCanvas.redraw();
3864
			fLeftCanvas.redraw();
3551
			
3865
3552
		if (fLeft != null && fLeft.isControlOkToUse())
3866
		if (fLeft != null && fLeft.isControlOkToUse())
3553
			fLeft.getTextWidget().redraw();
3867
			fLeft.getTextWidget().redraw();
3554
			
3868
3555
		if (Utilities.okToUse(getCenterControl()))
3869
		if (Utilities.okToUse(getCenterControl()))
3556
			getCenterControl().redraw();
3870
			getCenterControl().redraw();
3557
			
3871
3558
		if (fRight != null && fRight.isControlOkToUse())
3872
		if (fRight != null && fRight.isControlOkToUse())
3559
			fRight.getTextWidget().redraw();
3873
			fRight.getTextWidget().redraw();
3560
			
3874
3561
		if (Utilities.okToUse(fRightCanvas))
3875
		if (Utilities.okToUse(fRightCanvas))
3562
			fRightCanvas.redraw();
3876
			fRightCanvas.redraw();
3563
	}
3877
	}
3564
	
3878
3565
	private boolean showResolveUI() {
3879
	private boolean showResolveUI() {
3566
		if (!fUseResolveUI || !isThreeWay() || isIgnoreAncestor())
3880
		if (!fUseResolveUI || !isThreeWay() || isIgnoreAncestor())
3567
			return false;
3881
			return false;
3568
		CompareConfiguration cc= getCompareConfiguration();
3882
		CompareConfiguration cc = getCompareConfiguration();
3569
		// we only enable the new resolve UI if exactly one side is editable
3883
		// we only enable the new resolve UI if exactly one side is editable
3570
		boolean l= cc.isLeftEditable();
3884
		boolean l = cc.isLeftEditable();
3571
		boolean r= cc.isRightEditable();
3885
		boolean r = cc.isRightEditable();
3572
		//return (l && !r) || (r && !l);
3886
		// return (l && !r) || (r && !l);
3573
		return l || r;
3887
		return l || r;
3574
	}
3888
	}
3575
	
3889
3576
	private void paintCenter(Canvas canvas, GC g) {
3890
	private void paintCenter(Canvas canvas, GC g) {
3577
		
3891
3578
		Display display= canvas.getDisplay();
3892
		Display display = canvas.getDisplay();
3579
		
3893
3580
		checkForColorUpdate(display);
3894
		checkForColorUpdate(display);
3581
		
3895
3582
		if (! fSynchronizedScrolling)
3896
		if (!fSynchronizedScrolling)
3583
			return;
3897
			return;
3584
3898
3585
		int lineHeightLeft= fLeft.getTextWidget().getLineHeight();
3899
		int lineHeightLeft = fLeft.getTextWidget().getLineHeight();
3586
		int lineHeightRight= fRight.getTextWidget().getLineHeight();
3900
		int lineHeightRight = fRight.getTextWidget().getLineHeight();
3587
		int visibleHeight= fRight.getViewportHeight();
3901
		int visibleHeight = fRight.getViewportHeight();
3588
3902
3589
		Point size= canvas.getSize();
3903
		Point size = canvas.getSize();
3590
		int x= 0;
3904
		int x = 0;
3591
		int w= size.x;
3905
		int w = size.x;
3592
				
3906
3593
		g.setBackground(canvas.getBackground());
3907
		g.setBackground(canvas.getBackground());
3594
		g.fillRectangle(x+1, 0, w-2, size.y);
3908
		g.fillRectangle(x + 1, 0, w - 2, size.y);
3595
		
3909
3596
		if (!fIsMotif) {
3910
		if (!fIsMotif) {
3597
			// draw thin line between center ruler and both texts
3911
			// draw thin line between center ruler and both texts
3598
			g.setBackground(display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW));
3912
			g.setBackground(display
3913
					.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW));
3599
			g.fillRectangle(0, 0, 1, size.y);
3914
			g.fillRectangle(0, 0, 1, size.y);
3600
			g.fillRectangle(w-1, 0, 1, size.y);
3915
			g.fillRectangle(w - 1, 0, 1, size.y);
3601
		}
3916
		}
3602
			
3917
3603
		if (! fHighlightRanges)
3918
		if (!fHighlightRanges)
3604
			return;
3919
			return;
3605
3920
3606
		boolean showResolveUI= showResolveUI();
3921
		boolean showResolveUI = showResolveUI();
3607
3922
3608
		if (fMerger.hasChanges()) {
3923
		if (fMerger.hasChanges()) {
3609
			int lshift= fLeft.getVerticalScrollOffset();
3924
			int lshift = fLeft.getVerticalScrollOffset();
3610
			int rshift= fRight.getVerticalScrollOffset();
3925
			int rshift = fRight.getVerticalScrollOffset();
3611
					
3926
3612
			Point region= new Point(0, 0);
3927
			Point region = new Point(0, 0);
3613
		
3928
3614
			for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) {
3929
			for (Iterator iterator = fMerger.changesIterator(); iterator
3930
					.hasNext();) {
3615
				Diff diff = (Diff) iterator.next();
3931
				Diff diff = (Diff) iterator.next();
3616
				if (diff.isDeleted())
3932
				if (diff.isDeleted())
3617
					continue;
3933
					continue;
3618
				
3934
3619
				if (fShowCurrentOnly2 && !isCurrentDiff(diff))
3935
				if (fShowCurrentOnly2 && !isCurrentDiff(diff))
3620
					continue;
3936
					continue;
3621
3937
3622
				fLeft.getLineRange(diff.getPosition(LEFT_CONTRIBUTOR), region);
3938
				fLeft.getLineRange(diff.getPosition(LEFT_CONTRIBUTOR), region);
3623
				int ly= (region.x * lineHeightLeft) + lshift;
3939
				int ly = (region.x * lineHeightLeft) + lshift;
3624
				int lh= region.y * lineHeightLeft;
3940
				int lh = region.y * lineHeightLeft;
3625
	
3941
3626
				fRight.getLineRange(diff.getPosition(RIGHT_CONTRIBUTOR), region);
3942
				fRight
3627
				int ry= (region.x * lineHeightRight) + rshift;
3943
						.getLineRange(diff.getPosition(RIGHT_CONTRIBUTOR),
3628
				int rh= region.y * lineHeightRight;
3944
								region);
3629
	
3945
				int ry = (region.x * lineHeightRight) + rshift;
3630
				if (Math.max(ly+lh, ry+rh) < 0)
3946
				int rh = region.y * lineHeightRight;
3947
3948
				if (Math.max(ly + lh, ry + rh) < 0)
3631
					continue;
3949
					continue;
3632
				if (Math.min(ly, ry) >= visibleHeight)
3950
				if (Math.min(ly, ry) >= visibleHeight)
3633
					break;
3951
					break;
3634
	
3952
3635
				fPts[0]= x;	fPts[1]= ly;	fPts[2]= w;	fPts[3]= ry;
3953
				fPts[0] = x;
3636
				fPts[6]= x;	fPts[7]= ly+lh;	fPts[4]= w;	fPts[5]= ry+rh;
3954
				fPts[1] = ly;
3637
				
3955
				fPts[2] = w;
3638
				Color fillColor= getColor(display, getFillColor(diff));
3956
				fPts[3] = ry;
3639
				Color strokeColor= getColor(display, getStrokeColor(diff));
3957
				fPts[6] = x;
3640
				
3958
				fPts[7] = ly + lh;
3959
				fPts[4] = w;
3960
				fPts[5] = ry + rh;
3961
3962
				Color fillColor = getColor(display, getFillColor(diff));
3963
				Color strokeColor = getColor(display, getStrokeColor(diff));
3964
3641
				if (fUseSingleLine) {
3965
				if (fUseSingleLine) {
3642
					int w2= 3;
3966
					int w2 = 3;
3643
3967
3644
					g.setBackground(fillColor);
3968
					g.setBackground(fillColor);
3645
					g.fillRectangle(0, ly, w2, lh);		// left
3969
					g.fillRectangle(0, ly, w2, lh); // left
3646
					g.fillRectangle(w-w2, ry, w2, rh);	// right
3970
					g.fillRectangle(w - w2, ry, w2, rh); // right
3647
3971
3648
					g.setLineWidth(0 /* LW */);
3972
					g.setLineWidth(0 /* LW */);
3649
					g.setForeground(strokeColor);
3973
					g.setForeground(strokeColor);
3650
					g.drawRectangle(0-1, ly, w2, lh);	// left
3974
					g.drawRectangle(0 - 1, ly, w2, lh); // left
3651
					g.drawRectangle(w-w2, ry, w2, rh);	// right
3975
					g.drawRectangle(w - w2, ry, w2, rh); // right
3652
3976
3653
					if (fUseSplines) {
3977
					if (fUseSplines) {
3654
						int[] points= getCenterCurvePoints(w2, ly+lh/2, w-w2, ry+rh/2);
3978
						int[] points = getCenterCurvePoints(w2, ly + lh / 2, w
3655
						for (int i= 1; i < points.length; i++)
3979
								- w2, ry + rh / 2);
3656
							g.drawLine(w2+i-1, points[i-1], w2+i, points[i]);
3980
						for (int i = 1; i < points.length; i++)
3981
							g.drawLine(w2 + i - 1, points[i - 1], w2 + i,
3982
									points[i]);
3657
					} else {
3983
					} else {
3658
						g.drawLine(w2, ly+lh/2, w-w2, ry+rh/2);
3984
						g.drawLine(w2, ly + lh / 2, w - w2, ry + rh / 2);
3659
					}
3985
					}
3660
				} else {
3986
				} else {
3661
					// two lines
3987
					// two lines
Lines 3665-3680 Link Here
3665
						g.setLineWidth(0 /* LW */);
3991
						g.setLineWidth(0 /* LW */);
3666
						g.setForeground(strokeColor);
3992
						g.setForeground(strokeColor);
3667
3993
3668
						int[] topPoints= getCenterCurvePoints(fPts[0], fPts[1], fPts[2], fPts[3]);
3994
						int[] topPoints = getCenterCurvePoints(fPts[0],
3669
						int[] bottomPoints= getCenterCurvePoints(fPts[6], fPts[7], fPts[4], fPts[5]);
3995
								fPts[1], fPts[2], fPts[3]);
3996
						int[] bottomPoints = getCenterCurvePoints(fPts[6],
3997
								fPts[7], fPts[4], fPts[5]);
3670
						g.setForeground(fillColor);
3998
						g.setForeground(fillColor);
3671
						g.drawLine(0, bottomPoints[0], 0, topPoints[0]);
3999
						g.drawLine(0, bottomPoints[0], 0, topPoints[0]);
3672
						for (int i= 1; i < bottomPoints.length; i++) {
4000
						for (int i = 1; i < bottomPoints.length; i++) {
3673
							g.setForeground(fillColor);
4001
							g.setForeground(fillColor);
3674
							g.drawLine(i, bottomPoints[i], i, topPoints[i]);
4002
							g.drawLine(i, bottomPoints[i], i, topPoints[i]);
3675
							g.setForeground(strokeColor);
4003
							g.setForeground(strokeColor);
3676
							g.drawLine(i-1, topPoints[i-1], i, topPoints[i]);
4004
							g
3677
							g.drawLine(i-1, bottomPoints[i-1], i, bottomPoints[i]);
4005
									.drawLine(i - 1, topPoints[i - 1], i,
4006
											topPoints[i]);
4007
							g.drawLine(i - 1, bottomPoints[i - 1], i,
4008
									bottomPoints[i]);
3678
						}
4009
						}
3679
					} else {
4010
					} else {
3680
						g.setBackground(fillColor);
4011
						g.setBackground(fillColor);
Lines 3686-3843 Link Here
3686
						g.drawLine(fPts[6], fPts[7], fPts[4], fPts[5]);
4017
						g.drawLine(fPts[6], fPts[7], fPts[4], fPts[5]);
3687
					}
4018
					}
3688
				}
4019
				}
3689
				
4020
3690
				if (fUseSingleLine && showResolveUI && diff.isUnresolvedIncomingOrConflicting()) {
4021
				if (fUseSingleLine && showResolveUI
4022
						&& diff.isUnresolvedIncomingOrConflicting()) {
3691
					// draw resolve state
4023
					// draw resolve state
3692
					int cx= (w-RESOLVE_SIZE)/2;
4024
					int cx = (w - RESOLVE_SIZE) / 2;
3693
					int cy= ((ly+lh/2) + (ry+rh/2) - RESOLVE_SIZE)/2;
4025
					int cy = ((ly + lh / 2) + (ry + rh / 2) - RESOLVE_SIZE) / 2;
3694
					
4026
3695
					g.setBackground(fillColor);
4027
					g.setBackground(fillColor);
3696
					g.fillRectangle(cx, cy, RESOLVE_SIZE, RESOLVE_SIZE);
4028
					g.fillRectangle(cx, cy, RESOLVE_SIZE, RESOLVE_SIZE);
3697
					
4029
3698
					g.setForeground(strokeColor);
4030
					g.setForeground(strokeColor);
3699
					g.drawRectangle(cx, cy, RESOLVE_SIZE, RESOLVE_SIZE);
4031
					g.drawRectangle(cx, cy, RESOLVE_SIZE, RESOLVE_SIZE);
3700
				}
4032
				}
3701
			}
4033
			}
3702
		}
4034
		}
3703
	}
4035
	}
3704
	
4036
3705
	private int[] getCenterCurvePoints(int startx, int starty, int endx, int endy) {
4037
	private int[] getCenterCurvePoints(int startx, int starty, int endx,
4038
			int endy) {
3706
		if (fBasicCenterCurve == null)
4039
		if (fBasicCenterCurve == null)
3707
			buildBaseCenterCurve(endx-startx);
4040
			buildBaseCenterCurve(endx - startx);
3708
		double height= endy - starty;
4041
		double height = endy - starty;
3709
		height= height/2;
4042
		height = height / 2;
3710
		int width= endx-startx;
4043
		int width = endx - startx;
3711
		int[] points= new int[width];
4044
		int[] points = new int[width];
3712
		for (int i= 0; i < width; i++) {
4045
		for (int i = 0; i < width; i++) {
3713
			points[i]= (int) (-height * fBasicCenterCurve[i] + height + starty);
4046
			points[i] = (int) (-height * fBasicCenterCurve[i] + height + starty);
3714
		}
4047
		}
3715
		return points;
4048
		return points;
3716
	}
4049
	}
3717
4050
3718
	private void buildBaseCenterCurve(int w) {
4051
	private void buildBaseCenterCurve(int w) {
3719
		double width= w;
4052
		double width = w;
3720
		fBasicCenterCurve= new double[getCenterWidth()];
4053
		fBasicCenterCurve = new double[getCenterWidth()];
3721
		for (int i= 0; i < getCenterWidth(); i++) {
4054
		for (int i = 0; i < getCenterWidth(); i++) {
3722
			double r= i / width;
4055
			double r = i / width;
3723
			fBasicCenterCurve[i]= Math.cos(Math.PI * r);
4056
			fBasicCenterCurve[i] = Math.cos(Math.PI * r);
3724
		}
4057
		}
3725
	}
4058
	}
3726
4059
3727
	private void paintSides(GC g, MergeSourceViewer tp, Canvas canvas, boolean right) {
4060
	private void paintSides(GC g, MergeSourceViewer tp, Canvas canvas,
3728
		
4061
			boolean right) {
3729
		Display display= canvas.getDisplay();
4062
3730
		
4063
		Display display = canvas.getDisplay();
3731
		int lineHeight= tp.getTextWidget().getLineHeight();
4064
3732
		int visibleHeight= tp.getViewportHeight();
4065
		int lineHeight = tp.getTextWidget().getLineHeight();
3733
4066
		int visibleHeight = tp.getViewportHeight();
3734
		Point size= canvas.getSize();
4067
3735
		int x= 0;
4068
		Point size = canvas.getSize();
3736
		int w= fMarginWidth;
4069
		int x = 0;
3737
		int w2= w/2;
4070
		int w = fMarginWidth;
3738
			
4071
		int w2 = w / 2;
4072
3739
		g.setBackground(canvas.getBackground());
4073
		g.setBackground(canvas.getBackground());
3740
		g.fillRectangle(x, 0, w, size.y);
4074
		g.fillRectangle(x, 0, w, size.y);
3741
4075
3742
		if (!fIsMotif) {
4076
		if (!fIsMotif) {
3743
			// draw thin line between ruler and text
4077
			// draw thin line between ruler and text
3744
			g.setBackground(display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW));
4078
			g.setBackground(display
4079
					.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW));
3745
			if (right)
4080
			if (right)
3746
				g.fillRectangle(0, 0, 1, size.y);
4081
				g.fillRectangle(0, 0, 1, size.y);
3747
			else
4082
			else
3748
				g.fillRectangle(size.x-1, 0, 1, size.y);
4083
				g.fillRectangle(size.x - 1, 0, 1, size.y);
3749
		}
4084
		}
3750
4085
3751
		if (! fHighlightRanges)
4086
		if (!fHighlightRanges)
3752
			return;
4087
			return;
3753
4088
3754
		if (fMerger.hasChanges()) {
4089
		if (fMerger.hasChanges()) {
3755
			int shift= tp.getVerticalScrollOffset() + (2-LW);
4090
			int shift = tp.getVerticalScrollOffset() + (2 - LW);
3756
				
4091
3757
			Point region= new Point(0, 0);
4092
			Point region = new Point(0, 0);
3758
			char leg = getLeg(tp);
4093
			char leg = getLeg(tp);
3759
			for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) {
4094
			for (Iterator iterator = fMerger.changesIterator(); iterator
4095
					.hasNext();) {
3760
				Diff diff = (Diff) iterator.next();
4096
				Diff diff = (Diff) iterator.next();
3761
				if (diff.isDeleted())
4097
				if (diff.isDeleted())
3762
					continue;
4098
					continue;
3763
				
4099
3764
				if (fShowCurrentOnly2 && !isCurrentDiff(diff))
4100
				if (fShowCurrentOnly2 && !isCurrentDiff(diff))
3765
					continue;
4101
					continue;
3766
4102
3767
				tp.getLineRange(diff.getPosition(leg), region);
4103
				tp.getLineRange(diff.getPosition(leg), region);
3768
				int y= (region.x * lineHeight) + shift;
4104
				int y = (region.x * lineHeight) + shift;
3769
				int h= region.y * lineHeight;
4105
				int h = region.y * lineHeight;
3770
	
4106
3771
				if (y+h < 0)
4107
				if (y + h < 0)
3772
					continue;
4108
					continue;
3773
				if (y >= visibleHeight)
4109
				if (y >= visibleHeight)
3774
					break;
4110
					break;
3775
					
4111
3776
				g.setBackground(getColor(display, getFillColor(diff)));
4112
				g.setBackground(getColor(display, getFillColor(diff)));
3777
				if (right)
4113
				if (right)
3778
					g.fillRectangle(x, y, w2, h);
4114
					g.fillRectangle(x, y, w2, h);
3779
				else
4115
				else
3780
					g.fillRectangle(x+w2, y, w2, h);
4116
					g.fillRectangle(x + w2, y, w2, h);
3781
	
4117
3782
				g.setLineWidth(0 /* LW */);
4118
				g.setLineWidth(0 /* LW */);
3783
				g.setForeground(getColor(display, getStrokeColor(diff)));
4119
				g.setForeground(getColor(display, getStrokeColor(diff)));
3784
				if (right)
4120
				if (right)
3785
					g.drawRectangle(x-1, y-1, w2, h);
4121
					g.drawRectangle(x - 1, y - 1, w2, h);
3786
				else
4122
				else
3787
					g.drawRectangle(x+w2, y-1, w2, h);
4123
					g.drawRectangle(x + w2, y - 1, w2, h);
3788
			}
4124
			}
3789
		}
4125
		}
3790
	}
4126
	}
3791
	
4127
3792
	private void paint(PaintEvent event, MergeSourceViewer tp) {
4128
	private void paint(PaintEvent event, MergeSourceViewer tp) {
3793
		
4129
3794
		if (! fHighlightRanges)
4130
		if (!fHighlightRanges)
3795
			return;
4131
			return;
3796
		if (!fMerger.hasChanges())
4132
		if (!fMerger.hasChanges())
3797
			return;
4133
			return;
3798
4134
3799
		Control canvas= (Control) event.widget;
4135
		Control canvas = (Control) event.widget;
3800
		GC g= event.gc;
4136
		GC g = event.gc;
3801
		
4137
3802
		Display display= canvas.getDisplay();
4138
		Display display = canvas.getDisplay();
3803
		
4139
3804
		int lineHeight= tp.getTextWidget().getLineHeight();
4140
		int lineHeight = tp.getTextWidget().getLineHeight();
3805
		int w= canvas.getSize().x;
4141
		int w = canvas.getSize().x;
3806
		int shift= tp.getVerticalScrollOffset() + (2-LW);
4142
		int shift = tp.getVerticalScrollOffset() + (2 - LW);
3807
		int maxh= event.y+event.height; 	// visibleHeight
4143
		int maxh = event.y + event.height; // visibleHeight
3808
		
4144
3809
		//if (fIsMotif)
4145
		// if (fIsMotif)
3810
			shift+= fTopInset;
4146
		shift += fTopInset;
3811
				
4147
3812
		Point range= new Point(0, 0);
4148
		Point range = new Point(0, 0);
3813
		
4149
3814
		char leg = getLeg(tp);
4150
		char leg = getLeg(tp);
3815
		for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) {
4151
		for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) {
3816
			Diff diff = (Diff) iterator.next();
4152
			Diff diff = (Diff) iterator.next();
3817
			if (diff.isDeleted())
4153
			if (diff.isDeleted())
3818
				continue;
4154
				continue;
3819
			
4155
3820
			if (fShowCurrentOnly && !isCurrentDiff(diff))
4156
			if (fShowCurrentOnly && !isCurrentDiff(diff))
3821
				continue;
4157
				continue;
3822
4158
3823
			tp.getLineRange(diff.getPosition(leg), range);
4159
			tp.getLineRange(diff.getPosition(leg), range);
3824
			int y= (range.x * lineHeight) + shift;
4160
			int y = (range.x * lineHeight) + shift;
3825
			int h= range.y * lineHeight;
4161
			int h = range.y * lineHeight;
3826
			
4162
3827
			if (y+h < event.y)
4163
			if (y + h < event.y)
3828
				continue;
4164
				continue;
3829
			if (y > maxh)
4165
			if (y > maxh)
3830
				break;
4166
				break;
3831
			
4167
3832
			g.setBackground(getColor(display, getStrokeColor(diff)));
4168
			g.setBackground(getColor(display, getStrokeColor(diff)));
3833
			g.fillRectangle(0, y-1, w, LW);
4169
			g.fillRectangle(0, y - 1, w, LW);
3834
			g.fillRectangle(0, y+h-1, w, LW);
4170
			g.fillRectangle(0, y + h - 1, w, LW);
3835
		}
4171
		}
3836
	}
4172
	}
3837
4173
3838
	private RGB getFillColor(Diff diff) {
4174
	private RGB getFillColor(Diff diff) {
3839
		boolean selected= fCurrentDiff != null && fCurrentDiff.getParent() == diff;
4175
		boolean selected = fCurrentDiff != null
3840
		RGB selected_fill= getBackground(null);
4176
				&& fCurrentDiff.getParent() == diff;
4177
		RGB selected_fill = getBackground(null);
3841
		if (isThreeWay() && !isIgnoreAncestor()) {
4178
		if (isThreeWay() && !isIgnoreAncestor()) {
3842
			switch (diff.getKind()) {
4179
			switch (diff.getKind()) {
3843
			case RangeDifference.RIGHT:
4180
			case RangeDifference.RIGHT:
Lines 3857-3866 Link Here
3857
		}
4194
		}
3858
		return selected ? selected_fill : OUTGOING_FILL;
4195
		return selected ? selected_fill : OUTGOING_FILL;
3859
	}
4196
	}
3860
	
4197
3861
	private RGB getStrokeColor(Diff diff) {
4198
	private RGB getStrokeColor(Diff diff) {
3862
		boolean selected= fCurrentDiff != null && fCurrentDiff.getParent() == diff;
4199
		boolean selected = fCurrentDiff != null
3863
		
4200
				&& fCurrentDiff.getParent() == diff;
4201
3864
		if (isThreeWay() && !isIgnoreAncestor()) {
4202
		if (isThreeWay() && !isIgnoreAncestor()) {
3865
			switch (diff.getKind()) {
4203
			switch (diff.getKind()) {
3866
			case RangeDifference.RIGHT:
4204
			case RangeDifference.RIGHT:
Lines 3880-3918 Link Here
3880
		}
4218
		}
3881
		return selected ? SELECTED_OUTGOING : OUTGOING;
4219
		return selected ? SELECTED_OUTGOING : OUTGOING;
3882
	}
4220
	}
3883
	
4221
3884
	private Color getColor(Display display, RGB rgb) {
4222
	private Color getColor(Display display, RGB rgb) {
3885
		if (rgb == null)
4223
		if (rgb == null)
3886
			return null;
4224
			return null;
3887
		if (fColors == null)
4225
		if (fColors == null)
3888
			fColors= new HashMap(20);
4226
			fColors = new HashMap(20);
3889
		Color c= (Color) fColors.get(rgb);
4227
		Color c = (Color) fColors.get(rgb);
3890
		if (c == null) {
4228
		if (c == null) {
3891
			c= new Color(display, rgb);
4229
			c = new Color(display, rgb);
3892
			fColors.put(rgb, c);
4230
			fColors.put(rgb, c);
3893
		}
4231
		}
3894
		return c;
4232
		return c;
3895
	}
4233
	}
3896
			
4234
3897
	static RGB interpolate(RGB fg, RGB bg, double scale) {
4235
	static RGB interpolate(RGB fg, RGB bg, double scale) {
3898
		if (fg != null && bg != null)
4236
		if (fg != null && bg != null)
3899
			return new RGB(
4237
			return new RGB((int) ((1.0 - scale) * fg.red + scale * bg.red),
3900
				(int)((1.0-scale) * fg.red + scale * bg.red),
4238
					(int) ((1.0 - scale) * fg.green + scale * bg.green),
3901
				(int)((1.0-scale) * fg.green + scale * bg.green),
4239
					(int) ((1.0 - scale) * fg.blue + scale * bg.blue));
3902
				(int)((1.0-scale) * fg.blue + scale * bg.blue)
3903
			);
3904
		if (fg != null)
4240
		if (fg != null)
3905
			return fg;
4241
			return fg;
3906
		if (bg != null)
4242
		if (bg != null)
3907
			return bg;
4243
			return bg;
3908
		return new RGB(128, 128, 128);	// a gray
4244
		return new RGB(128, 128, 128); // a gray
3909
	}
4245
	}
3910
	
4246
3911
	//---- Navigating and resolving Diffs
4247
	// ---- Navigating and resolving Diffs
3912
	
4248
3913
	private Diff getNextVisibleDiff(boolean down, boolean deep) {
4249
	private Diff getNextVisibleDiff(boolean down, boolean deep) {
3914
		Diff diff= null;
4250
		Diff diff = null;
3915
		MergeSourceViewer part= getNavigationPart();
4251
		MergeSourceViewer part = getNavigationPart();
3916
		if (part == null)
4252
		if (part == null)
3917
			return null;
4253
			return null;
3918
		Point s = part.getSelectedRange();
4254
		Point s = part.getSelectedRange();
Lines 3924-3962 Link Here
3924
					&& !isAncestorVisible()) {
4260
					&& !isAncestorVisible()) {
3925
				Position position = diff.getPosition(leg);
4261
				Position position = diff.getPosition(leg);
3926
				s = new Point(position.getOffset(), position.getLength());
4262
				s = new Point(position.getOffset(), position.getLength());
3927
				diff= null;
4263
				diff = null;
3928
				continue;
4264
				continue;
3929
			}
4265
			}
3930
			break;
4266
			break;
3931
		}
4267
		}
3932
		return diff;
4268
		return diff;
3933
	}
4269
	}
3934
	
4270
3935
	private Diff internalGetNextDiff(boolean down, boolean deep, MergeSourceViewer part, Point s) {
4271
	private Diff internalGetNextDiff(boolean down, boolean deep,
4272
			MergeSourceViewer part, Point s) {
3936
		if (fMerger.hasChanges()) {
4273
		if (fMerger.hasChanges()) {
3937
			if (down)
4274
			if (down)
3938
				return findNext(part, s.x, s.x+s.y, deep);
4275
				return findNext(part, s.x, s.x + s.y, deep);
3939
			return findPrev(part, s.x, s.x+s.y, deep);
4276
			return findPrev(part, s.x, s.x + s.y, deep);
3940
		}
4277
		}
3941
		return null;
4278
		return null;
3942
	}
4279
	}
3943
	
4280
3944
	private MergeSourceViewer getNavigationPart() {
4281
	private MergeSourceViewer getNavigationPart() {
3945
		MergeSourceViewer part= fFocusPart;
4282
		MergeSourceViewer part = fFocusPart;
3946
		if (part == null)
4283
		if (part == null)
3947
			part= fRight;
4284
			part = fRight;
3948
		return part;
4285
		return part;
3949
	}
4286
	}
3950
4287
3951
	private Diff getWrappedDiff(Diff diff, boolean down) {
4288
	private Diff getWrappedDiff(Diff diff, boolean down) {
3952
		return fMerger.getWrappedDiff(diff, down);
4289
		return fMerger.getWrappedDiff(diff, down);
3953
	}
4290
	}
3954
	
4291
3955
	/*
4292
	/*
3956
	 * Returns true if end (or beginning) of document reached.
4293
	 * Returns true if end (or beginning) of document reached.
3957
	 */
4294
	 */
3958
	private boolean navigate(boolean down, boolean wrap, boolean deep) {
4295
	private boolean navigate(boolean down, boolean wrap, boolean deep) {
3959
		Diff diff= null;
4296
		Diff diff = null;
3960
		boolean wrapped = false;
4297
		boolean wrapped = false;
3961
		for (;;) {
4298
		for (;;) {
3962
			diff = getNextVisibleDiff(down, deep);
4299
			diff = getNextVisibleDiff(down, deep);
Lines 3976-3997 Link Here
3976
		}
4313
		}
3977
		return diff == null;
4314
		return diff == null;
3978
	}
4315
	}
3979
	
4316
3980
	private void endOfDocumentReached(boolean down) {
4317
	private void endOfDocumentReached(boolean down) {
3981
		Control c= getControl();
4318
		Control c = getControl();
3982
		if (Utilities.okToUse(c)) {
4319
		if (Utilities.okToUse(c)) {
3983
			handleEndOfDocumentReached(c.getShell(), down);
4320
			handleEndOfDocumentReached(c.getShell(), down);
3984
		}
4321
		}
3985
	}
4322
	}
3986
	
4323
3987
	private void handleEndOfDocumentReached(Shell shell, boolean next) {
4324
	private void handleEndOfDocumentReached(Shell shell, boolean next) {
3988
		boolean hasNextElement = hasNextElement(next);
4325
		boolean hasNextElement = hasNextElement(next);
3989
		IPreferenceStore store = CompareUIPlugin.getDefault().getPreferenceStore();
4326
		IPreferenceStore store = CompareUIPlugin.getDefault()
3990
		String value = store.getString(ICompareUIConstants.PREF_NAVIGATION_END_ACTION);
4327
				.getPreferenceStore();
4328
		String value = store
4329
				.getString(ICompareUIConstants.PREF_NAVIGATION_END_ACTION);
3991
		if (!value.equals(ICompareUIConstants.PREF_VALUE_PROMPT)) {
4330
		if (!value.equals(ICompareUIConstants.PREF_VALUE_PROMPT)) {
3992
			// We only want to do the automatic thing if there is something to do
4331
			// We only want to do the automatic thing if there is something to
3993
			if (hasNextElement || store.getString(ICompareUIConstants.PREF_NAVIGATION_END_ACTION).equals(ICompareUIConstants.PREF_VALUE_LOOP)) {
4332
			// do
3994
				performEndOfDocumentAction(shell, store, ICompareUIConstants.PREF_NAVIGATION_END_ACTION, next);
4333
			if (hasNextElement
4334
					|| store.getString(
4335
							ICompareUIConstants.PREF_NAVIGATION_END_ACTION)
4336
							.equals(ICompareUIConstants.PREF_VALUE_LOOP)) {
4337
				performEndOfDocumentAction(shell, store,
4338
						ICompareUIConstants.PREF_NAVIGATION_END_ACTION, next);
3995
				return;
4339
				return;
3996
			}
4340
			}
3997
		}
4341
		}
Lines 4012-4032 Link Here
4012
				loopMessage = CompareMessages.TextMergeViewer_6;
4356
				loopMessage = CompareMessages.TextMergeViewer_6;
4013
				nextMessage = CompareMessages.TextMergeViewer_7;
4357
				nextMessage = CompareMessages.TextMergeViewer_7;
4014
			}
4358
			}
4015
			String[] localLoopOption = new String[] { loopMessage, ICompareUIConstants.PREF_VALUE_LOOP };
4359
			String[] localLoopOption = new String[] { loopMessage,
4016
			String[] nextElementOption = new String[] { nextMessage, ICompareUIConstants.PREF_VALUE_NEXT};
4360
					ICompareUIConstants.PREF_VALUE_LOOP };
4017
			NavigationEndDialog dialog = new NavigationEndDialog(shell,
4361
			String[] nextElementOption = new String[] { nextMessage,
4018
					title,
4362
					ICompareUIConstants.PREF_VALUE_NEXT };
4019
					null,
4363
			NavigationEndDialog dialog = new NavigationEndDialog(shell, title,
4020
					message,
4364
					null, message, new String[][] { localLoopOption,
4021
					new String[][] {
4365
							nextElementOption, });
4022
					localLoopOption,
4023
					nextElementOption,
4024
			});
4025
			int result = dialog.open();
4366
			int result = dialog.open();
4026
			if (result == Window.OK) {
4367
			if (result == Window.OK) {
4027
				performEndOfDocumentAction(shell, store, ICompareUIConstants.PREF_NAVIGATION_END_ACTION_LOCAL, next);
4368
				performEndOfDocumentAction(shell, store,
4369
						ICompareUIConstants.PREF_NAVIGATION_END_ACTION_LOCAL,
4370
						next);
4028
				if (dialog.getToggleState()) {
4371
				if (dialog.getToggleState()) {
4029
					store.putValue(ICompareUIConstants.PREF_NAVIGATION_END_ACTION, store.getString(ICompareUIConstants.PREF_NAVIGATION_END_ACTION_LOCAL));
4372
					store
4373
							.putValue(
4374
									ICompareUIConstants.PREF_NAVIGATION_END_ACTION,
4375
									store
4376
											.getString(ICompareUIConstants.PREF_NAVIGATION_END_ACTION_LOCAL));
4030
				}
4377
				}
4031
			}
4378
			}
4032
		} else {
4379
		} else {
Lines 4044-4054 Link Here
4044
			}
4391
			}
4045
		}
4392
		}
4046
	}
4393
	}
4047
	
4394
4048
	private void performEndOfDocumentAction(Shell shell, IPreferenceStore store, String key, boolean next) {
4395
	private void performEndOfDocumentAction(Shell shell,
4396
			IPreferenceStore store, String key, boolean next) {
4049
		String value = store.getString(key);
4397
		String value = store.getString(key);
4050
		if (value.equals(ICompareUIConstants.PREF_VALUE_NEXT)) {
4398
		if (value.equals(ICompareUIConstants.PREF_VALUE_NEXT)) {
4051
			ICompareNavigator navigator = getCompareConfiguration().getContainer().getNavigator();
4399
			ICompareNavigator navigator = getCompareConfiguration()
4400
					.getContainer().getNavigator();
4052
			if (hasNextElement(next))
4401
			if (hasNextElement(next))
4053
				navigator.selectChange(next);
4402
				navigator.selectChange(next);
4054
			else
4403
			else
Lines 4057-4065 Link Here
4057
			selectFirstDiff(next);
4406
			selectFirstDiff(next);
4058
		}
4407
		}
4059
	}
4408
	}
4060
	
4409
4061
	private boolean hasNextElement(boolean down) {
4410
	private boolean hasNextElement(boolean down) {
4062
		ICompareNavigator navigator = getCompareConfiguration().getContainer().getNavigator();
4411
		ICompareNavigator navigator = getCompareConfiguration().getContainer()
4412
				.getNavigator();
4063
		if (navigator instanceof CompareNavigator) {
4413
		if (navigator instanceof CompareNavigator) {
4064
			CompareNavigator n = (CompareNavigator) navigator;
4414
			CompareNavigator n = (CompareNavigator) navigator;
4065
			return n.hasChange(down);
4415
			return n.hasChange(down);
Lines 4068-4227 Link Here
4068
	}
4418
	}
4069
4419
4070
	/*
4420
	/*
4071
	 * Find the Diff that overlaps with the given TextPart's text range.
4421
	 * Find the Diff that overlaps with the given TextPart's text range. If the
4072
	 * If the range doesn't overlap with any range <code>null</code>
4422
	 * range doesn't overlap with any range <code>null</code> is returned.
4073
	 * is returned.
4074
	 */
4423
	 */
4075
	private Diff findDiff(MergeSourceViewer tp, int rangeStart, int rangeEnd) {
4424
	private Diff findDiff(MergeSourceViewer tp, int rangeStart, int rangeEnd) {
4076
		char contributor = getLeg(tp);
4425
		char contributor = getLeg(tp);
4077
		return fMerger.findDiff(contributor, rangeStart, rangeEnd);
4426
		return fMerger.findDiff(contributor, rangeStart, rangeEnd);
4078
	}
4427
	}
4079
	
4428
4080
	private Diff findNext(MergeSourceViewer tp, int start, int end, boolean deep) {
4429
	private Diff findNext(MergeSourceViewer tp, int start, int end, boolean deep) {
4081
		return fMerger.findNext(getLeg(tp), start, end, deep);
4430
		return fMerger.findNext(getLeg(tp), start, end, deep);
4082
	}
4431
	}
4083
	
4432
4084
	private Diff findPrev(MergeSourceViewer tp, int start, int end, boolean deep) {
4433
	private Diff findPrev(MergeSourceViewer tp, int start, int end, boolean deep) {
4085
		return fMerger.findPrev(getLeg(tp), start, end, deep);
4434
		return fMerger.findPrev(getLeg(tp), start, end, deep);
4086
	}
4435
	}
4087
4436
4088
	/*
4437
	/*
4089
	 * Set the currently active Diff and update the toolbars controls and lines.
4438
	 * Set the currently active Diff and update the toolbars controls and lines.
4090
	 * If <code>revealAndSelect</code> is <code>true</code> the Diff is revealed and
4439
	 * If <code>revealAndSelect</code> is <code>true</code> the Diff is revealed
4091
	 * selected in both TextParts.
4440
	 * and selected in both TextParts.
4092
	 */
4441
	 */
4093
	private void setCurrentDiff(Diff d, boolean revealAndSelect) {
4442
	private void setCurrentDiff(Diff d, boolean revealAndSelect) {
4094
		setCurrentDiff(d, revealAndSelect, false);
4443
		setCurrentDiff(d, revealAndSelect, false);
4095
	}
4444
	}
4096
		
4445
4097
	/*
4446
	/*
4098
	 * Set the currently active Diff and update the toolbars controls and lines.
4447
	 * Set the currently active Diff and update the toolbars controls and lines.
4099
	 * If <code>revealAndSelect</code> is <code>true</code> the Diff is revealed and
4448
	 * If <code>revealAndSelect</code> is <code>true</code> the Diff is revealed
4100
	 * selected in both TextParts.
4449
	 * and selected in both TextParts.
4101
	 */
4450
	 */
4102
	private void setCurrentDiff(Diff d, boolean revealAndSelect, boolean deep) {
4451
	private void setCurrentDiff(Diff d, boolean revealAndSelect, boolean deep) {
4103
4452
4104
//		if (d == fCurrentDiff)
4453
		// if (d == fCurrentDiff)
4105
//			return;
4454
		// return;
4106
4455
4107
		if (fCenterButton != null && !fCenterButton.isDisposed())
4456
		if (fCenterButton != null && !fCenterButton.isDisposed())
4108
			fCenterButton.setVisible(false);
4457
			fCenterButton.setVisible(false);
4109
4458
4110
		Diff oldDiff= fCurrentDiff;
4459
		Diff oldDiff = fCurrentDiff;
4111
					
4460
4112
		if (d != null && revealAndSelect) {
4461
		if (d != null && revealAndSelect) {
4113
			
4462
4114
			// before we set fCurrentDiff we change the selection
4463
			// before we set fCurrentDiff we change the selection
4115
			// so that the paint code uses the old background colors
4464
			// so that the paint code uses the old background colors
4116
			// otherwise selection isn't drawn correctly
4465
			// otherwise selection isn't drawn correctly
4117
			if (d.isToken() || !fHighlightTokenChanges || deep || !d.hasChildren()) {
4466
			if (d.isToken() || !fHighlightTokenChanges || deep
4467
					|| !d.hasChildren()) {
4118
				if (isThreeWay() && !isIgnoreAncestor())
4468
				if (isThreeWay() && !isIgnoreAncestor())
4119
					fAncestor.setSelection(d.getPosition(ANCESTOR_CONTRIBUTOR));
4469
					fAncestor.setSelection(d.getPosition(ANCESTOR_CONTRIBUTOR));
4120
				fLeft.setSelection(d.getPosition(LEFT_CONTRIBUTOR));
4470
				fLeft.setSelection(d.getPosition(LEFT_CONTRIBUTOR));
4121
				fRight.setSelection(d.getPosition(RIGHT_CONTRIBUTOR));
4471
				fRight.setSelection(d.getPosition(RIGHT_CONTRIBUTOR));
4122
			} else {
4472
			} else {
4123
				if (isThreeWay() && !isIgnoreAncestor())
4473
				if (isThreeWay() && !isIgnoreAncestor())
4124
					fAncestor.setSelection(new Position(d.getPosition(ANCESTOR_CONTRIBUTOR).offset, 0));
4474
					fAncestor.setSelection(new Position(d
4125
				fLeft.setSelection(new Position(d.getPosition(LEFT_CONTRIBUTOR).offset, 0));
4475
							.getPosition(ANCESTOR_CONTRIBUTOR).offset, 0));
4126
				fRight.setSelection(new Position(d.getPosition(RIGHT_CONTRIBUTOR).offset, 0));
4476
				fLeft.setSelection(new Position(
4477
						d.getPosition(LEFT_CONTRIBUTOR).offset, 0));
4478
				fRight.setSelection(new Position(d
4479
						.getPosition(RIGHT_CONTRIBUTOR).offset, 0));
4127
			}
4480
			}
4128
			
4481
4129
			// now switch diffs
4482
			// now switch diffs
4130
			fCurrentDiff= d;
4483
			fCurrentDiff = d;
4131
			revealDiff(d, d.isToken());
4484
			revealDiff(d, d.isToken());
4132
		} else {
4485
		} else {
4133
			fCurrentDiff= d;
4486
			fCurrentDiff = d;
4134
		}
4487
		}
4135
		
4488
4136
		Diff d1= oldDiff != null ? oldDiff.getParent() : null;
4489
		Diff d1 = oldDiff != null ? oldDiff.getParent() : null;
4137
		Diff d2= fCurrentDiff != null ? fCurrentDiff.getParent() : null;
4490
		Diff d2 = fCurrentDiff != null ? fCurrentDiff.getParent() : null;
4138
		if (d1 != d2) {
4491
		if (d1 != d2) {
4139
			updateDiffBackground(d1);
4492
			updateDiffBackground(d1);
4140
			updateDiffBackground(d2);
4493
			updateDiffBackground(d2);
4141
		}
4494
		}
4142
		
4495
4143
		updateControls();
4496
		updateControls();
4144
		invalidateLines();
4497
		invalidateLines();
4145
		refreshBirdsEyeView();
4498
		refreshBirdsEyeView();
4146
	}
4499
	}
4147
	
4500
4148
	/*
4501
	/*
4149
	 * Smart determines whether
4502
	 * Smart determines whether
4150
	 */
4503
	 */
4151
	private void revealDiff(Diff d, boolean smart) {
4504
	private void revealDiff(Diff d, boolean smart) {
4152
		
4505
4153
		boolean ancestorIsVisible= false;
4506
		boolean ancestorIsVisible = false;
4154
		boolean leftIsVisible= false;
4507
		boolean leftIsVisible = false;
4155
		boolean rightIsVisible= false;
4508
		boolean rightIsVisible = false;
4156
4509
4157
		if (smart) {
4510
		if (smart) {
4158
			Point region= new Point(0, 0);
4511
			Point region = new Point(0, 0);
4159
			// find the starting line of the diff in all text widgets
4512
			// find the starting line of the diff in all text widgets
4160
			int ls= fLeft.getLineRange(d.getPosition(LEFT_CONTRIBUTOR), region).x;
4513
			int ls = fLeft
4161
			int rs= fRight.getLineRange(d.getPosition(RIGHT_CONTRIBUTOR), region).x;
4514
					.getLineRange(d.getPosition(LEFT_CONTRIBUTOR), region).x;
4162
			
4515
			int rs = fRight.getLineRange(d.getPosition(RIGHT_CONTRIBUTOR),
4516
					region).x;
4517
4163
			if (isThreeWay() && !isIgnoreAncestor()) {
4518
			if (isThreeWay() && !isIgnoreAncestor()) {
4164
				int as= fAncestor.getLineRange(d.getPosition(ANCESTOR_CONTRIBUTOR), region).x;
4519
				int as = fAncestor.getLineRange(d
4165
				if (as >= fAncestor.getTopIndex() && as <= fAncestor.getBottomIndex())
4520
						.getPosition(ANCESTOR_CONTRIBUTOR), region).x;
4166
					ancestorIsVisible= true;
4521
				if (as >= fAncestor.getTopIndex()
4522
						&& as <= fAncestor.getBottomIndex())
4523
					ancestorIsVisible = true;
4167
			}
4524
			}
4168
4525
4169
			if (ls >= fLeft.getTopIndex() && ls <= fLeft.getBottomIndex())
4526
			if (ls >= fLeft.getTopIndex() && ls <= fLeft.getBottomIndex())
4170
				leftIsVisible= true;
4527
				leftIsVisible = true;
4171
4528
4172
			if (rs >= fRight.getTopIndex() && rs <= fRight.getBottomIndex())
4529
			if (rs >= fRight.getTopIndex() && rs <= fRight.getBottomIndex())
4173
				rightIsVisible= true;
4530
				rightIsVisible = true;
4174
		}
4531
		}
4175
4532
4176
		// vertical scrolling
4533
		// vertical scrolling
4177
		if (!leftIsVisible || !rightIsVisible) {
4534
		if (!leftIsVisible || !rightIsVisible) {
4178
			int avpos= 0, lvpos= 0, rvpos= 0;
4535
			int avpos = 0, lvpos = 0, rvpos = 0;
4179
			
4536
4180
			MergeSourceViewer allButThis= null;
4537
			MergeSourceViewer allButThis = null;
4181
			if (leftIsVisible) {
4538
			if (leftIsVisible) {
4182
				avpos= lvpos= rvpos= realToVirtualPosition(LEFT_CONTRIBUTOR, fLeft.getTopIndex());
4539
				avpos = lvpos = rvpos = realToVirtualPosition(LEFT_CONTRIBUTOR,
4183
				allButThis= fLeft;
4540
						fLeft.getTopIndex());
4541
				allButThis = fLeft;
4184
			} else if (rightIsVisible) {
4542
			} else if (rightIsVisible) {
4185
				avpos= lvpos= rvpos= realToVirtualPosition(RIGHT_CONTRIBUTOR, fRight.getTopIndex());
4543
				avpos = lvpos = rvpos = realToVirtualPosition(
4186
				allButThis= fRight;
4544
						RIGHT_CONTRIBUTOR, fRight.getTopIndex());
4545
				allButThis = fRight;
4187
			} else if (ancestorIsVisible) {
4546
			} else if (ancestorIsVisible) {
4188
				avpos= lvpos= rvpos= realToVirtualPosition(ANCESTOR_CONTRIBUTOR, fAncestor.getTopIndex());
4547
				avpos = lvpos = rvpos = realToVirtualPosition(
4189
				allButThis= fAncestor;
4548
						ANCESTOR_CONTRIBUTOR, fAncestor.getTopIndex());
4549
				allButThis = fAncestor;
4190
			} else {
4550
			} else {
4191
				int vpos= 0;
4551
				int vpos = 0;
4192
				for (Iterator iterator = fMerger.rangesIterator(); iterator
4552
				for (Iterator iterator = fMerger.rangesIterator(); iterator
4193
						.hasNext();) {
4553
						.hasNext();) {
4194
					Diff diff = (Diff) iterator.next();
4554
					Diff diff = (Diff) iterator.next();
4195
					if (diff == d)
4555
					if (diff == d)
4196
						break;
4556
						break;
4197
					if (fSynchronizedScrolling) {
4557
					if (fSynchronizedScrolling) {
4198
						vpos+= diff.getMaxDiffHeight();
4558
						vpos += diff.getMaxDiffHeight();
4199
					} else {
4559
					} else {
4200
						avpos+= diff.getAncestorHeight();
4560
						avpos += diff.getAncestorHeight();
4201
						lvpos+= diff.getLeftHeight();
4561
						lvpos += diff.getLeftHeight();
4202
						rvpos+= diff.getRightHeight();
4562
						rvpos += diff.getRightHeight();
4203
					}
4563
					}
4204
				}
4564
				}
4205
				if (fSynchronizedScrolling)
4565
				if (fSynchronizedScrolling)
4206
					avpos= lvpos= rvpos= vpos;
4566
					avpos = lvpos = rvpos = vpos;
4207
				int delta= fRight.getViewportLines()/4;
4567
				int delta = fRight.getViewportLines() / 4;
4208
				avpos-= delta;
4568
				avpos -= delta;
4209
				if (avpos < 0)
4569
				if (avpos < 0)
4210
					avpos= 0;
4570
					avpos = 0;
4211
				lvpos-= delta;
4571
				lvpos -= delta;
4212
				if (lvpos < 0)
4572
				if (lvpos < 0)
4213
					lvpos= 0;
4573
					lvpos = 0;
4214
				rvpos-= delta;
4574
				rvpos -= delta;
4215
				if (rvpos < 0)
4575
				if (rvpos < 0)
4216
					rvpos= 0;
4576
					rvpos = 0;
4217
			}
4577
			}
4218
							
4578
4219
			scrollVertical(avpos, lvpos, rvpos, allButThis);
4579
			scrollVertical(avpos, lvpos, rvpos, allButThis);
4220
			
4580
4221
			if (fVScrollBar != null)
4581
			if (fVScrollBar != null)
4222
				fVScrollBar.setSelection(avpos);
4582
				fVScrollBar.setSelection(avpos);
4223
		}
4583
		}
4224
		
4584
4225
		// horizontal scrolling
4585
		// horizontal scrolling
4226
		if (d.isToken()) {
4586
		if (d.isToken()) {
4227
			// we only scroll horizontally for token diffs
4587
			// we only scroll horizontally for token diffs
Lines 4235-4275 Link Here
4235
			hscroll(fRight);
4595
			hscroll(fRight);
4236
		}
4596
		}
4237
	}
4597
	}
4238
	
4598
4239
	private static void reveal(MergeSourceViewer v, Position p) {
4599
	private static void reveal(MergeSourceViewer v, Position p) {
4240
		if (v != null && p != null) {
4600
		if (v != null && p != null) {
4241
			StyledText st= v.getTextWidget();
4601
			StyledText st = v.getTextWidget();
4242
			if (st != null) {
4602
			if (st != null) {
4243
				Rectangle r= st.getClientArea();
4603
				Rectangle r = st.getClientArea();
4244
				if (!r.isEmpty())	// workaround for #7320: Next diff scrolls when going into current diff
4604
				if (!r.isEmpty()) // workaround for #7320: Next diff scrolls
4605
									// when going into current diff
4245
					v.revealRange(p.offset, p.length);
4606
					v.revealRange(p.offset, p.length);
4246
			}
4607
			}
4247
		}
4608
		}
4248
	}
4609
	}
4249
	
4610
4250
	private static void hscroll(MergeSourceViewer v) {
4611
	private static void hscroll(MergeSourceViewer v) {
4251
		if (v != null) {
4612
		if (v != null) {
4252
			StyledText st= v.getTextWidget();
4613
			StyledText st = v.getTextWidget();
4253
			if (st != null)
4614
			if (st != null)
4254
				st.setHorizontalIndex(0);
4615
				st.setHorizontalIndex(0);
4255
		}
4616
		}
4256
	}
4617
	}
4257
	
4618
4258
	//--------------------------------------------------------------------------------
4619
	// --------------------------------------------------------------------------------
4259
	
4620
4260
	void copyAllUnresolved(boolean leftToRight) {
4621
	void copyAllUnresolved(boolean leftToRight) {
4261
		if (fMerger.hasChanges() && isThreeWay() && !isIgnoreAncestor()) {
4622
		if (fMerger.hasChanges() && isThreeWay() && !isIgnoreAncestor()) {
4262
			IRewriteTarget target= leftToRight ? fRight.getRewriteTarget() : fLeft.getRewriteTarget();
4623
			IRewriteTarget target = leftToRight ? fRight.getRewriteTarget()
4263
			boolean compoundChangeStarted= false;
4624
					: fLeft.getRewriteTarget();
4625
			boolean compoundChangeStarted = false;
4264
			try {
4626
			try {
4265
				for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) {
4627
				for (Iterator iterator = fMerger.changesIterator(); iterator
4628
						.hasNext();) {
4266
					Diff diff = (Diff) iterator.next();
4629
					Diff diff = (Diff) iterator.next();
4267
					switch (diff.getKind()) {
4630
					switch (diff.getKind()) {
4268
					case RangeDifference.LEFT:
4631
					case RangeDifference.LEFT:
4269
						if (leftToRight) {
4632
						if (leftToRight) {
4270
							if (!compoundChangeStarted) {
4633
							if (!compoundChangeStarted) {
4271
								target.beginCompoundChange();
4634
								target.beginCompoundChange();
4272
								compoundChangeStarted= true;
4635
								compoundChangeStarted = true;
4273
							}
4636
							}
4274
							copy(diff, leftToRight);
4637
							copy(diff, leftToRight);
4275
						}
4638
						}
Lines 4278-4284 Link Here
4278
						if (!leftToRight) {
4641
						if (!leftToRight) {
4279
							if (!compoundChangeStarted) {
4642
							if (!compoundChangeStarted) {
4280
								target.beginCompoundChange();
4643
								target.beginCompoundChange();
4281
								compoundChangeStarted= true;
4644
								compoundChangeStarted = true;
4282
							}
4645
							}
4283
							copy(diff, leftToRight);
4646
							copy(diff, leftToRight);
4284
						}
4647
						}
Lines 4294-4300 Link Here
4294
			}
4657
			}
4295
		}
4658
		}
4296
	}
4659
	}
4297
	
4660
4298
	/*
4661
	/*
4299
	 * Copy whole document from one side to the other.
4662
	 * Copy whole document from one side to the other.
4300
	 */
4663
	 */
Lines 4306-4316 Link Here
4306
			invalidateLines();
4669
			invalidateLines();
4307
			return;
4670
			return;
4308
		}
4671
		}
4309
				
4672
4310
		if (leftToRight) {
4673
		if (leftToRight) {
4311
			if (fLeft.getEnabled()) {
4674
			if (fLeft.getEnabled()) {
4312
				// copy text
4675
				// copy text
4313
				String text= fLeft.getTextWidget().getText();
4676
				String text = fLeft.getTextWidget().getText();
4314
				fRight.getTextWidget().setText(text);
4677
				fRight.getTextWidget().setText(text);
4315
				fRight.setEnabled(true);
4678
				fRight.setEnabled(true);
4316
			} else {
4679
			} else {
Lines 4318-4329 Link Here
4318
				fRight.getTextWidget().setText(""); //$NON-NLS-1$
4681
				fRight.getTextWidget().setText(""); //$NON-NLS-1$
4319
				fRight.setEnabled(false);
4682
				fRight.setEnabled(false);
4320
			}
4683
			}
4321
			fRightLineCount= fRight.getLineCount();
4684
			fRightLineCount = fRight.getLineCount();
4322
			setRightDirty(true);
4685
			setRightDirty(true);
4323
		} else {
4686
		} else {
4324
			if (fRight.getEnabled()) {
4687
			if (fRight.getEnabled()) {
4325
				// copy text
4688
				// copy text
4326
				String text= fRight.getTextWidget().getText();
4689
				String text = fRight.getTextWidget().getText();
4327
				fLeft.getTextWidget().setText(text);
4690
				fLeft.getTextWidget().setText(text);
4328
				fLeft.setEnabled(true);
4691
				fLeft.setEnabled(true);
4329
			} else {
4692
			} else {
Lines 4331-4337 Link Here
4331
				fLeft.getTextWidget().setText(""); //$NON-NLS-1$
4694
				fLeft.getTextWidget().setText(""); //$NON-NLS-1$
4332
				fLeft.setEnabled(false);
4695
				fLeft.setEnabled(false);
4333
			}
4696
			}
4334
			fLeftLineCount= fLeft.getLineCount();
4697
			fLeftLineCount = fLeft.getLineCount();
4335
			setLeftDirty(true);
4698
			setLeftDirty(true);
4336
		}
4699
		}
4337
		update(false);
4700
		update(false);
Lines 4345-4351 Link Here
4345
	private void copyDiffRightToLeft() {
4708
	private void copyDiffRightToLeft() {
4346
		copy(fCurrentDiff, false, false);
4709
		copy(fCurrentDiff, false, false);
4347
	}
4710
	}
4348
		
4711
4349
	/*
4712
	/*
4350
	 * Copy the contents of the given diff from one side to the other.
4713
	 * Copy the contents of the given diff from one side to the other.
4351
	 */
4714
	 */
Lines 4362-4372 Link Here
4362
4725
4363
	/*
4726
	/*
4364
	 * Copy the contents of the given diff from one side to the other but
4727
	 * Copy the contents of the given diff from one side to the other but
4365
	 * doesn't reveal anything.
4728
	 * doesn't reveal anything. Returns true if copy was successful.
4366
	 * Returns true if copy was successful.
4367
	 */
4729
	 */
4368
	private boolean copy(Diff diff, boolean leftToRight) {
4730
	private boolean copy(Diff diff, boolean leftToRight) {
4369
		
4731
4370
		if (diff != null && !diff.isResolved()) {
4732
		if (diff != null && !diff.isResolved()) {
4371
			if (!validateChange(!leftToRight))
4733
			if (!validateChange(!leftToRight))
4372
				return false;
4734
				return false;
Lines 4389-4559 Link Here
4389
			info = fLeftContributor;
4751
			info = fLeftContributor;
4390
		else
4752
		else
4391
			info = fRightContributor;
4753
			info = fRightContributor;
4392
		
4754
4393
		return info.validateChange();
4755
		return info.validateChange();
4394
	}
4756
	}
4395
4757
4396
	//---- scrolling
4758
	// ---- scrolling
4397
	
4759
4398
	/*
4760
	/*
4399
	 * The height of the TextEditors in lines.
4761
	 * The height of the TextEditors in lines.
4400
	 */
4762
	 */
4401
	private int getViewportHeight() {
4763
	private int getViewportHeight() {
4402
		StyledText te= fLeft.getTextWidget();
4764
		StyledText te = fLeft.getTextWidget();
4403
		
4765
4404
		int vh= te.getClientArea().height;
4766
		int vh = te.getClientArea().height;
4405
		if (vh == 0) {
4767
		if (vh == 0) {
4406
			Rectangle trim= te.computeTrim(0, 0, 0, 0);
4768
			Rectangle trim = te.computeTrim(0, 0, 0, 0);
4407
			int scrollbarHeight= trim.height;
4769
			int scrollbarHeight = trim.height;
4408
			
4770
4409
			int headerHeight= getHeaderHeight();
4771
			int headerHeight = getHeaderHeight();
4410
	
4772
4411
			Composite composite= (Composite) getControl();
4773
			Composite composite = (Composite) getControl();
4412
			Rectangle r= composite.getClientArea();
4774
			Rectangle r = composite.getClientArea();
4413
							
4775
4414
			vh= r.height-headerHeight-scrollbarHeight;
4776
			vh = r.height - headerHeight - scrollbarHeight;
4415
		}
4777
		}
4416
4778
4417
		return vh / te.getLineHeight();
4779
		return vh / te.getLineHeight();
4418
	}
4780
	}
4419
	
4781
4420
	/*
4782
	/*
4421
	 * Returns the virtual position for the given view position.
4783
	 * Returns the virtual position for the given view position.
4422
	 */
4784
	 */
4423
	private int realToVirtualPosition(char contributor, int vpos) {
4785
	private int realToVirtualPosition(char contributor, int vpos) {
4424
		if (! fSynchronizedScrolling)
4786
		if (!fSynchronizedScrolling)
4425
			return vpos;
4787
			return vpos;
4426
		return fMerger.realToVirtualPosition(contributor, vpos);
4788
		return fMerger.realToVirtualPosition(contributor, vpos);
4427
	}
4789
	}
4428
		
4790
4429
	private void scrollVertical(int avpos, int lvpos, int rvpos, MergeSourceViewer allBut) {
4791
	private void scrollVertical(int avpos, int lvpos, int rvpos,
4430
						
4792
			MergeSourceViewer allBut) {
4431
		int s= 0;
4793
4432
		
4794
		int s = 0;
4795
4433
		if (fSynchronizedScrolling) {
4796
		if (fSynchronizedScrolling) {
4434
			s= fMerger.getVirtualHeight() - rvpos;
4797
			s = fMerger.getVirtualHeight() - rvpos;
4435
			int height= fRight.getViewportLines()/4;
4798
			int height = fRight.getViewportLines() / 4;
4436
			if (s < 0)
4799
			if (s < 0)
4437
				s= 0;
4800
				s = 0;
4438
			if (s > height)
4801
			if (s > height)
4439
				s= height;
4802
				s = height;
4440
		}
4803
		}
4441
4804
4442
		fInScrolling= true;
4805
		fInScrolling = true;
4443
				
4806
4444
		if (isThreeWay() && allBut != fAncestor) {
4807
		if (isThreeWay() && allBut != fAncestor) {
4445
			if (fSynchronizedScrolling || allBut == null) {
4808
			if (fSynchronizedScrolling || allBut == null) {
4446
				int y= virtualToRealPosition(ANCESTOR_CONTRIBUTOR, avpos+s)-s;
4809
				int y = virtualToRealPosition(ANCESTOR_CONTRIBUTOR, avpos + s)
4810
						- s;
4447
				fAncestor.vscroll(y);
4811
				fAncestor.vscroll(y);
4448
			}
4812
			}
4449
		}
4813
		}
4450
4814
4451
		if (allBut != fLeft) {
4815
		if (allBut != fLeft) {
4452
			if (fSynchronizedScrolling || allBut == null) {
4816
			if (fSynchronizedScrolling || allBut == null) {
4453
				int y= virtualToRealPosition(LEFT_CONTRIBUTOR, lvpos+s)-s;
4817
				int y = virtualToRealPosition(LEFT_CONTRIBUTOR, lvpos + s) - s;
4454
				fLeft.vscroll(y);
4818
				fLeft.vscroll(y);
4455
			}
4819
			}
4456
		}
4820
		}
4457
4821
4458
		if (allBut != fRight) {
4822
		if (allBut != fRight) {
4459
			if (fSynchronizedScrolling || allBut == null) {
4823
			if (fSynchronizedScrolling || allBut == null) {
4460
				int y= virtualToRealPosition(RIGHT_CONTRIBUTOR, rvpos+s)-s;
4824
				int y = virtualToRealPosition(RIGHT_CONTRIBUTOR, rvpos + s) - s;
4461
				fRight.vscroll(y);
4825
				fRight.vscroll(y);
4462
			}
4826
			}
4463
		}
4827
		}
4464
		
4828
4465
		fInScrolling= false;
4829
		fInScrolling = false;
4466
		
4830
4467
		if (isThreeWay() && fAncestorCanvas != null)
4831
		if (isThreeWay() && fAncestorCanvas != null)
4468
			fAncestorCanvas.repaint();
4832
			fAncestorCanvas.repaint();
4469
		
4833
4470
		if (fLeftCanvas != null)
4834
		if (fLeftCanvas != null)
4471
			fLeftCanvas.repaint();
4835
			fLeftCanvas.repaint();
4472
		
4836
4473
		Control center= getCenterControl();
4837
		Control center = getCenterControl();
4474
		if (center instanceof BufferedCanvas)
4838
		if (center instanceof BufferedCanvas)
4475
			((BufferedCanvas)center).repaint();
4839
			((BufferedCanvas) center).repaint();
4476
		
4840
4477
		if (fRightCanvas != null)
4841
		if (fRightCanvas != null)
4478
			fRightCanvas.repaint();
4842
			fRightCanvas.repaint();
4479
	}
4843
	}
4480
		
4844
4481
	/*
4845
	/*
4482
	 * Updates Scrollbars with viewports.
4846
	 * Updates Scrollbars with viewports.
4483
	 */
4847
	 */
4484
	private void syncViewport(MergeSourceViewer w) {
4848
	private void syncViewport(MergeSourceViewer w) {
4485
		
4849
4486
		if (fInScrolling)
4850
		if (fInScrolling)
4487
			return;
4851
			return;
4488
4852
4489
		int ix= w.getTopIndex();
4853
		int ix = w.getTopIndex();
4490
		int ix2= w.getDocumentRegionOffset();
4854
		int ix2 = w.getDocumentRegionOffset();
4491
		
4855
4492
		int viewPosition= realToVirtualPosition(getLeg(w), ix-ix2);
4856
		int viewPosition = realToVirtualPosition(getLeg(w), ix - ix2);
4493
				
4857
4494
		scrollVertical(viewPosition, viewPosition, viewPosition, w);	// scroll all but the given views
4858
		scrollVertical(viewPosition, viewPosition, viewPosition, w); // scroll
4495
		
4859
																		// all
4860
																		// but
4861
																		// the
4862
																		// given
4863
																		// views
4864
4496
		if (fVScrollBar != null) {
4865
		if (fVScrollBar != null) {
4497
			int value= Math.max(0, Math.min(viewPosition, fMerger.getVirtualHeight() - getViewportHeight()));
4866
			int value = Math.max(0, Math.min(viewPosition, fMerger
4867
					.getVirtualHeight()
4868
					- getViewportHeight()));
4498
			fVScrollBar.setSelection(value);
4869
			fVScrollBar.setSelection(value);
4499
			//refreshBirdEyeView();
4870
			// refreshBirdEyeView();
4500
		}
4871
		}
4501
	}
4872
	}
4502
4873
4503
	/**
4874
	/**
4504
	 */
4875
	 */
4505
	private void updateVScrollBar() {
4876
	private void updateVScrollBar() {
4506
		
4877
4507
		if (Utilities.okToUse(fVScrollBar) && fSynchronizedScrolling) {
4878
		if (Utilities.okToUse(fVScrollBar) && fSynchronizedScrolling) {
4508
			int virtualHeight= fMerger.getVirtualHeight();
4879
			int virtualHeight = fMerger.getVirtualHeight();
4509
			int viewPortHeight= getViewportHeight();
4880
			int viewPortHeight = getViewportHeight();
4510
			int pageIncrement= viewPortHeight-1;
4881
			int pageIncrement = viewPortHeight - 1;
4511
			int thumb= (viewPortHeight > virtualHeight) ? virtualHeight : viewPortHeight;
4882
			int thumb = (viewPortHeight > virtualHeight) ? virtualHeight
4512
						
4883
					: viewPortHeight;
4884
4513
			fVScrollBar.setPageIncrement(pageIncrement);
4885
			fVScrollBar.setPageIncrement(pageIncrement);
4514
			fVScrollBar.setMaximum(virtualHeight);
4886
			fVScrollBar.setMaximum(virtualHeight);
4515
			fVScrollBar.setThumb(thumb);
4887
			fVScrollBar.setThumb(thumb);
4516
		}
4888
		}
4517
	}
4889
	}
4518
	
4890
4519
	/*
4891
	/*
4520
	 * maps given virtual position into a real view position of this view.
4892
	 * maps given virtual position into a real view position of this view.
4521
	 */
4893
	 */
4522
	private int virtualToRealPosition(char contributor, int v) {
4894
	private int virtualToRealPosition(char contributor, int v) {
4523
		if (! fSynchronizedScrolling)
4895
		if (!fSynchronizedScrolling)
4524
			return v;
4896
			return v;
4525
		return fMerger.virtualToRealPosition(contributor, v);
4897
		return fMerger.virtualToRealPosition(contributor, v);
4526
	}
4898
	}
4527
	
4899
4528
	/* (non-Javadoc)
4900
	/*
4529
	 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#flushContent(java.lang.Object, org.eclipse.core.runtime.IProgressMonitor)
4901
	 * (non-Javadoc)
4902
	 * 
4903
	 * @see
4904
	 * org.eclipse.compare.contentmergeviewer.ContentMergeViewer#flushContent
4905
	 * (java.lang.Object, org.eclipse.core.runtime.IProgressMonitor)
4530
	 */
4906
	 */
4531
	protected void flushContent(Object oldInput, IProgressMonitor monitor) {
4907
	protected void flushContent(Object oldInput, IProgressMonitor monitor) {
4532
				
4908
4533
		// check and handle any shared buffers
4909
		// check and handle any shared buffers
4534
		IMergeViewerContentProvider content= getMergeContentProvider();
4910
		IMergeViewerContentProvider content = getMergeContentProvider();
4535
		Object leftContent = content.getLeftContent(oldInput);
4911
		Object leftContent = content.getLeftContent(oldInput);
4536
		Object rightContent = content.getRightContent(oldInput);
4912
		Object rightContent = content.getRightContent(oldInput);
4537
		
4913
4538
		if (leftContent != null && getCompareConfiguration().isLeftEditable() && isLeftDirty()) {
4914
		if (leftContent != null && getCompareConfiguration().isLeftEditable()
4915
				&& isLeftDirty()) {
4539
			if (fLeftContributor.hasSharedDocument(leftContent)) {
4916
			if (fLeftContributor.hasSharedDocument(leftContent)) {
4540
				if (flush(fLeftContributor))
4917
				if (flush(fLeftContributor))
4541
					setLeftDirty(false);
4918
					setLeftDirty(false);
4542
			}
4919
			}
4543
		}
4920
		}
4544
		
4921
4545
		if (rightContent != null && getCompareConfiguration().isRightEditable() && isRightDirty()) {
4922
		if (rightContent != null && getCompareConfiguration().isRightEditable()
4923
				&& isRightDirty()) {
4546
			if (fRightContributor.hasSharedDocument(rightContent)) {
4924
			if (fRightContributor.hasSharedDocument(rightContent)) {
4547
				if (flush(fRightContributor))
4925
				if (flush(fRightContributor))
4548
					setRightDirty(false);
4926
					setRightDirty(false);
4549
			}
4927
			}
4550
		}
4928
		}
4551
		
4929
4552
		if (!(content instanceof MergeViewerContentProvider) || isLeftDirty() || isRightDirty()) {
4930
		if (!(content instanceof MergeViewerContentProvider) || isLeftDirty()
4931
				|| isRightDirty()) {
4553
			super.flushContent(oldInput, monitor);
4932
			super.flushContent(oldInput, monitor);
4554
		}
4933
		}
4555
	}
4934
	}
4556
	
4935
4557
	private boolean flush(final ContributorInfo info) {
4936
	private boolean flush(final ContributorInfo info) {
4558
		try {
4937
		try {
4559
			return info.flush();
4938
			return info.flush();
Lines 4573-4579 Link Here
4573
		CompareUIPlugin.log(throwable);
4952
		CompareUIPlugin.log(throwable);
4574
	}
4953
	}
4575
4954
4576
	/* (non-Javadoc)
4955
	/*
4956
	 * (non-Javadoc)
4957
	 * 
4577
	 * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
4958
	 * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
4578
	 */
4959
	 */
4579
	public Object getAdapter(Class adapter) {
4960
	public Object getAdapter(Class adapter) {
Lines 4604-4612 Link Here
4604
			return fHandlerService;
4985
			return fHandlerService;
4605
		return null;
4986
		return null;
4606
	}
4987
	}
4607
	
4988
4608
	/* (non-Javadoc)
4989
	/*
4609
	 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#handleCompareInputChange()
4990
	 * (non-Javadoc)
4991
	 * 
4992
	 * @seeorg.eclipse.compare.contentmergeviewer.ContentMergeViewer#
4993
	 * handleCompareInputChange()
4610
	 */
4994
	 */
4611
	protected void handleCompareInputChange() {
4995
	protected void handleCompareInputChange() {
4612
		try {
4996
		try {
Lines 4625-4633 Link Here
4625
		if (fSynchronizedScrolling) {
5009
		if (fSynchronizedScrolling) {
4626
			fSynchronziedScrollPosition = fVScrollBar.getSelection();
5010
			fSynchronziedScrollPosition = fVScrollBar.getSelection();
4627
		}
5011
		}
4628
		
5012
4629
	}
5013
	}
4630
	
5014
4631
	private void endRefresh() {
5015
	private void endRefresh() {
4632
		isRefreshing = false;
5016
		isRefreshing = false;
4633
		fLeftContributor.cacheSelection(null);
5017
		fLeftContributor.cacheSelection(null);
Lines 4640-4651 Link Here
4640
		scrollVertical(vpos, vpos, vpos, null);
5024
		scrollVertical(vpos, vpos, vpos, null);
4641
		workaround65205();
5025
		workaround65205();
4642
	}
5026
	}
4643
	
5027
4644
	private boolean isIgnoreAncestor() {
5028
	private boolean isIgnoreAncestor() {
4645
		return Utilities.getBoolean(getCompareConfiguration(), ICompareUIConstants.PROP_IGNORE_ANCESTOR, false);
5029
		return Utilities.getBoolean(getCompareConfiguration(),
5030
				ICompareUIConstants.PROP_IGNORE_ANCESTOR, false);
4646
	}
5031
	}
4647
	
5032
4648
	/* package */ void update(boolean includeControls) {
5033
	/* package */void update(boolean includeControls) {
4649
		if (getControl().isDisposed())
5034
		if (getControl().isDisposed())
4650
			return;
5035
			return;
4651
		if (fHasErrors) {
5036
		if (fHasErrors) {
Lines 4653-4669 Link Here
4653
		} else {
5038
		} else {
4654
			doDiff();
5039
			doDiff();
4655
		}
5040
		}
4656
		
5041
4657
		if (includeControls)
5042
		if (includeControls)
4658
			updateControls();
5043
			updateControls();
4659
		
5044
4660
		updateVScrollBar();
5045
		updateVScrollBar();
4661
		updatePresentation(null);
5046
		updatePresentation(null);
4662
	}
5047
	}
4663
5048
4664
	private void resetDiffs() {
5049
	private void resetDiffs() {
4665
		// clear stuff
5050
		// clear stuff
4666
		fCurrentDiff= null;
5051
		fCurrentDiff = null;
4667
		fMerger.reset();
5052
		fMerger.reset();
4668
		resetPositions(fLeft.getDocument());
5053
		resetPositions(fLeft.getDocument());
4669
		resetPositions(fRight.getDocument());
5054
		resetPositions(fRight.getDocument());
Lines 4673-4715 Link Here
4673
	private boolean isPatchHunk() {
5058
	private boolean isPatchHunk() {
4674
		return Utilities.isHunk(getInput());
5059
		return Utilities.isHunk(getInput());
4675
	}
5060
	}
4676
	
5061
4677
	private boolean isPatchHunkOk() {
5062
	private boolean isPatchHunkOk() {
4678
		if (isPatchHunk())
5063
		if (isPatchHunk())
4679
			return Utilities.isHunkOk(getInput());
5064
			return Utilities.isHunkOk(getInput());
4680
		return false;
5065
		return false;
4681
	}
5066
	}
4682
	
5067
4683
	/**
5068
	/**
4684
	 * Return the provided start position of the hunk in the target file.
5069
	 * Return the provided start position of the hunk in the target file.
5070
	 * 
4685
	 * @return the provided start position of the hunk in the target file
5071
	 * @return the provided start position of the hunk in the target file
4686
	 */
5072
	 */
4687
	private int getHunkStart() {
5073
	private int getHunkStart() {
4688
		Object input = getInput();
5074
		Object input = getInput();
4689
		if (input != null && input instanceof DiffNode){
5075
		if (input != null && input instanceof DiffNode) {
4690
			ITypedElement right = ((DiffNode) input).getRight();
5076
			ITypedElement right = ((DiffNode) input).getRight();
4691
			if (right != null) {
5077
			if (right != null) {
4692
				Object element = Utilities.getAdapter(right, IHunk.class);
5078
				Object element = Utilities.getAdapter(right, IHunk.class);
4693
				if (element instanceof IHunk)
5079
				if (element instanceof IHunk)
4694
					return ((IHunk)element).getStartPosition();
5080
					return ((IHunk) element).getStartPosition();
4695
			}
5081
			}
4696
			ITypedElement left = ((DiffNode) input).getLeft();
5082
			ITypedElement left = ((DiffNode) input).getLeft();
4697
			if (left != null) {
5083
			if (left != null) {
4698
				Object element = Utilities.getAdapter(left, IHunk.class);
5084
				Object element = Utilities.getAdapter(left, IHunk.class);
4699
				if (element instanceof IHunk)
5085
				if (element instanceof IHunk)
4700
					return ((IHunk)element).getStartPosition();
5086
					return ((IHunk) element).getStartPosition();
4701
			}
5087
			}
4702
		}
5088
		}
4703
		return 0;
5089
		return 0;
4704
	}
5090
	}
4705
	
5091
4706
	private IFindReplaceTarget getFindReplaceTarget() {
5092
	private IFindReplaceTarget getFindReplaceTarget() {
4707
		if (fFindReplaceTarget == null)
5093
		if (fFindReplaceTarget == null)
4708
			fFindReplaceTarget= new FindReplaceTarget();
5094
			fFindReplaceTarget = new FindReplaceTarget();
4709
		return fFindReplaceTarget;
5095
		return fFindReplaceTarget;
4710
	}
5096
	}
4711
	
5097
4712
	/* package */ char getLeg(MergeSourceViewer w) {
5098
	/* package */char getLeg(MergeSourceViewer w) {
4713
		if (w == fLeft)
5099
		if (w == fLeft)
4714
			return LEFT_CONTRIBUTOR;
5100
			return LEFT_CONTRIBUTOR;
4715
		if (w == fRight)
5101
		if (w == fRight)
Lines 4718-4724 Link Here
4718
			return ANCESTOR_CONTRIBUTOR;
5104
			return ANCESTOR_CONTRIBUTOR;
4719
		return ANCESTOR_CONTRIBUTOR;
5105
		return ANCESTOR_CONTRIBUTOR;
4720
	}
5106
	}
4721
	
5107
4722
	private boolean isCurrentDiff(Diff diff) {
5108
	private boolean isCurrentDiff(Diff diff) {
4723
		if (diff == null)
5109
		if (diff == null)
4724
			return false;
5110
			return false;
Lines 4728-4734 Link Here
4728
			return true;
5114
			return true;
4729
		return false;
5115
		return false;
4730
	}
5116
	}
4731
	
5117
4732
	private boolean isNavigationPossible() {
5118
	private boolean isNavigationPossible() {
4733
		if (fCurrentDiff == null && fMerger.hasChanges())
5119
		if (fCurrentDiff == null && fMerger.hasChanges())
4734
			return true;
5120
			return true;
(-)compare/org/eclipse/compare/internal/SaveDiffFileWizard.java (+1384 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
 *     Benjamin Muskalla (b.muskalla@gmx.net) - Bug 149672 [Patch] Create Patch wizard should remember previous settings
11
 *******************************************************************************/
12
package org.eclipse.compare.internal;
13
14
import java.io.File;
15
import java.io.IOException;
16
import java.net.MalformedURLException;
17
import java.net.URL;
18
import java.util.ArrayList;
19
import java.util.Iterator;
20
import java.util.List;
21
22
import org.eclipse.compare.internal.merge.DocumentMerger;
23
import org.eclipse.core.resources.IContainer;
24
import org.eclipse.core.resources.IFile;
25
import org.eclipse.core.resources.IProject;
26
import org.eclipse.core.resources.IResource;
27
import org.eclipse.core.resources.IWorkspace;
28
import org.eclipse.core.resources.IWorkspaceRoot;
29
import org.eclipse.core.resources.ResourcesPlugin;
30
import org.eclipse.core.runtime.IPath;
31
import org.eclipse.core.runtime.IStatus;
32
import org.eclipse.core.runtime.Path;
33
import org.eclipse.jface.dialogs.Dialog;
34
import org.eclipse.jface.dialogs.IDialogConstants;
35
import org.eclipse.jface.dialogs.IDialogSettings;
36
import org.eclipse.jface.dialogs.MessageDialog;
37
import org.eclipse.jface.dialogs.TitleAreaDialog;
38
import org.eclipse.jface.resource.ImageDescriptor;
39
import org.eclipse.jface.text.IDocument;
40
import org.eclipse.jface.viewers.DoubleClickEvent;
41
import org.eclipse.jface.viewers.IDoubleClickListener;
42
import org.eclipse.jface.viewers.ISelection;
43
import org.eclipse.jface.viewers.ISelectionChangedListener;
44
import org.eclipse.jface.viewers.IStructuredSelection;
45
import org.eclipse.jface.viewers.SelectionChangedEvent;
46
import org.eclipse.jface.viewers.StructuredSelection;
47
import org.eclipse.jface.viewers.TreeViewer;
48
import org.eclipse.jface.wizard.Wizard;
49
import org.eclipse.jface.wizard.WizardDialog;
50
import org.eclipse.jface.wizard.WizardPage;
51
import org.eclipse.swt.SWT;
52
import org.eclipse.swt.events.ModifyEvent;
53
import org.eclipse.swt.events.ModifyListener;
54
import org.eclipse.swt.events.SelectionAdapter;
55
import org.eclipse.swt.events.SelectionEvent;
56
import org.eclipse.swt.graphics.Image;
57
import org.eclipse.swt.graphics.Point;
58
import org.eclipse.swt.layout.GridData;
59
import org.eclipse.swt.layout.GridLayout;
60
import org.eclipse.swt.widgets.Button;
61
import org.eclipse.swt.widgets.Composite;
62
import org.eclipse.swt.widgets.Control;
63
import org.eclipse.swt.widgets.Event;
64
import org.eclipse.swt.widgets.FileDialog;
65
import org.eclipse.swt.widgets.Group;
66
import org.eclipse.swt.widgets.Label;
67
import org.eclipse.swt.widgets.Listener;
68
import org.eclipse.swt.widgets.Shell;
69
import org.eclipse.swt.widgets.Text;
70
import org.eclipse.ui.model.BaseWorkbenchContentProvider;
71
import org.eclipse.ui.model.WorkbenchLabelProvider;
72
import org.eclipse.ui.views.navigator.ResourceComparator;
73
74
/**
75
 * A wizard for creating a patch file by running the CVS diff command.
76
 */
77
public class SaveDiffFileWizard extends Wizard {
78
79
	private final static int INITIAL_WIDTH = 300;
80
	private final static int INITIAL_HEIGHT = 350;
81
82
	public static void run(DocumentMerger merger, IDocument leftDoc,
83
			IDocument rightDoc, String leftLabel, String rightLabel,
84
			String leftPath, String rightPath, Shell shell, boolean rightToLeft) {
85
		final String title = CompareMessages.GenerateLocalDiff_title;
86
		final SaveDiffFileWizard wizard = new SaveDiffFileWizard(merger,
87
				leftDoc, rightDoc, leftLabel, rightLabel, leftPath, rightPath,
88
				rightToLeft);
89
		wizard.setWindowTitle(title);
90
		WizardDialog dialog = new WizardDialog(shell, wizard);
91
		dialog.setMinimumPageSize(INITIAL_WIDTH, INITIAL_HEIGHT);
92
		dialog.open();
93
	}
94
95
	private class DirectionSelectionPage extends WizardPage {
96
97
		public final static int LEFT_OPTION = 1;
98
		public final static int RIGHT_OPTION = 2;
99
100
		private Button fromLeftOption;
101
		private Button fromRightOption;
102
		private RadioButtonGroup fromRadioGroup = new RadioButtonGroup();
103
104
		protected DirectionSelectionPage(String pageName, String title,
105
				ImageDescriptor titleImage) {
106
			super(pageName, title, titleImage);
107
		}
108
109
		public void createControl(Composite parent) {
110
			Composite composite = new Composite(parent, SWT.NULL);
111
			GridLayout layout = new GridLayout();
112
			layout.marginLeft = 5;
113
			layout.marginTop = 9;
114
			composite.setLayout(layout);
115
			composite.setLayoutData(new GridData());
116
			setControl(composite);
117
118
			fromLeftOption = new Button(composite, SWT.RADIO);
119
			fromLeftOption.setText(leftLabel);
120
121
			fromRightOption = new Button(composite, SWT.RADIO);
122
			fromRightOption.setText(rightLabel);
123
			GridData data = new GridData();
124
			data.verticalIndent = 6;
125
			fromRightOption.setLayoutData(data);
126
127
			fromRadioGroup.add(LEFT_OPTION, fromLeftOption);
128
			fromRadioGroup.add(RIGHT_OPTION, fromRightOption);
129
130
			Dialog.applyDialogFont(parent);
131
132
			// Add listeners
133
			fromLeftOption.addSelectionListener(new SelectionAdapter() {
134
				public void widgetSelected(SelectionEvent e) {
135
					fromRadioGroup.setSelection(LEFT_OPTION, true);
136
					targetFileEdited = false;
137
				}
138
			});
139
140
			fromRightOption.addSelectionListener(new SelectionAdapter() {
141
				public void widgetSelected(SelectionEvent e) {
142
					fromRadioGroup.setSelection(RIGHT_OPTION, true);
143
					targetFileEdited = false;
144
				}
145
			});
146
147
			fromRadioGroup.setSelection(rightToLeft ? RIGHT_OPTION
148
					: LEFT_OPTION, true);
149
		}
150
151
		public boolean isRightToLeft() {
152
			return fromRadioGroup.getSelected() != LEFT_OPTION;
153
		}
154
155
	}
156
157
	/**
158
	 * Page to select a patch file. Overriding validatePage was necessary to
159
	 * allow entering a file name that already exists.
160
	 */
161
	private class LocationPage extends WizardPage {
162
163
		public final static int CLIPBOARD = 1;
164
		public final static int FILESYSTEM = 2;
165
		public final static int WORKSPACE = 3;
166
167
		private Button cpRadio;
168
169
		private Button fsRadio;
170
		protected Text fsPathText;
171
		private Button fsBrowseButton;
172
		private boolean fsBrowsed = false;
173
174
		private Button wsRadio;
175
		protected Text wsPathText;
176
		private Button wsBrowseButton;
177
		private boolean wsBrowsed = false;
178
179
		protected boolean pageValid;
180
		protected IContainer wsSelectedContainer;
181
		protected IPath[] foldersToCreate;
182
		protected int selectedLocation;
183
184
		/**
185
		 * The default values store used to initialize the selections.
186
		 */
187
		private final DefaultValuesStore store;
188
189
		class LocationPageContentProvider extends BaseWorkbenchContentProvider {
190
			boolean showClosedProjects = false;
191
192
			public Object[] getChildren(Object element) {
193
				if (element instanceof IWorkspace) {
194
					// Check if closed projects should be shown
195
					IProject[] allProjects = ((IWorkspace) element).getRoot()
196
							.getProjects();
197
					if (showClosedProjects)
198
						return allProjects;
199
200
					ArrayList accessibleProjects = new ArrayList();
201
					for (int i = 0; i < allProjects.length; i++) {
202
						if (allProjects[i].isOpen()) {
203
							accessibleProjects.add(allProjects[i]);
204
						}
205
					}
206
					return accessibleProjects.toArray();
207
				}
208
				return super.getChildren(element);
209
			}
210
		}
211
212
		class WorkspaceDialog extends TitleAreaDialog {
213
214
			protected TreeViewer wsTreeViewer;
215
			protected Text wsFilenameText;
216
			protected Image dlgTitleImage;
217
218
			private boolean modified = false;
219
220
			public WorkspaceDialog(Shell shell) {
221
				super(shell);
222
			}
223
224
			protected Control createContents(Composite parent) {
225
				Control control = super.createContents(parent);
226
				setTitle(CompareMessages.WorkspacePatchDialogTitle);
227
				setMessage(CompareMessages.WorkspacePatchDialogDescription);
228
				dlgTitleImage = CompareUIPlugin.getImageDescriptor(
229
						ICompareUIConstants.IMG_WIZBAN_DIFF).createImage();
230
				setTitleImage(dlgTitleImage);
231
				return control;
232
			}
233
234
			protected Control createDialogArea(Composite parent) {
235
				Composite parentComposite = (Composite) super
236
						.createDialogArea(parent);
237
238
				// Create a composite with standard margins and spacing
239
				Composite composite = new Composite(parentComposite, SWT.NONE);
240
				GridLayout layout = new GridLayout();
241
				layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
242
				layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
243
				layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
244
				layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
245
				composite.setLayout(layout);
246
				composite.setLayoutData(new GridData(GridData.FILL_BOTH));
247
				composite.setFont(parentComposite.getFont());
248
249
				getShell().setText(CompareMessages.GenerateDiffFileWizard_9);
250
251
				wsTreeViewer = new TreeViewer(composite, SWT.BORDER);
252
				final GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
253
				gd.widthHint = 550;
254
				gd.heightHint = 250;
255
				wsTreeViewer.getTree().setLayoutData(gd);
256
257
				wsTreeViewer
258
						.setContentProvider(new LocationPageContentProvider());
259
				wsTreeViewer.setComparator(new ResourceComparator(
260
						ResourceComparator.NAME));
261
				wsTreeViewer.setLabelProvider(new WorkbenchLabelProvider());
262
				wsTreeViewer.setInput(ResourcesPlugin.getWorkspace());
263
264
				// Open to whatever is selected in the workspace field
265
				IPath existingWorkspacePath = new Path(wsPathText.getText());
266
				if (existingWorkspacePath != null) {
267
					// Ensure that this workspace path is valid
268
					IResource selectedResource = ResourcesPlugin.getWorkspace()
269
							.getRoot().findMember(existingWorkspacePath);
270
					if (selectedResource != null) {
271
						wsTreeViewer.expandToLevel(selectedResource, 0);
272
						wsTreeViewer.setSelection(new StructuredSelection(
273
								selectedResource));
274
					}
275
				}
276
277
				final Composite group = new Composite(composite, SWT.NONE);
278
				layout = new GridLayout(2, false);
279
				layout.marginWidth = 0;
280
				group.setLayout(layout);
281
				group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
282
						false));
283
284
				final Label label = new Label(group, SWT.NONE);
285
				label.setLayoutData(new GridData());
286
				label.setText(CompareMessages.Fi_le_name__9);
287
288
				wsFilenameText = new Text(group, SWT.BORDER);
289
				wsFilenameText.setLayoutData(new GridData(SWT.FILL, SWT.TOP,
290
						true, false));
291
292
				setupListeners();
293
294
				return parent;
295
			}
296
297
			protected Button createButton(Composite parent, int id,
298
					String label, boolean defaultButton) {
299
				Button button = super.createButton(parent, id, label,
300
						defaultButton);
301
				if (id == IDialogConstants.OK_ID) {
302
					button.setEnabled(false);
303
				}
304
				return button;
305
			}
306
307
			private void validateDialog() {
308
				String fileName = wsFilenameText.getText();
309
310
				if (fileName.equals("")) { //$NON-NLS-1$
311
					if (modified) {
312
						setErrorMessage(CompareMessages.GenerateDiffFileWizard_2);
313
						getButton(IDialogConstants.OK_ID).setEnabled(false);
314
						return;
315
					}
316
					setErrorMessage(null);
317
					getButton(IDialogConstants.OK_ID).setEnabled(false);
318
					return;
319
				}
320
321
				// Make sure that the filename is valid
322
				if (!(ResourcesPlugin.getWorkspace().validateName(fileName,
323
						IResource.FILE)).isOK()
324
						&& modified) {
325
					setErrorMessage(CompareMessages.GenerateDiffFileWizard_5);
326
					getButton(IDialogConstants.OK_ID).setEnabled(false);
327
					return;
328
				}
329
330
				// Make sure that a container has been selected
331
				if (getSelectedContainer() == null) {
332
					setErrorMessage(CompareMessages.GenerateDiffFileWizard_0);
333
					getButton(IDialogConstants.OK_ID).setEnabled(false);
334
					return;
335
				}
336
				IWorkspace workspace = ResourcesPlugin.getWorkspace();
337
				IPath fullPath = wsSelectedContainer.getFullPath().append(
338
						fileName);
339
				if (workspace.getRoot().getFolder(fullPath).exists()) {
340
					setErrorMessage(CompareMessages.GenerateDiffFileWizard_FolderExists);
341
					getButton(IDialogConstants.OK_ID).setEnabled(false);
342
					return;
343
344
				}
345
346
				setErrorMessage(null);
347
				getButton(IDialogConstants.OK_ID).setEnabled(true);
348
			}
349
350
			protected void okPressed() {
351
				IFile file = wsSelectedContainer.getFile(new Path(
352
						wsFilenameText.getText()));
353
				if (file != null)
354
					wsPathText.setText(file.getFullPath().toString());
355
356
				validatePage();
357
				super.okPressed();
358
			}
359
360
			private IContainer getSelectedContainer() {
361
				Object obj = ((IStructuredSelection) wsTreeViewer
362
						.getSelection()).getFirstElement();
363
				if (obj instanceof IContainer) {
364
					wsSelectedContainer = (IContainer) obj;
365
				} else if (obj instanceof IFile) {
366
					wsSelectedContainer = ((IFile) obj).getParent();
367
				}
368
				return wsSelectedContainer;
369
			}
370
371
			protected void cancelPressed() {
372
				validatePage();
373
				super.cancelPressed();
374
			}
375
376
			public boolean close() {
377
				if (dlgTitleImage != null)
378
					dlgTitleImage.dispose();
379
				return super.close();
380
			}
381
382
			void setupListeners() {
383
				wsTreeViewer
384
						.addSelectionChangedListener(new ISelectionChangedListener() {
385
							public void selectionChanged(
386
									SelectionChangedEvent event) {
387
								IStructuredSelection s = (IStructuredSelection) event
388
										.getSelection();
389
								Object obj = s.getFirstElement();
390
								if (obj instanceof IContainer)
391
									wsSelectedContainer = (IContainer) obj;
392
								else if (obj instanceof IFile) {
393
									IFile tempFile = (IFile) obj;
394
									wsSelectedContainer = tempFile.getParent();
395
									wsFilenameText.setText(tempFile.getName());
396
								}
397
								validateDialog();
398
							}
399
						});
400
401
				wsTreeViewer.addDoubleClickListener(new IDoubleClickListener() {
402
					public void doubleClick(DoubleClickEvent event) {
403
						ISelection s = event.getSelection();
404
						if (s instanceof IStructuredSelection) {
405
							Object item = ((IStructuredSelection) s)
406
									.getFirstElement();
407
							if (wsTreeViewer.getExpandedState(item))
408
								wsTreeViewer.collapseToLevel(item, 1);
409
							else
410
								wsTreeViewer.expandToLevel(item, 1);
411
						}
412
						validateDialog();
413
					}
414
				});
415
416
				wsFilenameText.addModifyListener(new ModifyListener() {
417
					public void modifyText(ModifyEvent e) {
418
						modified = true;
419
						validateDialog();
420
					}
421
				});
422
			}
423
		}
424
425
		LocationPage(String pageName, String title, ImageDescriptor image,
426
				DefaultValuesStore store) {
427
			super(pageName, title, image);
428
			setPageComplete(false);
429
			this.store = store;
430
		}
431
432
		protected boolean validatePage() {
433
			switch (selectedLocation) {
434
			case WORKSPACE:
435
				pageValid = validateWorkspaceLocation();
436
				break;
437
			case FILESYSTEM:
438
				pageValid = validateFilesystemLocation();
439
				break;
440
			case CLIPBOARD:
441
				pageValid = true;
442
				break;
443
			}
444
445
			// Avoid draw flicker by clearing error message if all is valid.
446
			if (pageValid) {
447
				setMessage(null);
448
				setErrorMessage(null);
449
			}
450
			setPageComplete(pageValid);
451
			return pageValid;
452
		}
453
454
		private boolean validateFilesystemLocation() {
455
			// Conditions for the file system location to be valid:
456
			// - the path must be valid and non-empty
457
			// - the path must be absolute
458
			// - the specified file must be of type file
459
			// - the parent must exist (new folders can be created via browse)
460
			final String pathString = fsPathText.getText().trim();
461
			if (pathString.length() == 0
462
					|| !new Path("").isValidPath(pathString)) { //$NON-NLS-1$
463
				if (fsBrowsed)
464
					setErrorMessage(CompareMessages.GenerateDiffFileWizard_0);
465
				else
466
					setErrorMessage(CompareMessages.GenerateDiffFileWizard_browseFilesystem);
467
				return false;
468
			}
469
470
			final File file = new File(pathString);
471
			if (!file.isAbsolute()) {
472
				setErrorMessage(CompareMessages.GenerateDiffFileWizard_0);
473
				return false;
474
			}
475
476
			if (file.isDirectory()) {
477
				setErrorMessage(CompareMessages.GenerateDiffFileWizard_2);
478
				return false;
479
			}
480
481
			if (pathString.endsWith("/") || pathString.endsWith("\\")) { //$NON-NLS-1$//$NON-NLS-2$
482
				setErrorMessage(CompareMessages.GenerateDiffFileWizard_3);
483
				return false;
484
			}
485
486
			final File parent = file.getParentFile();
487
			if (!(parent.exists() && parent.isDirectory())) {
488
				setErrorMessage(CompareMessages.GenerateDiffFileWizard_3);
489
				return false;
490
			}
491
			return true;
492
		}
493
494
		private boolean validateWorkspaceLocation() {
495
			// Conditions for the file system location to be valid:
496
			// - a parent must be selected in the workspace tree view
497
			// - the resource name must be valid
498
			if (wsPathText.getText().equals("")) { //$NON-NLS-1$
499
				// Make sure that the field actually has a filename in it
500
				// amd make sure that the user has had a chance to browse
501
				if (selectedLocation == WORKSPACE && wsBrowsed)
502
					setErrorMessage(CompareMessages.GenerateDiffFileWizard_5);
503
				else
504
					setErrorMessage(CompareMessages.GenerateDiffFileWizard_4);
505
				return false;
506
			}
507
508
			// Make sure that all the segments but the last one (i.e. project +
509
			// all folders) exist - file doesn't have to exist. It may have
510
			// happened that some folder refactoring has been done since this
511
			// path was last saved.
512
			//
513
			// The path will always be in format project/{folders}*/file - this
514
			// is controlled by the workspace location dialog and by
515
			// validatePath method when path has been entered manually.
516
			IPath pathToWorkspaceFile = new Path(wsPathText.getText());
517
			IStatus status = ResourcesPlugin.getWorkspace().validatePath(
518
					wsPathText.getText(), IResource.FILE);
519
			if (status.isOK()) {
520
				// Trim file name from path
521
				IPath containerPath = pathToWorkspaceFile.removeLastSegments(1);
522
				IResource container = ResourcesPlugin.getWorkspace().getRoot()
523
						.findMember(containerPath);
524
				if (container == null) {
525
					if (selectedLocation == WORKSPACE)
526
						setErrorMessage(CompareMessages.GenerateDiffFileWizard_4);
527
					return false;
528
				} else if (!container.isAccessible()) {
529
					if (selectedLocation == WORKSPACE)
530
						setErrorMessage(CompareMessages.GenerateDiffFileWizard_ProjectClosed);
531
					return false;
532
				} else {
533
					if (ResourcesPlugin.getWorkspace().getRoot().getFolder(
534
							pathToWorkspaceFile).exists()) {
535
						setErrorMessage(CompareMessages.GenerateDiffFileWizard_FolderExists);
536
						return false;
537
					}
538
				}
539
			} else {
540
				setErrorMessage(status.getMessage());
541
				return false;
542
			}
543
544
			return true;
545
		}
546
547
		/**
548
		 * Answers a full path to a file system file or <code>null</code> if the
549
		 * user selected to save the patch in the clipboard.
550
		 */
551
		public File getFile() {
552
			if (pageValid && selectedLocation == FILESYSTEM) {
553
				return new File(fsPathText.getText().trim());
554
			}
555
			if (pageValid && selectedLocation == WORKSPACE) {
556
				final String filename = wsPathText.getText().trim();
557
				IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
558
				final IFile file = root.getFile(new Path(filename));
559
				return file.getLocation().toFile();
560
			}
561
			return null;
562
		}
563
564
		/**
565
		 * Answers the workspace string entered in the dialog or
566
		 * <code>null</code> if the user selected to save the patch in the
567
		 * clipboard or file system.
568
		 * 
569
		 * @return workspace location or null
570
		 */
571
		public String getWorkspaceLocation() {
572
			if (pageValid && selectedLocation == WORKSPACE) {
573
				final String filename = wsPathText.getText().trim();
574
				return filename;
575
			}
576
			return null;
577
		}
578
579
		/**
580
		 * Get the selected workspace resource if the patch is to be saved in
581
		 * the workspace, or null otherwise.
582
		 * 
583
		 * @return selected resource or null
584
		 */
585
		public IResource getResource() {
586
			if (pageValid && selectedLocation == WORKSPACE) {
587
				IPath pathToWorkspaceFile = new Path(wsPathText.getText()
588
						.trim());
589
				// Trim file name from path
590
				IPath containerPath = pathToWorkspaceFile.removeLastSegments(1);
591
				return ResourcesPlugin.getWorkspace().getRoot().findMember(
592
						containerPath);
593
			}
594
			return null;
595
		}
596
597
		public void createControl(Composite parent) {
598
			final Composite composite = new Composite(parent, SWT.NULL);
599
			composite.setLayout(new GridLayout());
600
			setControl(composite);
601
			initializeDialogUnits(composite);
602
603
			setupLocationControls(composite);
604
605
			initializeDefaultValues();
606
607
			Dialog.applyDialogFont(parent);
608
609
			validatePage();
610
611
			updateEnablements();
612
			setupListeners();
613
		}
614
615
		private void setupLocationControls(final Composite parent) {
616
			final Composite composite = new Composite(parent, SWT.NULL);
617
			GridLayout gridLayout = new GridLayout();
618
			gridLayout.numColumns = 3;
619
			composite.setLayout(gridLayout);
620
			composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
621
622
			// Clipboard
623
			GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
624
			gd.horizontalSpan = 3;
625
			cpRadio = new Button(composite, SWT.RADIO);
626
			cpRadio.setText(CompareMessages.Save_To_Clipboard_2);
627
			cpRadio.setLayoutData(gd);
628
629
			// Filesystem
630
			fsRadio = new Button(composite, SWT.RADIO);
631
			fsRadio.setText(CompareMessages.Save_In_File_System_3);
632
633
			fsPathText = new Text(composite, SWT.BORDER);
634
			gd = new GridData(GridData.FILL_HORIZONTAL);
635
			fsPathText.setLayoutData(gd);
636
637
			fsBrowseButton = new Button(composite, SWT.PUSH);
638
			fsBrowseButton.setText(CompareMessages.Browse____4);
639
			GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
640
			int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
641
			Point minSize = fsBrowseButton.computeSize(SWT.DEFAULT,
642
					SWT.DEFAULT, true);
643
			data.widthHint = Math.max(widthHint, minSize.x);
644
			fsBrowseButton.setLayoutData(data);
645
646
			// Workspace
647
			wsRadio = new Button(composite, SWT.RADIO);
648
			wsRadio.setText(CompareMessages.Save_In_Workspace_7);
649
650
			wsPathText = new Text(composite, SWT.BORDER);
651
			gd = new GridData(GridData.FILL_HORIZONTAL);
652
			wsPathText.setLayoutData(gd);
653
654
			wsBrowseButton = new Button(composite, SWT.PUSH);
655
			wsBrowseButton.setText(CompareMessages.Browse____4);
656
			data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
657
			widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
658
			minSize = fsBrowseButton
659
					.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
660
			data.widthHint = Math.max(widthHint, minSize.x);
661
			wsBrowseButton.setLayoutData(data);
662
663
			((GridData) cpRadio.getLayoutData()).heightHint = minSize.y;
664
		}
665
666
		private void initializeDefaultValues() {
667
			selectedLocation = store.getLocationSelection();
668
669
			updateRadioButtons();
670
671
			// We need to ensure that we have a valid workspace path - user
672
			// could have altered workspace since last time this was saved
673
			wsPathText.setText(store.getWorkspacePath());
674
			if (!validateWorkspaceLocation()) {
675
				wsPathText.setText(""); //$NON-NLS-1$
676
				// Don't open wizard with an error - change to clipboard
677
				if (selectedLocation == WORKSPACE) {
678
					// Clear the error message caused by the workspace not
679
					// having any workspace path entered
680
					setErrorMessage(null);
681
					selectedLocation = CLIPBOARD;
682
					updateRadioButtons();
683
				}
684
			}
685
			// Do the same thing for the filesystem field
686
			fsPathText.setText(store.getFilesystemPath());
687
			if (!validateFilesystemLocation()) {
688
				fsPathText.setText(""); //$NON-NLS-1$
689
				if (selectedLocation == FILESYSTEM) {
690
					setErrorMessage(null);
691
					selectedLocation = CLIPBOARD;
692
					updateRadioButtons();
693
				}
694
			}
695
696
		}
697
698
		private void updateRadioButtons() {
699
			cpRadio.setSelection(selectedLocation == CLIPBOARD);
700
			fsRadio.setSelection(selectedLocation == FILESYSTEM);
701
			wsRadio.setSelection(selectedLocation == WORKSPACE);
702
		}
703
704
		private void setupListeners() {
705
			cpRadio.addListener(SWT.Selection, new Listener() {
706
				public void handleEvent(Event event) {
707
					selectedLocation = CLIPBOARD;
708
					validatePage();
709
					updateEnablements();
710
				}
711
			});
712
			fsRadio.addListener(SWT.Selection, new Listener() {
713
				public void handleEvent(Event event) {
714
					selectedLocation = FILESYSTEM;
715
					validatePage();
716
					updateEnablements();
717
				}
718
			});
719
720
			wsRadio.addListener(SWT.Selection, new Listener() {
721
				public void handleEvent(Event event) {
722
					selectedLocation = WORKSPACE;
723
					validatePage();
724
					updateEnablements();
725
				}
726
			});
727
728
			ModifyListener pathTextModifyListener = new ModifyListener() {
729
				public void modifyText(ModifyEvent e) {
730
					validatePage();
731
				}
732
			};
733
			fsPathText.addModifyListener(pathTextModifyListener);
734
			wsPathText.addModifyListener(pathTextModifyListener);
735
736
			fsBrowseButton.addListener(SWT.Selection, new Listener() {
737
				public void handleEvent(Event event) {
738
					final FileDialog dialog = new FileDialog(getShell(),
739
							SWT.PRIMARY_MODAL | SWT.SAVE);
740
					if (pageValid) {
741
						final File file = new File(fsPathText.getText());
742
						dialog.setFilterPath(file.getParent());
743
					}
744
					dialog.setText(CompareMessages.Save_Patch_As_5);
745
					dialog.setFileName(CompareMessages.patch_txt_6);
746
					final String path = dialog.open();
747
					fsBrowsed = true;
748
					if (path != null) {
749
						fsPathText.setText(new Path(path).toOSString());
750
					}
751
					validatePage();
752
				}
753
			});
754
755
			wsBrowseButton.addListener(SWT.Selection, new Listener() {
756
				public void handleEvent(Event event) {
757
					final WorkspaceDialog dialog = new WorkspaceDialog(
758
							getShell());
759
					wsBrowsed = true;
760
					dialog.open();
761
					validatePage();
762
				}
763
			});
764
765
		}
766
767
		public void updateEnablements() {
768
			// Enable and disable controls based on the selected radio button.
769
			fsBrowseButton.setEnabled(selectedLocation == FILESYSTEM);
770
			fsPathText.setEnabled(selectedLocation == FILESYSTEM);
771
			if (selectedLocation == FILESYSTEM)
772
				fsBrowsed = false;
773
			wsPathText.setEnabled(selectedLocation == WORKSPACE);
774
			wsBrowseButton.setEnabled(selectedLocation == WORKSPACE);
775
			if (selectedLocation == WORKSPACE)
776
				wsBrowsed = false;
777
		}
778
779
		public int getSelectedLocation() {
780
			return selectedLocation;
781
		}
782
783
	}
784
785
	private class OptionsPage extends WizardPage {
786
787
		public final static int FORMAT_UNIFIED = 1;
788
		public final static int FORMAT_CONTEXT = 2;
789
		public final static int FORMAT_STANDARD = 3;
790
791
		public final static int ROOT_WORKSPACE = 1;
792
		public final static int ROOT_PROJECT = 2;
793
		public final static int ROOT_SELECTION = 3;
794
		public final static int ROOT_CUSTOM = 4;
795
796
		private boolean initialized = false;
797
798
		private Button unifiedDiffOption;
799
		private Button contextDiffOption;
800
		private Button regularDiffOption;
801
802
		private Button unified_workspaceRelativeOption;
803
		private Button unified_projectRelativeOption;
804
		private Button unified_selectionRelativeOption;
805
		private Button unified_customRelativeOption;
806
		private Text unified_customRelativeText;
807
808
		private final RadioButtonGroup diffTypeRadioGroup = new RadioButtonGroup();
809
		private final RadioButtonGroup unifiedRadioGroup = new RadioButtonGroup();
810
811
		private final DefaultValuesStore store;
812
813
		protected OptionsPage(String pageName, String title,
814
				ImageDescriptor titleImage, DefaultValuesStore store) {
815
			super(pageName, title, titleImage);
816
			this.store = store;
817
		}
818
819
		public void setVisible(boolean visible) {
820
			super.setVisible(visible);
821
			if (!initialized && visible) {
822
				File toFile = null;
823
				if (directionSelectionPage.isRightToLeft()) {
824
					toFile = new File(leftPath);
825
				} else {
826
					toFile = new File(rightPath);
827
				}
828
				String toPath = toFile.getPath();
829
				unified_customRelativeText.setText(toPath);
830
				targetFileEdited = true;
831
			}
832
		}
833
834
		public void createControl(Composite parent) {
835
			Composite composite = new Composite(parent, SWT.NULL);
836
			GridLayout layout = new GridLayout();
837
			composite.setLayout(layout);
838
			composite.setLayoutData(new GridData());
839
			setControl(composite);
840
841
			Group diffTypeGroup = new Group(composite, SWT.NONE);
842
			layout = new GridLayout();
843
			layout.marginHeight = 0;
844
			diffTypeGroup.setLayout(layout);
845
			GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL
846
					| GridData.GRAB_HORIZONTAL);
847
			diffTypeGroup.setLayoutData(data);
848
			diffTypeGroup.setText(CompareMessages.Diff_output_format_12);
849
850
			unifiedDiffOption = new Button(diffTypeGroup, SWT.RADIO);
851
			unifiedDiffOption
852
					.setText(CompareMessages.Unified__format_required_by_Compare_With_Patch_feature__13);
853
854
			contextDiffOption = new Button(diffTypeGroup, SWT.RADIO);
855
			contextDiffOption.setText(CompareMessages.Context_14);
856
			regularDiffOption = new Button(diffTypeGroup, SWT.RADIO);
857
			regularDiffOption.setText(CompareMessages.Standard_15);
858
859
			diffTypeRadioGroup.add(FORMAT_UNIFIED, unifiedDiffOption);
860
			diffTypeRadioGroup.add(FORMAT_CONTEXT, contextDiffOption);
861
			diffTypeRadioGroup.add(FORMAT_STANDARD, regularDiffOption);
862
863
			// Unified Format Options
864
			Group unifiedGroup = new Group(composite, SWT.None);
865
			layout = new GridLayout();
866
			layout.numColumns = 2;
867
			unifiedGroup.setLayout(layout);
868
			data = new GridData(GridData.HORIZONTAL_ALIGN_FILL
869
					| GridData.GRAB_HORIZONTAL);
870
			unifiedGroup.setLayoutData(data);
871
			unifiedGroup.setText(CompareMessages.GenerateDiffFileWizard_10);
872
873
			unified_workspaceRelativeOption = new Button(unifiedGroup,
874
					SWT.RADIO);
875
			unified_workspaceRelativeOption
876
					.setText(CompareMessages.GenerateDiffFileWizard_6);
877
			unified_workspaceRelativeOption.setLayoutData(new GridData(
878
					SWT.BEGINNING, SWT.CENTER, false, false, 2, 1));
879
880
			unified_projectRelativeOption = new Button(unifiedGroup, SWT.RADIO);
881
			unified_projectRelativeOption
882
					.setText(CompareMessages.GenerateDiffFileWizard_7);
883
			unified_projectRelativeOption.setLayoutData(new GridData(
884
					SWT.BEGINNING, SWT.CENTER, false, false, 2, 1));
885
886
			unified_selectionRelativeOption = new Button(unifiedGroup,
887
					SWT.RADIO);
888
			unified_selectionRelativeOption
889
					.setText(CompareMessages.GenerateDiffFileWizard_8);
890
			unified_selectionRelativeOption.setLayoutData(new GridData(
891
					SWT.BEGINNING, SWT.CENTER, false, false, 2, 1));
892
893
			unified_customRelativeOption = new Button(unifiedGroup, SWT.RADIO);
894
			unified_customRelativeOption
895
					.setText(CompareMessages.GenerateDiffFileWizard_13);
896
			unified_customRelativeOption.setSelection(true);
897
			unified_customRelativeOption.setLayoutData(new GridData(
898
					SWT.BEGINNING, SWT.CENTER, false, false, 1, 1));
899
900
			unified_customRelativeText = new Text(unifiedGroup, SWT.BORDER);
901
			unified_customRelativeText.setLayoutData(new GridData(SWT.FILL,
902
					SWT.CENTER, true, false, 1, 1));
903
904
			unifiedRadioGroup.add(ROOT_WORKSPACE,
905
					unified_workspaceRelativeOption);
906
			unifiedRadioGroup.add(ROOT_PROJECT, unified_projectRelativeOption);
907
			unifiedRadioGroup.add(ROOT_SELECTION,
908
					unified_selectionRelativeOption);
909
			unifiedRadioGroup.add(ROOT_CUSTOM, unified_customRelativeOption);
910
911
			Dialog.applyDialogFont(parent);
912
913
			initializeDefaultValues();
914
915
			// add listeners
916
			unifiedDiffOption.addSelectionListener(new SelectionAdapter() {
917
				public void widgetSelected(SelectionEvent e) {
918
					diffTypeRadioGroup.setSelection(FORMAT_UNIFIED, false);
919
				}
920
			});
921
922
			contextDiffOption.addSelectionListener(new SelectionAdapter() {
923
				public void widgetSelected(SelectionEvent e) {
924
					diffTypeRadioGroup.setSelection(FORMAT_CONTEXT, false);
925
				}
926
			});
927
928
			regularDiffOption.addSelectionListener(new SelectionAdapter() {
929
				public void widgetSelected(SelectionEvent e) {
930
					diffTypeRadioGroup.setSelection(FORMAT_STANDARD, false);
931
				}
932
			});
933
934
			unified_workspaceRelativeOption
935
					.addSelectionListener(new SelectionAdapter() {
936
						public void widgetSelected(SelectionEvent e) {
937
							unifiedRadioGroup.setSelection(ROOT_WORKSPACE,
938
									false);
939
						}
940
					});
941
942
			unified_projectRelativeOption
943
					.addSelectionListener(new SelectionAdapter() {
944
						public void widgetSelected(SelectionEvent e) {
945
							unifiedRadioGroup.setSelection(ROOT_PROJECT, false);
946
						}
947
					});
948
949
			unified_selectionRelativeOption
950
					.addSelectionListener(new SelectionAdapter() {
951
						public void widgetSelected(SelectionEvent e) {
952
							unifiedRadioGroup.setSelection(ROOT_SELECTION,
953
									false);
954
						}
955
					});
956
957
			unified_selectionRelativeOption
958
					.addSelectionListener(new SelectionAdapter() {
959
						public void widgetSelected(SelectionEvent e) {
960
							unifiedRadioGroup.setSelection(ROOT_CUSTOM, false);
961
						}
962
					});
963
964
			// calculatePatchRoot();
965
			updateEnablements();
966
967
			// update selection
968
			diffTypeRadioGroup.selectEnabledOnly();
969
			unifiedRadioGroup.selectEnabledOnly();
970
		}
971
972
		public int getFormatSelection() {
973
			return diffTypeRadioGroup.getSelected();
974
		}
975
976
		public int getRootSelection() {
977
			return unifiedRadioGroup.getSelected();
978
		}
979
980
		public String getPath() {
981
			return unified_customRelativeText.getText();
982
		}
983
984
		private void initializeDefaultValues() {
985
			// Radio buttons for format
986
			diffTypeRadioGroup.setSelection(store.getFormatSelection(), true);
987
			// Radio buttons for patch root
988
			unifiedRadioGroup.setSelection(store.getRootSelection(), true);
989
		}
990
991
		protected void updateEnablements() {
992
			diffTypeRadioGroup.setEnablement(false, new int[] { FORMAT_CONTEXT,
993
					FORMAT_STANDARD }, FORMAT_UNIFIED);
994
			unifiedRadioGroup.setEnablement(false, new int[] { ROOT_WORKSPACE,
995
					ROOT_PROJECT, ROOT_SELECTION }, ROOT_CUSTOM);
996
		}
997
998
	}
999
1000
	/**
1001
	 * Class to retrieve and store the default selected values.
1002
	 */
1003
	private final class DefaultValuesStore {
1004
1005
		private static final String PREF_LAST_SELECTION = "org.eclipse.compare.internal.GenerateDiffFileWizard.PatchFileSelectionPage.lastselection"; //$NON-NLS-1$
1006
		private static final String PREF_LAST_FS_PATH = "org.eclipse.compare.internal.GenerateDiffFileWizard.PatchFileSelectionPage.filesystem.path"; //$NON-NLS-1$
1007
		private static final String PREF_LAST_WS_PATH = "org.eclipse.compare.internal.GenerateDiffFileWizard.PatchFileSelectionPage.workspace.path"; //$NON-NLS-1$
1008
		private static final String PREF_LAST_AO_FORMAT = "org.eclipse.compare.internal.GenerateDiffFileWizard.OptionsPage.diff.format"; //$NON-NLS-1$
1009
		private static final String PREF_LAST_AO_ROOT = "org.eclipse.compare.internal.GenerateDiffFileWizard.OptionsPage.patch.root"; //$NON-NLS-1$
1010
1011
		private final IDialogSettings dialogSettings;
1012
1013
		public DefaultValuesStore() {
1014
			dialogSettings = CompareUIPlugin.getDefault().getDialogSettings();
1015
		}
1016
1017
		public int getLocationSelection() {
1018
			int value = LocationPage.CLIPBOARD;
1019
			try {
1020
				value = dialogSettings.getInt(PREF_LAST_SELECTION);
1021
			} catch (NumberFormatException e) {
1022
				// Ignore
1023
			}
1024
1025
			switch (value) {
1026
			case LocationPage.FILESYSTEM:
1027
			case LocationPage.WORKSPACE:
1028
			case LocationPage.CLIPBOARD:
1029
				return value;
1030
			default:
1031
				return LocationPage.CLIPBOARD;
1032
			}
1033
		}
1034
1035
		public String getFilesystemPath() {
1036
			final String path = dialogSettings.get(PREF_LAST_FS_PATH);
1037
			return path != null ? path : ""; //$NON-NLS-1$
1038
		}
1039
1040
		public String getWorkspacePath() {
1041
			final String path = dialogSettings.get(PREF_LAST_WS_PATH);
1042
			return path != null ? path : ""; //$NON-NLS-1$
1043
		}
1044
1045
		public int getFormatSelection() {
1046
			int value = OptionsPage.FORMAT_UNIFIED;
1047
			try {
1048
				value = dialogSettings.getInt(PREF_LAST_AO_FORMAT);
1049
			} catch (NumberFormatException e) {
1050
				// Ignore
1051
			}
1052
1053
			switch (value) {
1054
			case OptionsPage.FORMAT_UNIFIED:
1055
			case OptionsPage.FORMAT_CONTEXT:
1056
			case OptionsPage.FORMAT_STANDARD:
1057
				return value;
1058
			default:
1059
				return OptionsPage.FORMAT_UNIFIED;
1060
			}
1061
		}
1062
1063
		public int getRootSelection() {
1064
			int value = OptionsPage.ROOT_WORKSPACE;
1065
			try {
1066
				value = dialogSettings.getInt(PREF_LAST_AO_ROOT);
1067
			} catch (NumberFormatException e) {
1068
				// Ignore
1069
			}
1070
1071
			switch (value) {
1072
			case OptionsPage.ROOT_WORKSPACE:
1073
			case OptionsPage.ROOT_PROJECT:
1074
			case OptionsPage.ROOT_SELECTION:
1075
				return value;
1076
			default:
1077
				return OptionsPage.ROOT_WORKSPACE;
1078
			}
1079
		}
1080
1081
		public void storeLocationSelection(int defaultSelection) {
1082
			dialogSettings.put(PREF_LAST_SELECTION, defaultSelection);
1083
		}
1084
1085
		public void storeFilesystemPath(String path) {
1086
			dialogSettings.put(PREF_LAST_FS_PATH, path);
1087
		}
1088
1089
		public void storeWorkspacePath(String path) {
1090
			dialogSettings.put(PREF_LAST_WS_PATH, path);
1091
		}
1092
1093
		public void storeOutputFormat(int selection) {
1094
			dialogSettings.put(PREF_LAST_AO_FORMAT, selection);
1095
		}
1096
1097
		public void storePatchRoot(int selection) {
1098
			dialogSettings.put(PREF_LAST_AO_ROOT, selection);
1099
		}
1100
	}
1101
1102
	private DirectionSelectionPage directionSelectionPage;
1103
	private LocationPage locationPage;
1104
	private OptionsPage optionsPage;
1105
1106
	// protected IResource[] resources;
1107
	private final DefaultValuesStore defaultValuesStore;
1108
	// private final IWorkbenchPart part;
1109
1110
	private DocumentMerger merger;
1111
	private IDocument leftDoc;
1112
	private IDocument rightDoc;
1113
	private String leftLabel;
1114
	private String rightLabel;
1115
	private String leftPath;
1116
	private String rightPath;
1117
	private boolean rightToLeft;
1118
1119
	private boolean targetFileEdited = false;
1120
1121
	public SaveDiffFileWizard(DocumentMerger merger, IDocument leftDoc,
1122
			IDocument rightDoc, String leftLabel, String rightLabel,
1123
			String leftPath, String rightPath, boolean rightToLeft) {
1124
		super();
1125
		setWindowTitle(CompareMessages.GenerateLocalDiff_title);
1126
		initializeDefaultPageImageDescriptor();
1127
		defaultValuesStore = new DefaultValuesStore();
1128
		this.merger = merger;
1129
		this.leftDoc = leftDoc;
1130
		this.rightDoc = rightDoc;
1131
		this.leftLabel = leftLabel;
1132
		this.rightLabel = rightLabel;
1133
		this.leftPath = leftPath;
1134
		this.rightPath = rightPath;
1135
		this.rightToLeft = rightToLeft;
1136
	}
1137
1138
	public void addPages() {
1139
		String pageTitle = CompareMessages.GenerateLocalDiff_pageTitle;
1140
		String pageDescription = CompareMessages.GenerateLocalDiff_Specify_the_file_which_contributes_the_changes;
1141
		directionSelectionPage = new DirectionSelectionPage(
1142
				pageTitle,
1143
				pageTitle,
1144
				CompareUIPlugin
1145
						.getImageDescriptor(ICompareUIConstants.IMG_WIZBAN_DIFF));
1146
		directionSelectionPage.setDescription(pageDescription);
1147
		addPage(directionSelectionPage);
1148
1149
		pageTitle = CompareMessages.GenerateLocalDiff_pageTitle;
1150
		pageDescription = CompareMessages.GenerateLocalDiff_pageDescription;
1151
		locationPage = new LocationPage(pageTitle, pageTitle, CompareUIPlugin
1152
				.getImageDescriptor(ICompareUIConstants.IMG_WIZBAN_DIFF),
1153
				defaultValuesStore);
1154
		locationPage.setDescription(pageDescription);
1155
		addPage(locationPage);
1156
1157
		pageTitle = CompareMessages.Advanced_options_19;
1158
		pageDescription = CompareMessages.Configure_the_options_used_for_the_CVS_diff_command_20;
1159
		optionsPage = new OptionsPage(pageTitle, pageTitle, CompareUIPlugin
1160
				.getImageDescriptor(ICompareUIConstants.IMG_WIZBAN_DIFF),
1161
				defaultValuesStore);
1162
		optionsPage.setDescription(pageDescription);
1163
		addPage(optionsPage);
1164
	}
1165
1166
	/**
1167
	 * Declares the wizard banner iamge descriptor
1168
	 */
1169
	protected void initializeDefaultPageImageDescriptor() {
1170
		final String iconPath = "icons/full/"; //$NON-NLS-1$
1171
		try {
1172
			final URL installURL = CompareUIPlugin.getDefault().getBundle()
1173
					.getEntry("/"); //$NON-NLS-1$
1174
			final URL url = new URL(installURL, iconPath
1175
					+ "wizards/newconnect_wiz.gif"); //$NON-NLS-1$
1176
			ImageDescriptor desc = ImageDescriptor.createFromURL(url);
1177
			setDefaultPageImageDescriptor(desc);
1178
		} catch (MalformedURLException e) {
1179
			// Should not happen. Ignore.
1180
		}
1181
	}
1182
1183
	/*
1184
	 * (Non-javadoc) Method declared on IWizard.
1185
	 */
1186
	public boolean needsProgressMonitor() {
1187
		return true;
1188
	}
1189
1190
	public boolean performFinish() {
1191
		final int location = locationPage.getSelectedLocation();
1192
		final File file = location != LocationPage.CLIPBOARD ? locationPage
1193
				.getFile() : null;
1194
1195
		if (!(file == null || validateFile(file))) {
1196
			return false;
1197
		}
1198
1199
		// Create the patch
1200
		generateDiffFile(file);
1201
1202
		// Refresh workspace if necessary and save default selection.
1203
		switch (location) {
1204
		case LocationPage.WORKSPACE:
1205
			final String workspaceResource = locationPage
1206
					.getWorkspaceLocation();
1207
			if (workspaceResource != null) {
1208
				defaultValuesStore
1209
						.storeLocationSelection(LocationPage.WORKSPACE);
1210
				defaultValuesStore.storeWorkspacePath(workspaceResource);
1211
			} else {
1212
				// Problem with workspace location, choose clipboard next time
1213
				defaultValuesStore
1214
						.storeLocationSelection(LocationPage.CLIPBOARD);
1215
			}
1216
			break;
1217
		case LocationPage.FILESYSTEM:
1218
			defaultValuesStore.storeFilesystemPath(file.getPath());
1219
			defaultValuesStore.storeLocationSelection(LocationPage.FILESYSTEM);
1220
			break;
1221
		case LocationPage.CLIPBOARD:
1222
			defaultValuesStore.storeLocationSelection(LocationPage.CLIPBOARD);
1223
			break;
1224
		default:
1225
			return false;
1226
		}
1227
1228
		defaultValuesStore.storeOutputFormat(optionsPage.getFormatSelection());
1229
		defaultValuesStore.storePatchRoot(optionsPage.getRootSelection());
1230
1231
		return true;
1232
	}
1233
1234
	private void generateDiffFile(File file) {
1235
		String toPath = null;
1236
		if (targetFileEdited) {
1237
			toPath = optionsPage.getPath();
1238
		} else {
1239
			File toFile = null;
1240
			if (directionSelectionPage.isRightToLeft()) {
1241
				toFile = new File(leftPath);
1242
			} else {
1243
				toFile = new File(rightPath);
1244
			}
1245
			toPath = toFile.getPath();
1246
		}
1247
1248
		UnifiedDiffFormatter formatter = new UnifiedDiffFormatter(merger,
1249
				leftDoc, rightDoc, toPath, directionSelectionPage
1250
						.isRightToLeft());
1251
		try {
1252
			if (file == null) {
1253
				formatter.generateDiff(getShell().getDisplay());
1254
			} else {
1255
				formatter.generateDiff(file);
1256
			}
1257
		} catch (IOException e) {
1258
			throw new RuntimeException(e);
1259
		}
1260
	}
1261
1262
	public boolean validateFile(File file) {
1263
		if (file == null)
1264
			return false;
1265
1266
		// Consider file valid if it doesn't exist for now.
1267
		if (!file.exists())
1268
			return true;
1269
1270
		// The file exists.
1271
		if (!file.canWrite()) {
1272
			final String title = CompareMessages.GenerateLocalDiff_1;
1273
			final String msg = CompareMessages.GenerateLocalDiff_2;
1274
			final MessageDialog dialog = new MessageDialog(getShell(), title,
1275
					null, msg, MessageDialog.ERROR,
1276
					new String[] { IDialogConstants.OK_LABEL }, 0);
1277
			dialog.open();
1278
			return false;
1279
		}
1280
1281
		final String title = CompareMessages.GenerateLocalDiff_overwriteTitle;
1282
		final String msg = CompareMessages.GenerateLocalDiff_overwriteMsg;
1283
		final MessageDialog dialog = new MessageDialog(getShell(), title, null,
1284
				msg, MessageDialog.QUESTION, new String[] {
1285
						IDialogConstants.YES_LABEL,
1286
						IDialogConstants.CANCEL_LABEL }, 0);
1287
		dialog.open();
1288
		if (dialog.getReturnCode() != 0) {
1289
			return false;
1290
		}
1291
		return true;
1292
	}
1293
1294
	/**
1295
	 * The class maintain proper selection of radio button within the group:
1296
	 * <ul>
1297
	 * <li>Only one button can be selected at the time.</li>
1298
	 * <li>Disabled button can't be selected unless all buttons in the group are
1299
	 * disabled.</li>
1300
	 * </ul>
1301
	 */
1302
	private class RadioButtonGroup {
1303
1304
		private List buttons = new ArrayList(3);
1305
1306
		private int selected = 0;
1307
1308
		public void add(int buttonCode, Button button) {
1309
			if (button != null && (button.getStyle() & SWT.RADIO) != 0) {
1310
				if (button.getSelection() && !buttons.isEmpty()) {
1311
					deselectAll();
1312
					selected = buttonCode - 1;
1313
				}
1314
				buttons.add(buttonCode - 1, button);
1315
			}
1316
		}
1317
1318
		public int getSelected() {
1319
			return selected + 1;
1320
		}
1321
1322
		public int setSelection(int buttonCode, boolean selectEnabledOnly) {
1323
			deselectAll();
1324
1325
			((Button) buttons.get(buttonCode - 1)).setSelection(true);
1326
			selected = buttonCode - 1;
1327
			if (selectEnabledOnly)
1328
				selected = selectEnabledOnly() - 1;
1329
			return getSelected();
1330
		}
1331
1332
		public int selectEnabledOnly() {
1333
			deselectAll();
1334
			Button selectedButton = (Button) buttons.get(selected);
1335
			if (!selectedButton.isEnabled()) {
1336
				// If the button is disabled, set selection to an enabled one
1337
				for (Iterator iterator = buttons.iterator(); iterator.hasNext();) {
1338
					Button b = (Button) iterator.next();
1339
					if (b.isEnabled()) {
1340
						b.setSelection(true);
1341
						selected = buttons.indexOf(b);
1342
						return selected + 1;
1343
					}
1344
				}
1345
				// If none found, reset the initial selection
1346
				selectedButton.setSelection(true);
1347
			} else {
1348
				// Because selection has been cleared, set it again
1349
				selectedButton.setSelection(true);
1350
			}
1351
			// Return selected button's code so the value can be stored
1352
			return getSelected();
1353
		}
1354
1355
		public void setEnablement(boolean enabled, int[] buttonsToChange,
1356
				int defaultSelection) {
1357
			// Enable (or disable) given buttons
1358
			for (int i = 0; i < buttonsToChange.length; i++) {
1359
				((Button) this.buttons.get(buttonsToChange[i] - 1))
1360
						.setEnabled(enabled);
1361
			}
1362
			// Check whether the selected button is enabled
1363
			if (!((Button) this.buttons.get(selected)).isEnabled()) {
1364
				if (defaultSelection != -1)
1365
					// Set the default selection and check if it's enabled
1366
					setSelection(defaultSelection, true);
1367
				else
1368
					// No default selection is given, select any enabled button
1369
					selectEnabledOnly();
1370
			}
1371
		}
1372
1373
		public void setEnablement(boolean enabled, int[] buttonsToChange) {
1374
			// Value -1 means that no default selection is given
1375
			setEnablement(enabled, buttonsToChange, -1);
1376
		}
1377
1378
		private void deselectAll() {
1379
			for (Iterator iterator = buttons.iterator(); iterator.hasNext();)
1380
				((Button) iterator.next()).setSelection(false);
1381
		}
1382
	}
1383
1384
}
(-)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