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

Collapse All | Expand All

(-)plugin.properties (+2 lines)
Lines 74-78 Link Here
74
CompareLocalHistory.tooltip= Compare the Selected Resource with Local History
74
CompareLocalHistory.tooltip= Compare the Selected Resource with Local History
75
ReplaceLocalHistory.label= &Local History...
75
ReplaceLocalHistory.label= &Local History...
76
ReplaceLocalHistory.tooltip= Replace the Selected Resource with Local History
76
ReplaceLocalHistory.tooltip= Replace the Selected Resource with Local History
77
CompareWithEachOtherAction.label= &Each Other
78
CompareWithEachOtherAction.tooltip= Compare the Selected Resources
77
79
78
ignoresTransferName= Team Ignored Resources Transfer
80
ignoresTransferName= Team Ignored Resources Transfer
(-)plugin.xml (+9 lines)
Lines 154-159 Link Here
154
               enablesFor="1"
154
               enablesFor="1"
155
               overrideActionId="replaceFromHistory"
155
               overrideActionId="replaceFromHistory"
156
               tooltip="%ReplaceLocalHistory.tooltip"/>
156
               tooltip="%ReplaceLocalHistory.tooltip"/>
157
         <action
158
               class="org.eclipse.team.internal.ui.actions.CompareAction"
159
               enablesFor="2+"
160
               id="org.eclipse.team.ui.compareWithEachOther"
161
               label="%CompareWithEachOtherAction.label"
162
               menubarPath="compareWithMenu/compareWithGroup"
163
               overrideActionId="compareWithEachOther"
164
               tooltip="CompareWithEachOtherAction.tooltip">
165
         </action>
157
      </objectContribution>
166
      </objectContribution>
158
      <objectContribution
167
      <objectContribution
159
            objectClass="org.eclipse.core.resources.IResource"
168
            objectClass="org.eclipse.core.resources.IResource"
(-)src/org/eclipse/team/internal/ui/messages.properties (+8 lines)
Lines 548-550 Link Here
548
TeamAction_handlerNotEnabledTitle=Warning
548
TeamAction_handlerNotEnabledTitle=Warning
549
TeamAction_handlerNotEnabledMessage=The action doesn't apply to the current selection.
549
TeamAction_handlerNotEnabledMessage=The action doesn't apply to the current selection.
550
SaveableCompareEditorInput_0=Show In
550
SaveableCompareEditorInput_0=Show In
551
SaveablesCompareEditorInput_twoWayTitle=Compare (''{0}'' - ''{1}'')
552
SaveablesCompareEditorInput_twoWayTooltip=Two-way compare of ''{0}'' with ''{1}''
553
SaveablesCompareEditorInput_threeWayTitle=Compare (''{0}'' - ''{1}'' - ''{2}'')
554
SaveablesCompareEditorInput_threeWayTooltip=Three-way compare of ''{1}'' and ''{2}'' relative to common ancestor ''{0}''
555
556
SelectAncestorDialog_title=Select Common Ancestor
557
SelectAncestorDialog_message=Which resource would you like to use as the common ancestor in the three-way compare?
558
SelectAncestorDialog_option=''{0}''
(-)src/org/eclipse/team/internal/ui/TeamUIMessages.java (+9 lines)
Lines 225-230 Link Here
225
	public static String RevisionAnnotationController_0;
225
	public static String RevisionAnnotationController_0;
226
226
227
	public static String SaveableCompareEditorInput_0;
227
	public static String SaveableCompareEditorInput_0;
228
	public static String SaveablesCompareEditorInput_twoWayTitle;
229
	public static String SaveablesCompareEditorInput_twoWayTooltip;
230
	public static String SaveablesCompareEditorInput_threeWayTitle;
231
	public static String SaveablesCompareEditorInput_threeWayTooltip;
228
232
229
	public static String ShowLocalHistory_0;
233
	public static String ShowLocalHistory_0;
230
234
Lines 692-695 Link Here
692
	public static String TeamAction_errorTitle;
696
	public static String TeamAction_errorTitle;
693
	public static String TeamAction_handlerNotEnabledTitle;
697
	public static String TeamAction_handlerNotEnabledTitle;
694
	public static String TeamAction_handlerNotEnabledMessage;
698
	public static String TeamAction_handlerNotEnabledMessage;
699
	
700
	public static String SelectAncestorDialog_title;
701
	public static String SelectAncestorDialog_message;
702
	public static String SelectAncestorDialog_option;
703
695
}
704
}
(-)src/org/eclipse/team/internal/ui/synchronize/SaveablesCompareEditorInput.java (+791 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.team.internal.ui.synchronize;
12
13
import java.lang.reflect.InvocationTargetException;
14
15
import org.eclipse.compare.*;
16
import org.eclipse.compare.structuremergeviewer.*;
17
import org.eclipse.core.resources.IFile;
18
import org.eclipse.core.resources.IResource;
19
import org.eclipse.core.runtime.*;
20
import org.eclipse.jface.action.*;
21
import org.eclipse.jface.resource.ImageDescriptor;
22
import org.eclipse.jface.resource.ImageRegistry;
23
import org.eclipse.jface.text.IDocument;
24
import org.eclipse.jface.text.ITextViewer;
25
import org.eclipse.jface.util.IPropertyChangeListener;
26
import org.eclipse.jface.viewers.*;
27
import org.eclipse.osgi.util.NLS;
28
import org.eclipse.swt.events.DisposeEvent;
29
import org.eclipse.swt.events.DisposeListener;
30
import org.eclipse.swt.graphics.Image;
31
import org.eclipse.swt.widgets.*;
32
import org.eclipse.team.internal.ui.*;
33
import org.eclipse.team.internal.ui.history.CompareFileRevisionEditorInput;
34
import org.eclipse.team.internal.ui.mapping.AbstractCompareInput;
35
import org.eclipse.team.internal.ui.mapping.CompareInputChangeNotifier;
36
import org.eclipse.team.internal.ui.synchronize.EditableSharedDocumentAdapter.ISharedDocumentAdapterListener;
37
import org.eclipse.team.ui.mapping.SaveableComparison;
38
import org.eclipse.team.ui.synchronize.SaveableCompareEditorInput;
39
import org.eclipse.ui.*;
40
import org.eclipse.ui.actions.*;
41
import org.eclipse.ui.keys.IBindingService;
42
import org.eclipse.ui.services.IDisposable;
43
44
/**
45
 * A compare editor input that makes use of a {@link Saveable} to manage the
46
 * save lifecycle of the left and right sides of the comparison. The ancestor
47
 * part of the comparison is not editable.
48
 */
49
public class SaveablesCompareEditorInput extends CompareEditorInput implements
50
		ISaveablesSource {
51
52
	private IPropertyListener fLeftPropertyListener;
53
	private IPropertyListener fRightPropertyListener;
54
55
	private Saveable fLeftSaveable;
56
	private Saveable fRightSaveable;
57
58
	private ITypedElement fAncestorElement;
59
	private ITypedElement fLeftElement;
60
	private ITypedElement fRightElement;
61
62
	private final IWorkbenchPage page;
63
	private final ListenerList inputChangeListeners = new ListenerList(
64
			ListenerList.IDENTITY);
65
	private ICompareInputChangeListener compareInputChangeListener;
66
67
	public SaveablesCompareEditorInput(ITypedElement ancestor,
68
			ITypedElement left, ITypedElement right, IWorkbenchPage page) {
69
		super(new CompareConfiguration());
70
		this.page = page;
71
		this.fAncestorElement = ancestor;
72
		this.fLeftElement = left;
73
		this.fRightElement = right;
74
	}
75
76
	private static ITypedElement getFileElement(ITypedElement element,
77
			CompareEditorInput editorInput) {
78
		if (element instanceof LocalResourceTypedElement) {
79
			return (LocalResourceTypedElement) element;
80
		}
81
		if (editorInput instanceof CompareFileRevisionEditorInput) {
82
			return ((CompareFileRevisionEditorInput) editorInput)
83
					.getLocalElement();
84
		}
85
		return null;
86
	}
87
88
	/**
89
	 * Return a typed element that represents a local file. If the element
90
	 * returned from this method is used as the left contributor of the compare
91
	 * input for a {@link SaveableCompareEditorInput}, then the file will be
92
	 * properly saved when the compare editor input or viewers are saved.
93
	 * 
94
	 * @param file
95
	 *            the file
96
	 * @return a typed element that represents a local file.
97
	 */
98
	public static ITypedElement createFileElement(IFile file) {
99
		return new LocalResourceTypedElement(file);
100
	}
101
102
	private ISaveablesLifecycleListener getSaveablesLifecycleListener(
103
			IWorkbenchPart part) {
104
		ISaveablesLifecycleListener listener = (ISaveablesLifecycleListener) Utils
105
				.getAdapter(part, ISaveablesLifecycleListener.class);
106
		if (listener == null)
107
			listener = (ISaveablesLifecycleListener) part.getSite().getService(
108
					ISaveablesLifecycleListener.class);
109
		return listener;
110
	}
111
112
	/*
113
	 * (non-Javadoc)
114
	 * 
115
	 * @see org.eclipse.compare.CompareEditorInput#contentsCreated()
116
	 */
117
	protected void contentsCreated() {
118
		super.contentsCreated();
119
		compareInputChangeListener = new ICompareInputChangeListener() {
120
			public void compareInputChanged(ICompareInput source) {
121
				if (source == getCompareResult()) {
122
					boolean closed = false;
123
					if (source.getKind() == Differencer.NO_CHANGE) {
124
						closed = closeEditor(true);
125
					}
126
					if (!closed) {
127
						// The editor was closed either because the compare
128
						// input still has changes
129
						// or because the editor input is dirty. In either case,
130
						// fire the changes
131
						// to the registered listeners
132
						propogateInputChange();
133
					}
134
				}
135
			}
136
		};
137
		getCompareInput().addCompareInputChangeListener(
138
				compareInputChangeListener);
139
140
		if (getLeftSaveable() instanceof SaveableComparison) {
141
			SaveableComparison lscm = (SaveableComparison) fLeftSaveable;
142
			fLeftPropertyListener = new IPropertyListener() {
143
				public void propertyChanged(Object source, int propId) {
144
					if (propId == SaveableComparison.PROP_DIRTY) {
145
						setDirty(fLeftSaveable.isDirty());
146
					}
147
				}
148
			};
149
			lscm.addPropertyListener(fLeftPropertyListener);
150
		}
151
152
		if (getRightSaveable() instanceof SaveableComparison) {
153
			SaveableComparison rscm = (SaveableComparison) fRightSaveable;
154
			fRightPropertyListener = new IPropertyListener() {
155
				public void propertyChanged(Object source, int propId) {
156
					if (propId == SaveableComparison.PROP_DIRTY) {
157
						setDirty(fRightSaveable.isDirty());
158
					}
159
				}
160
			};
161
			rscm.addPropertyListener(fRightPropertyListener);
162
		}
163
164
		setDirty(fLeftSaveable.isDirty() || fRightSaveable.isDirty());
165
	}
166
167
	/*
168
	 * (non-Javadoc)
169
	 * 
170
	 * @see org.eclipse.compare.CompareEditorInput#handleDispose()
171
	 */
172
	protected void handleDispose() {
173
		super.handleDispose();
174
		ICompareInput compareInput = getCompareInput();
175
		if (compareInput != null)
176
			compareInput
177
					.removeCompareInputChangeListener(compareInputChangeListener);
178
		compareInputChangeListener = null;
179
		if (fLeftSaveable instanceof SaveableComparison) {
180
			SaveableComparison scm = (SaveableComparison) fLeftSaveable;
181
			scm.removePropertyListener(fLeftPropertyListener);
182
		}
183
		if (fLeftSaveable instanceof LocalResourceSaveableComparison) {
184
			LocalResourceSaveableComparison rsc = (LocalResourceSaveableComparison) fLeftSaveable;
185
			rsc.dispose();
186
		}
187
		if (fRightSaveable instanceof SaveableComparison) {
188
			SaveableComparison scm = (SaveableComparison) fRightSaveable;
189
			scm.removePropertyListener(fRightPropertyListener);
190
		}
191
		if (fRightSaveable instanceof LocalResourceSaveableComparison) {
192
			LocalResourceSaveableComparison rsc = (LocalResourceSaveableComparison) fRightSaveable;
193
			rsc.dispose();
194
		}
195
196
		if (getCompareResult() instanceof IDisposable) {
197
			((IDisposable) getCompareResult()).dispose();
198
		}
199
	}
200
	
201
	private String[] getLabels() {
202
		IResource leftResource = getResource(fLeftElement);
203
		IResource rightResource = getResource(fRightElement);
204
		if (leftResource != null && rightResource != null) {
205
			String leftLabel = leftResource.getFullPath().makeRelative().toString();
206
			String rightLabel = rightResource.getFullPath().makeRelative().toString();
207
			if (fAncestorElement != null) {
208
				IResource ancestorResource = getResource(fAncestorElement);
209
				if (ancestorResource != null) {
210
					String ancestorLabel = rightResource.getFullPath().makeRelative().toString();
211
					return new String[] { ancestorLabel, leftLabel, rightLabel };
212
				}
213
			}
214
			return new String[] { leftLabel, rightLabel };
215
		}
216
		if (fAncestorElement != null) {
217
			return new String[] { fAncestorElement.getName(), fLeftElement.getName(), fRightElement.getName() };
218
		}
219
		return new String[] { fLeftElement.getName(), fRightElement.getName() };
220
	}
221
	
222
	public String getToolTipText() {
223
		String[] labels = getLabels();
224
		if (labels.length == 3)
225
			return NLS.bind(TeamUIMessages.SaveablesCompareEditorInput_threeWayTooltip, labels);
226
		return NLS.bind(TeamUIMessages.SaveablesCompareEditorInput_twoWayTooltip, labels);
227
	}		
228
229
	public String getTitle() {
230
		String[] labels = getLabels();
231
		if (labels.length == 3)
232
			return NLS.bind(TeamUIMessages.SaveablesCompareEditorInput_threeWayTitle, labels);
233
		return NLS.bind(TeamUIMessages.SaveablesCompareEditorInput_twoWayTitle, labels);
234
	}		
235
236
	private IWorkbenchPage getPage() {
237
		if (page == null)
238
			return PlatformUI.getWorkbench().getActiveWorkbenchWindow()
239
					.getActivePage();
240
		return page;
241
	}
242
243
	/**
244
	 * Return the compare input of this editor input.
245
	 * 
246
	 * @return the compare input of this editor input
247
	 */
248
	protected final ICompareInput getCompareInput() {
249
		return (ICompareInput) getCompareResult();
250
	}
251
252
	/**
253
	 * Callback from the resource saveable that is invoked when the resource is
254
	 * saved so that this input can fire a change event for its input.
255
	 * Subclasses only need this method if the left side of their compare input
256
	 * is an element returned from
257
	 * {@link SaveableCompareEditorInput#createFileElement(IFile)}.
258
	 */
259
	protected void fireInputChange() {
260
		((MyDiffNode) getCompareResult()).fireChange();
261
	}
262
263
	protected Saveable getLeftSaveable() {
264
		if (fLeftSaveable == null) {
265
			fLeftSaveable = createLeftSaveable();
266
		}
267
		return fLeftSaveable;
268
	}
269
270
	protected Saveable getRightSaveable() {
271
		if (fRightSaveable == null) {
272
			fRightSaveable = createRightSaveable();
273
		}
274
		return fRightSaveable;
275
	}
276
277
	protected Saveable createLeftSaveable() {
278
		Object compareResult = getCompareResult();
279
		Assert
280
				.isNotNull(compareResult,
281
						"This method cannot be called until after prepareInput is called"); //$NON-NLS-1$
282
		ITypedElement leftFileElement = getFileElement(getCompareInput()
283
				.getLeft(), this);
284
		return new InternalResourceSaveableComparison(
285
				(ICompareInput) compareResult, this, leftFileElement);
286
	}
287
288
	protected Saveable createRightSaveable() {
289
		Object compareResult = getCompareResult();
290
		Assert
291
				.isNotNull(compareResult,
292
						"This method cannot be called until after prepareInput is called"); //$NON-NLS-1$
293
		ITypedElement rightFileElement = getFileElement(getCompareInput()
294
				.getRight(), this);
295
		return new InternalResourceSaveableComparison(
296
				(ICompareInput) compareResult, this, rightFileElement);
297
	}
298
299
	/*
300
	 * (non-Javadoc)
301
	 * 
302
	 * @see org.eclipse.ui.ISaveablesSource#getActiveSaveables()
303
	 */
304
	public Saveable[] getActiveSaveables() {
305
		if (getCompareResult() == null)
306
			return new Saveable[0];
307
		return new Saveable[] { getLeftSaveable(), getRightSaveable() };
308
	}
309
310
	/*
311
	 * (non-Javadoc)
312
	 * 
313
	 * @see org.eclipse.ui.ISaveablesSource#getSaveables()
314
	 */
315
	public Saveable[] getSaveables() {
316
		return getActiveSaveables();
317
	}
318
319
	/*
320
	 * (non-Javadoc)
321
	 * 
322
	 * @see
323
	 * org.eclipse.compare.CompareEditorInput#findContentViewer(org.eclipse.
324
	 * jface.viewers.Viewer,
325
	 * org.eclipse.compare.structuremergeviewer.ICompareInput,
326
	 * org.eclipse.swt.widgets.Composite)
327
	 */
328
	public Viewer findContentViewer(Viewer pOldViewer, ICompareInput pInput,
329
			Composite pParent) {
330
		Viewer newViewer = super.findContentViewer(pOldViewer, pInput, pParent);
331
		boolean isNewViewer = newViewer != pOldViewer;
332
		if (isNewViewer && newViewer instanceof IPropertyChangeNotifier
333
				&& fLeftSaveable instanceof IPropertyChangeListener
334
				&& fRightSaveable instanceof IPropertyChangeListener) {
335
			// Register the model for change events if appropriate
336
			final IPropertyChangeNotifier dsp = (IPropertyChangeNotifier) newViewer;
337
			final IPropertyChangeListener lpcl = (IPropertyChangeListener) fLeftSaveable;
338
			final IPropertyChangeListener rpcl = (IPropertyChangeListener) fRightSaveable;
339
			dsp.addPropertyChangeListener(lpcl);
340
			dsp.addPropertyChangeListener(rpcl);
341
			Control c = newViewer.getControl();
342
			c.addDisposeListener(new DisposeListener() {
343
				public void widgetDisposed(DisposeEvent e) {
344
					dsp.removePropertyChangeListener(lpcl);
345
					dsp.removePropertyChangeListener(rpcl);
346
				}
347
			});
348
		}
349
		return newViewer;
350
	}
351
352
	public boolean isDirty() {
353
		if (fLeftSaveable != null && fLeftSaveable.isDirty())
354
			return true;
355
		if (fRightSaveable != null && fRightSaveable.isDirty())
356
			return true;
357
		return super.isDirty();
358
	}
359
360
	/**
361
	 * Close the editor if it is not dirty. If it is still dirty, let the
362
	 * content merge viewer handle the compare input change.
363
	 * 
364
	 * @param checkForUnsavedChanges
365
	 *            whether to check for unsaved changes
366
	 * @return <code>true</code> if the editor was closed (note that the close
367
	 *         may be asynchronous)
368
	 */
369
	protected boolean closeEditor(boolean checkForUnsavedChanges) {
370
		if (isSaveNeeded() && checkForUnsavedChanges) {
371
			return false;
372
		} else {
373
			Runnable runnable = new Runnable() {
374
				public void run() {
375
					IEditorPart part = getPage().findEditor(
376
							SaveablesCompareEditorInput.this);
377
					getPage().closeEditor(part, false);
378
				}
379
			};
380
			if (Display.getCurrent() != null) {
381
				runnable.run();
382
			} else {
383
				Display display = getPage().getWorkbenchWindow().getShell()
384
						.getDisplay();
385
				display.asyncExec(runnable);
386
			}
387
			return true;
388
		}
389
	}
390
391
	/**
392
	 * Prepare the compare input of this editor input. This method is not
393
	 * intended to be overridden of extended by subclasses (but is not final for
394
	 * backwards compatibility reasons). The implementation of this method in
395
	 * this class delegates the creation of the compare input to the
396
	 * {@link #prepareCompareInput(IProgressMonitor)} method which subclasses
397
	 * must implement.
398
	 * 
399
	 * @see org.eclipse.compare.CompareEditorInput#prepareInput(org.eclipse.core.runtime.IProgressMonitor)
400
	 */
401
	protected Object prepareInput(IProgressMonitor monitor)
402
			throws InvocationTargetException, InterruptedException {
403
		final ICompareInput input = prepareCompareInput(monitor);
404
		if (input != null)
405
			setTitle(NLS.bind(TeamUIMessages.SyncInfoCompareInput_title,
406
					new String[] { input.getName() }));
407
		return input;
408
	}
409
410
	/**
411
	 * Method called from {@link #prepareInput(IProgressMonitor)} to obtain the
412
	 * input. It's purpose is to ensure that the input is an instance of
413
	 * {@link ICompareInput}.
414
	 * 
415
	 * @param monitor
416
	 *            a progress monitor
417
	 * @return the compare input
418
	 * @throws InvocationTargetException
419
	 * @throws InterruptedException
420
	 */
421
	protected ICompareInput prepareCompareInput(IProgressMonitor monitor)
422
			throws InvocationTargetException, InterruptedException {
423
		ICompareInput input = createCompareInput();
424
		getCompareConfiguration().setLeftEditable(isEditable(input.getLeft()));
425
		getCompareConfiguration()
426
				.setRightEditable(isEditable(input.getRight()));
427
		initLabels();
428
		return input;
429
	}
430
431
	private boolean isEditable(Object obj) {
432
		if (obj instanceof IEditableContent) {
433
			return ((IEditableContent) obj).isEditable();
434
		}
435
		return false;
436
	}
437
438
	private void initLabels() {
439
		CompareConfiguration cc = getCompareConfiguration();
440
441
		IResource ancestorResource = getResource(fAncestorElement);
442
		IResource leftResource = getResource(fLeftElement);
443
		IResource rightResource = getResource(fRightElement);
444
445
		if (ancestorResource != null) {
446
			String ancestorLabel = ancestorResource.getFullPath()
447
					.makeRelative().toString();
448
449
			cc.setAncestorLabel(ancestorLabel);
450
		}
451
452
		if (leftResource != null && rightResource != null) {
453
			String leftLabel = leftResource.getFullPath().makeRelative()
454
					.toString();
455
			String rightLabel = rightResource.getFullPath().makeRelative()
456
					.toString();
457
458
			cc.setLeftLabel(leftLabel);
459
			cc.setRightLabel(rightLabel);
460
		}
461
	}
462
463
	private ICompareInput createCompareInput() {
464
		return fAncestorElement == null ? new MyDiffNode(fLeftElement,
465
				fRightElement) : new MyDiffNode(fAncestorElement, fLeftElement,
466
				fRightElement);
467
	}
468
469
	private CompareInputChangeNotifier notifier = new CompareInputChangeNotifier() {
470
		protected IResource[] getResources(ICompareInput input) {
471
			IResource leftResource = getResource(fLeftElement);
472
			IResource rightResource = getResource(fRightElement);
473
			if (leftResource == null && rightResource == null)
474
				return new IResource[0];
475
			if (leftResource == null && rightResource != null)
476
				return new IResource[] { rightResource };
477
			if (leftResource != null && rightResource == null)
478
				return new IResource[] { leftResource };
479
			return new IResource[] { leftResource, rightResource };
480
		}
481
	};
482
483
	private class MyDiffNode extends AbstractCompareInput {
484
		public MyDiffNode(ITypedElement left, ITypedElement right) {
485
			super(Differencer.CHANGE, null, left, right);
486
		}
487
488
		public MyDiffNode(ITypedElement ancestor, ITypedElement left,
489
				ITypedElement right) {
490
			super(Differencer.CONFLICTING, ancestor, left, right);
491
		}
492
493
		public void fireChange() {
494
			super.fireChange();
495
		}
496
497
		protected CompareInputChangeNotifier getChangeNotifier() {
498
			return notifier;
499
		}
500
501
		public boolean needsUpdate() {
502
			return true;
503
		}
504
505
		public void update() {
506
			fireChange();
507
		}
508
	}
509
510
	private IResource getResource(ITypedElement pElement) {
511
		if (pElement instanceof LocalResourceTypedElement
512
				&& pElement instanceof IResourceProvider) {
513
			return ((IResourceProvider) pElement).getResource();
514
		}
515
		return null;
516
	}
517
518
	public void registerContextMenu(final MenuManager pMenuManager,
519
			final ISelectionProvider pSelectionProvider) {
520
		super.registerContextMenu(pMenuManager, pSelectionProvider);
521
		final Saveable lLeftSaveable = getLeftSaveable();
522
		final ITypedElement lLeftElement = getFileElement(getCompareInput()
523
				.getLeft(), this);
524
		if (lLeftSaveable instanceof LocalResourceSaveableComparison) {
525
			pMenuManager.addMenuListener(new IMenuListener() {
526
				public void menuAboutToShow(IMenuManager manager) {
527
					handleMenuAboutToShow(manager, lLeftSaveable, lLeftElement,
528
							pSelectionProvider);
529
				}
530
			});
531
		}
532
		final Saveable lRightSaveable = getRightSaveable();
533
		final ITypedElement lRightElement = getFileElement(getCompareInput()
534
				.getRight(), this);
535
		if (lRightSaveable instanceof LocalResourceSaveableComparison) {
536
			pMenuManager.addMenuListener(new IMenuListener() {
537
				public void menuAboutToShow(IMenuManager manager) {
538
					handleMenuAboutToShow(manager, lRightSaveable,
539
							lRightElement, pSelectionProvider);
540
				}
541
			});
542
		}
543
	}
544
545
	/*
546
	 * (non-Javadoc)
547
	 * 
548
	 * @see
549
	 * org.eclipse.compare.CompareEditorInput#addCompareInputChangeListener(
550
	 * org.eclipse.compare.structuremergeviewer.ICompareInput,
551
	 * org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener)
552
	 */
553
	public void addCompareInputChangeListener(ICompareInput input,
554
			ICompareInputChangeListener listener) {
555
		if (input == getCompareResult()) {
556
			inputChangeListeners.add(listener);
557
		} else {
558
			super.addCompareInputChangeListener(input, listener);
559
		}
560
	}
561
562
	/*
563
	 * (non-Javadoc)
564
	 * 
565
	 * @see
566
	 * org.eclipse.compare.CompareEditorInput#removeCompareInputChangeListener
567
	 * (org.eclipse.compare.structuremergeviewer.ICompareInput,
568
	 * org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener)
569
	 */
570
	public void removeCompareInputChangeListener(ICompareInput input,
571
			ICompareInputChangeListener listener) {
572
		if (input == getCompareResult()) {
573
			inputChangeListeners.remove(listener);
574
		} else {
575
			super.removeCompareInputChangeListener(input, listener);
576
		}
577
	}
578
579
	private void propogateInputChange() {
580
		if (!inputChangeListeners.isEmpty()) {
581
			Object[] allListeners = inputChangeListeners.getListeners();
582
			final ICompareInput compareResult = (ICompareInput) getCompareResult();
583
			for (int i = 0; i < allListeners.length; i++) {
584
				final ICompareInputChangeListener listener = (ICompareInputChangeListener) allListeners[i];
585
				SafeRunner.run(new ISafeRunnable() {
586
					public void run() throws Exception {
587
						listener.compareInputChanged(compareResult);
588
					}
589
590
					public void handleException(Throwable exception) {
591
						// Logged by the safe runner
592
					}
593
				});
594
			}
595
		}
596
	}
597
598
	/*
599
	 * (non-Javadoc)
600
	 * 
601
	 * @see org.eclipse.compare.CompareEditorInput#getTitleImage()
602
	 */
603
	public Image getTitleImage() {
604
		ImageRegistry reg = TeamUIPlugin.getPlugin().getImageRegistry();
605
		Image image = reg.get(ITeamUIImages.IMG_SYNC_VIEW);
606
		if (image == null) {
607
			image = getImageDescriptor().createImage();
608
			reg.put(ITeamUIImages.IMG_SYNC_VIEW, image);
609
		}
610
		return image;
611
	}
612
613
	/*
614
	 * (non-Javadoc)
615
	 * 
616
	 * @see org.eclipse.ui.IEditorInput#getImageDescriptor()
617
	 */
618
	public ImageDescriptor getImageDescriptor() {
619
		return TeamUIPlugin.getImageDescriptor(ITeamUIImages.IMG_SYNC_VIEW);
620
	}
621
622
	/*
623
	 * (non-Javadoc)
624
	 * 
625
	 * @see org.eclipse.compare.CompareEditorInput#canRunAsJob()
626
	 */
627
	public boolean canRunAsJob() {
628
		return true;
629
	}
630
631
	private void handleMenuAboutToShow(IMenuManager manager, Saveable saveable,
632
			ITypedElement element, ISelectionProvider provider) {
633
		if (provider instanceof ITextViewer) {
634
			ITextViewer v = (ITextViewer) provider;
635
			IDocument d = v.getDocument();
636
			IDocument other = (IDocument) Utils.getAdapter(saveable,
637
					IDocument.class);
638
			if (d == other) {
639
				if (element instanceof IResourceProvider) {
640
					IResourceProvider rp = (IResourceProvider) element;
641
					IResource resource = rp.getResource();
642
					StructuredSelection selection = new StructuredSelection(
643
							resource);
644
					IWorkbenchPart workbenchPart = getContainer()
645
							.getWorkbenchPart();
646
					if (workbenchPart != null) {
647
						IWorkbenchSite ws = workbenchPart.getSite();
648
						MenuManager submenu1 = new MenuManager(
649
								getShowInMenuLabel());
650
						IContributionItem showInMenu = ContributionItemFactory.VIEWS_SHOW_IN
651
								.create(ws.getWorkbenchWindow());
652
						submenu1.add(showInMenu);
653
						manager.insertAfter("file", submenu1); //$NON-NLS-1$
654
						MenuManager submenu2 = new MenuManager(
655
								TeamUIMessages.OpenWithActionGroup_0);
656
						submenu2.add(new OpenWithMenu(ws.getPage(), resource));
657
						manager.insertAfter("file", submenu2); //$NON-NLS-1$
658
659
						OpenFileAction openFileAction = new OpenFileAction(ws
660
								.getPage());
661
						openFileAction.selectionChanged(selection);
662
						manager.insertAfter("file", openFileAction); //$NON-NLS-1$
663
					}
664
				}
665
			}
666
		}
667
	}
668
669
	private String getShowInMenuLabel() {
670
		String keyBinding = null;
671
672
		IBindingService bindingService = (IBindingService) PlatformUI
673
				.getWorkbench().getAdapter(IBindingService.class);
674
		if (bindingService != null)
675
			keyBinding = bindingService
676
					.getBestActiveBindingFormattedFor("org.eclipse.ui.navigate.showInQuickMenu"); //$NON-NLS-1$
677
678
		if (keyBinding == null)
679
			keyBinding = ""; //$NON-NLS-1$
680
681
		return NLS
682
				.bind(TeamUIMessages.SaveableCompareEditorInput_0, keyBinding);
683
	}
684
685
	// TODO: add getAdapter for IFile[]
686
687
	private class InternalResourceSaveableComparison extends
688
			LocalResourceSaveableComparison implements
689
			ISharedDocumentAdapterListener {
690
		private LocalResourceTypedElement lrte;
691
		private boolean connected = false;
692
693
		public InternalResourceSaveableComparison(ICompareInput input,
694
				CompareEditorInput editorInput, ITypedElement element) {
695
			super(input, editorInput, element);
696
			if (element instanceof LocalResourceTypedElement) {
697
				lrte = (LocalResourceTypedElement) element;
698
				if (lrte.isConnected()) {
699
					registerSaveable(true);
700
				} else {
701
					lrte.setSharedDocumentListener(this);
702
				}
703
			}
704
		}
705
706
		protected void fireInputChange() {
707
			SaveablesCompareEditorInput.this.fireInputChange();
708
		}
709
710
		public void dispose() {
711
			super.dispose();
712
			if (lrte != null)
713
				lrte.setSharedDocumentListener(null);
714
		}
715
716
		public void handleDocumentConnected() {
717
			if (connected)
718
				return;
719
			connected = true;
720
			registerSaveable(false);
721
			if (lrte != null)
722
				lrte.setSharedDocumentListener(null);
723
		}
724
725
		private void registerSaveable(boolean init) {
726
			ICompareContainer container = getContainer();
727
			IWorkbenchPart part = container.getWorkbenchPart();
728
			if (part != null) {
729
				ISaveablesLifecycleListener lifecycleListener = getSaveablesLifecycleListener(part);
730
				// Remove this saveable from the lifecycle listener
731
				if (!init)
732
					lifecycleListener
733
							.handleLifecycleEvent(new SaveablesLifecycleEvent(
734
									part, SaveablesLifecycleEvent.POST_CLOSE,
735
									new Saveable[] { this }, false));
736
				// Now fix the hashing so it uses the connected document
737
				initializeHashing();
738
				// Finally, add this saveable back to the listener
739
				lifecycleListener
740
						.handleLifecycleEvent(new SaveablesLifecycleEvent(part,
741
								SaveablesLifecycleEvent.POST_OPEN,
742
								new Saveable[] { this }, false));
743
			}
744
		}
745
746
		public void handleDocumentDeleted() {
747
			// Ignore
748
		}
749
750
		public void handleDocumentDisconnected() {
751
			// Ignore
752
		}
753
754
		public void handleDocumentFlushed() {
755
			// Ignore
756
		}
757
758
		public void handleDocumentSaved() {
759
			// Ignore
760
		}
761
762
		/*
763
		 * @see org.eclipse.ui.Saveable#equals(java.lang.Object)
764
		 */
765
		public boolean equals(Object obj) {
766
			if (this == obj)
767
				return true;
768
769
			if (!(obj instanceof Saveable))
770
				return false;
771
			
772
			Object document = getAdapter(IDocument.class);
773
			
774
			if (document != null) {
775
				Object otherDocument = ((Saveable) obj)
776
						.getAdapter(IDocument.class);
777
778
				if (document == null && otherDocument == null)
779
					return false;
780
781
				return document != null && document.equals(otherDocument);
782
			}
783
784
			if (obj instanceof InternalResourceSaveableComparison) {
785
				InternalResourceSaveableComparison rscm = (InternalResourceSaveableComparison) obj;
786
				return rscm.getInput().equals(getInput()) && rscm.lrte.equals(lrte);
787
			}
788
			return false;
789
		}
790
	}
791
}
(-)src/org/eclipse/team/internal/ui/actions/CompareAction.java (+153 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.team.internal.ui.actions;
12
13
import java.lang.reflect.InvocationTargetException;
14
15
import org.eclipse.compare.*;
16
import org.eclipse.core.resources.IFile;
17
import org.eclipse.core.resources.IResource;
18
import org.eclipse.jface.action.IAction;
19
import org.eclipse.jface.dialogs.IDialogConstants;
20
import org.eclipse.jface.dialogs.MessageDialog;
21
import org.eclipse.jface.window.Window;
22
import org.eclipse.osgi.util.NLS;
23
import org.eclipse.swt.SWT;
24
import org.eclipse.swt.events.*;
25
import org.eclipse.swt.layout.GridLayout;
26
import org.eclipse.swt.widgets.*;
27
import org.eclipse.team.internal.ui.TeamUIMessages;
28
import org.eclipse.team.internal.ui.synchronize.SaveablesCompareEditorInput;
29
import org.eclipse.ui.*;
30
31
public class CompareAction extends TeamAction {
32
33
	protected void execute(IAction action) throws InvocationTargetException,
34
			InterruptedException {
35
36
		IResource[] selectedResources = getSelectedResources();
37
38
		ITypedElement ancestor = null;
39
		ITypedElement left = null;
40
		ITypedElement right = null;
41
42
		if (selectedResources.length == 2) {
43
			if (selectedResources[0] != null)
44
				left = getElementFor(selectedResources[0]);
45
46
			if (selectedResources[1] != null)
47
				right = getElementFor(selectedResources[1]);
48
49
		} else if (selectedResources.length == 3) {
50
			// prompt for ancestor
51
			SelectAncestorDialog dialog = new SelectAncestorDialog(getShell(),
52
					selectedResources);
53
			int code = dialog.open();
54
			if (code == Window.CANCEL)
55
				return;
56
57
			ancestor = getElementFor(dialog.ancestorResource);
58
			left = getElementFor(dialog.leftResource);
59
			right = getElementFor(dialog.rightResource);
60
		} else {
61
			return;
62
		}
63
		openInCompare(ancestor, left, right);
64
	}
65
66
	private void openInCompare(ITypedElement ancestor, ITypedElement left,
67
			ITypedElement right) {
68
		IWorkbenchPage workBenchPage = getTargetPage();
69
		CompareEditorInput input = new SaveablesCompareEditorInput(ancestor,
70
				left, right, workBenchPage);
71
		IEditorPart editor = CompareRevisionAction.findReusableCompareEditor(
72
				input, workBenchPage);
73
		if (editor != null) {
74
			IEditorInput otherInput = editor.getEditorInput();
75
			if (otherInput.equals(input)) {
76
				// simply provide focus to editor
77
				workBenchPage.activate(editor);
78
			} else {
79
				// if editor is currently not open on that input either re-use
80
				// existing
81
				CompareUI.reuseCompareEditor(input, (IReusableEditor) editor);
82
				workBenchPage.activate(editor);
83
			}
84
		} else {
85
			CompareUI.openCompareEditor(input);
86
		}
87
	}
88
89
	public boolean isEnabled() {
90
		int l = getSelectedResources().length;
91
		return l == 2 || l == 3;
92
	}
93
94
	private ITypedElement getElementFor(IResource resource) {
95
		return SaveablesCompareEditorInput.createFileElement((IFile) resource);
96
	}
97
98
	// see
99
	// org.eclipse.compare.internal.ResourceCompareInput.SelectAncestorDialog
100
	private class SelectAncestorDialog extends MessageDialog {
101
		private IResource[] theResources;
102
		IResource ancestorResource;
103
		IResource leftResource;
104
		IResource rightResource;
105
106
		private Button[] buttons;
107
108
		public SelectAncestorDialog(Shell parentShell, IResource[] theResources) {
109
			super(parentShell, TeamUIMessages.SelectAncestorDialog_title, null,
110
					TeamUIMessages.SelectAncestorDialog_message,
111
					MessageDialog.QUESTION, new String[] {
112
							IDialogConstants.OK_LABEL,
113
							IDialogConstants.CANCEL_LABEL }, 0);
114
			this.theResources = theResources;
115
		}
116
117
		protected Control createCustomArea(Composite parent) {
118
			Composite composite = new Composite(parent, SWT.NONE);
119
			composite.setLayout(new GridLayout());
120
			buttons = new Button[3];
121
			for (int i = 0; i < 3; i++) {
122
				buttons[i] = new Button(composite, SWT.RADIO);
123
				buttons[i].addSelectionListener(selectionListener);
124
				buttons[i].setText(NLS.bind(
125
						TeamUIMessages.SelectAncestorDialog_option,
126
						theResources[i].getFullPath().toPortableString()));
127
				buttons[i].setFont(parent.getFont());
128
				// set initial state
129
				buttons[i].setSelection(i == 0);
130
			}
131
			pickAncestor(0);
132
			return composite;
133
		}
134
135
		private void pickAncestor(int i) {
136
			ancestorResource = theResources[i];
137
			leftResource = theResources[i == 0 ? 1 : 0];
138
			rightResource = theResources[i == 2 ? 1 : 2];
139
		}
140
141
		private SelectionListener selectionListener = new SelectionAdapter() {
142
			public void widgetSelected(SelectionEvent e) {
143
				Button selectedButton = (Button) e.widget;
144
				if (!selectedButton.getSelection())
145
					return;
146
				for (int i = 0; i < 3; i++)
147
					if (selectedButton == buttons[i])
148
						pickAncestor(i);
149
			}
150
		};
151
	}
152
153
}

Return to bug 193324