### Eclipse Workspace Patch 1.0 #P org.eclipse.team.ui Index: plugin.properties =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.team.ui/plugin.properties,v retrieving revision 1.75 diff -u -r1.75 plugin.properties --- plugin.properties 3 Jun 2008 13:35:37 -0000 1.75 +++ plugin.properties 27 Nov 2008 11:33:56 -0000 @@ -74,5 +74,7 @@ CompareLocalHistory.tooltip= Compare the Selected Resource with Local History ReplaceLocalHistory.label= &Local History... ReplaceLocalHistory.tooltip= Replace the Selected Resource with Local History +CompareWithEachOtherAction.label= &Each Other +CompareWithEachOtherAction.tooltip= Compare the Selected Resources ignoresTransferName= Team Ignored Resources Transfer Index: plugin.xml =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.team.ui/plugin.xml,v retrieving revision 1.196 diff -u -r1.196 plugin.xml --- plugin.xml 17 Apr 2008 15:31:56 -0000 1.196 +++ plugin.xml 27 Nov 2008 11:33:56 -0000 @@ -154,6 +154,15 @@ enablesFor="1" overrideActionId="replaceFromHistory" tooltip="%ReplaceLocalHistory.tooltip"/> + + true if the editor was closed (note that the close + * may be asynchronous) + */ + protected boolean closeEditor(boolean checkForUnsavedChanges) { + if (isSaveNeeded() && checkForUnsavedChanges) { + return false; + } else { + Runnable runnable = new Runnable() { + public void run() { + IEditorPart part = getPage().findEditor( + SaveablesCompareEditorInput.this); + getPage().closeEditor(part, false); + } + }; + if (Display.getCurrent() != null) { + runnable.run(); + } else { + Display display = getPage().getWorkbenchWindow().getShell() + .getDisplay(); + display.asyncExec(runnable); + } + return true; + } + } + + /** + * Prepare the compare input of this editor input. This method is not + * intended to be overridden of extended by subclasses (but is not final for + * backwards compatibility reasons). The implementation of this method in + * this class delegates the creation of the compare input to the + * {@link #prepareCompareInput(IProgressMonitor)} method which subclasses + * must implement. + * + * @see org.eclipse.compare.CompareEditorInput#prepareInput(org.eclipse.core.runtime.IProgressMonitor) + */ + protected Object prepareInput(IProgressMonitor monitor) + throws InvocationTargetException, InterruptedException { + final ICompareInput input = prepareCompareInput(monitor); + if (input != null) + setTitle(NLS.bind(TeamUIMessages.SyncInfoCompareInput_title, + new String[] { input.getName() })); + return input; + } + + /** + * Method called from {@link #prepareInput(IProgressMonitor)} to obtain the + * input. It's purpose is to ensure that the input is an instance of + * {@link ICompareInput}. + * + * @param monitor + * a progress monitor + * @return the compare input + * @throws InvocationTargetException + * @throws InterruptedException + */ + protected ICompareInput prepareCompareInput(IProgressMonitor monitor) + throws InvocationTargetException, InterruptedException { + ICompareInput input = createCompareInput(); + getCompareConfiguration().setLeftEditable(isEditable(input.getLeft())); + getCompareConfiguration() + .setRightEditable(isEditable(input.getRight())); + initLabels(); + return input; + } + + private boolean isEditable(Object obj) { + if (obj instanceof IEditableContent) { + return ((IEditableContent) obj).isEditable(); + } + return false; + } + + private void initLabels() { + CompareConfiguration cc = getCompareConfiguration(); + + IResource ancestorResource = getResource(fAncestorElement); + IResource leftResource = getResource(fLeftElement); + IResource rightResource = getResource(fRightElement); + + if (ancestorResource != null) { + String ancestorLabel = ancestorResource.getFullPath() + .makeRelative().toString(); + + cc.setAncestorLabel(ancestorLabel); + } + + if (leftResource != null && rightResource != null) { + String leftLabel = leftResource.getFullPath().makeRelative() + .toString(); + String rightLabel = rightResource.getFullPath().makeRelative() + .toString(); + + cc.setLeftLabel(leftLabel); + cc.setRightLabel(rightLabel); + } + } + + private ICompareInput createCompareInput() { + return fAncestorElement == null ? new MyDiffNode(fLeftElement, + fRightElement) : new MyDiffNode(fAncestorElement, fLeftElement, + fRightElement); + } + + private CompareInputChangeNotifier notifier = new CompareInputChangeNotifier() { + protected IResource[] getResources(ICompareInput input) { + IResource leftResource = getResource(fLeftElement); + IResource rightResource = getResource(fRightElement); + if (leftResource == null && rightResource == null) + return new IResource[0]; + if (leftResource == null && rightResource != null) + return new IResource[] { rightResource }; + if (leftResource != null && rightResource == null) + return new IResource[] { leftResource }; + return new IResource[] { leftResource, rightResource }; + } + }; + + private class MyDiffNode extends AbstractCompareInput { + public MyDiffNode(ITypedElement left, ITypedElement right) { + super(Differencer.CHANGE, null, left, right); + } + + public MyDiffNode(ITypedElement ancestor, ITypedElement left, + ITypedElement right) { + super(Differencer.CONFLICTING, ancestor, left, right); + } + + public void fireChange() { + super.fireChange(); + } + + protected CompareInputChangeNotifier getChangeNotifier() { + return notifier; + } + + public boolean needsUpdate() { + return true; + } + + public void update() { + fireChange(); + } + } + + private IResource getResource(ITypedElement pElement) { + if (pElement instanceof LocalResourceTypedElement + && pElement instanceof IResourceProvider) { + return ((IResourceProvider) pElement).getResource(); + } + return null; + } + + public void registerContextMenu(final MenuManager pMenuManager, + final ISelectionProvider pSelectionProvider) { + super.registerContextMenu(pMenuManager, pSelectionProvider); + final Saveable lLeftSaveable = getLeftSaveable(); + final ITypedElement lLeftElement = getFileElement(getCompareInput() + .getLeft(), this); + if (lLeftSaveable instanceof LocalResourceSaveableComparison) { + pMenuManager.addMenuListener(new IMenuListener() { + public void menuAboutToShow(IMenuManager manager) { + handleMenuAboutToShow(manager, lLeftSaveable, lLeftElement, + pSelectionProvider); + } + }); + } + final Saveable lRightSaveable = getRightSaveable(); + final ITypedElement lRightElement = getFileElement(getCompareInput() + .getRight(), this); + if (lRightSaveable instanceof LocalResourceSaveableComparison) { + pMenuManager.addMenuListener(new IMenuListener() { + public void menuAboutToShow(IMenuManager manager) { + handleMenuAboutToShow(manager, lRightSaveable, + lRightElement, pSelectionProvider); + } + }); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.compare.CompareEditorInput#addCompareInputChangeListener( + * org.eclipse.compare.structuremergeviewer.ICompareInput, + * org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener) + */ + public void addCompareInputChangeListener(ICompareInput input, + ICompareInputChangeListener listener) { + if (input == getCompareResult()) { + inputChangeListeners.add(listener); + } else { + super.addCompareInputChangeListener(input, listener); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.compare.CompareEditorInput#removeCompareInputChangeListener + * (org.eclipse.compare.structuremergeviewer.ICompareInput, + * org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener) + */ + public void removeCompareInputChangeListener(ICompareInput input, + ICompareInputChangeListener listener) { + if (input == getCompareResult()) { + inputChangeListeners.remove(listener); + } else { + super.removeCompareInputChangeListener(input, listener); + } + } + + private void propogateInputChange() { + if (!inputChangeListeners.isEmpty()) { + Object[] allListeners = inputChangeListeners.getListeners(); + final ICompareInput compareResult = (ICompareInput) getCompareResult(); + for (int i = 0; i < allListeners.length; i++) { + final ICompareInputChangeListener listener = (ICompareInputChangeListener) allListeners[i]; + SafeRunner.run(new ISafeRunnable() { + public void run() throws Exception { + listener.compareInputChanged(compareResult); + } + + public void handleException(Throwable exception) { + // Logged by the safe runner + } + }); + } + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.compare.CompareEditorInput#getTitleImage() + */ + public Image getTitleImage() { + ImageRegistry reg = TeamUIPlugin.getPlugin().getImageRegistry(); + Image image = reg.get(ITeamUIImages.IMG_SYNC_VIEW); + if (image == null) { + image = getImageDescriptor().createImage(); + reg.put(ITeamUIImages.IMG_SYNC_VIEW, image); + } + return image; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.IEditorInput#getImageDescriptor() + */ + public ImageDescriptor getImageDescriptor() { + return TeamUIPlugin.getImageDescriptor(ITeamUIImages.IMG_SYNC_VIEW); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.compare.CompareEditorInput#canRunAsJob() + */ + public boolean canRunAsJob() { + return true; + } + + private void handleMenuAboutToShow(IMenuManager manager, Saveable saveable, + ITypedElement element, ISelectionProvider provider) { + if (provider instanceof ITextViewer) { + ITextViewer v = (ITextViewer) provider; + IDocument d = v.getDocument(); + IDocument other = (IDocument) Utils.getAdapter(saveable, + IDocument.class); + if (d == other) { + if (element instanceof IResourceProvider) { + IResourceProvider rp = (IResourceProvider) element; + IResource resource = rp.getResource(); + StructuredSelection selection = new StructuredSelection( + resource); + IWorkbenchPart workbenchPart = getContainer() + .getWorkbenchPart(); + if (workbenchPart != null) { + IWorkbenchSite ws = workbenchPart.getSite(); + MenuManager submenu1 = new MenuManager( + getShowInMenuLabel()); + IContributionItem showInMenu = ContributionItemFactory.VIEWS_SHOW_IN + .create(ws.getWorkbenchWindow()); + submenu1.add(showInMenu); + manager.insertAfter("file", submenu1); //$NON-NLS-1$ + MenuManager submenu2 = new MenuManager( + TeamUIMessages.OpenWithActionGroup_0); + submenu2.add(new OpenWithMenu(ws.getPage(), resource)); + manager.insertAfter("file", submenu2); //$NON-NLS-1$ + + OpenFileAction openFileAction = new OpenFileAction(ws + .getPage()); + openFileAction.selectionChanged(selection); + manager.insertAfter("file", openFileAction); //$NON-NLS-1$ + } + } + } + } + } + + private String getShowInMenuLabel() { + String keyBinding = null; + + IBindingService bindingService = (IBindingService) PlatformUI + .getWorkbench().getAdapter(IBindingService.class); + if (bindingService != null) + keyBinding = bindingService + .getBestActiveBindingFormattedFor("org.eclipse.ui.navigate.showInQuickMenu"); //$NON-NLS-1$ + + if (keyBinding == null) + keyBinding = ""; //$NON-NLS-1$ + + return NLS + .bind(TeamUIMessages.SaveableCompareEditorInput_0, keyBinding); + } + + // TODO: add getAdapter for IFile[] + + private class InternalResourceSaveableComparison extends + LocalResourceSaveableComparison implements + ISharedDocumentAdapterListener { + private LocalResourceTypedElement lrte; + private boolean connected = false; + + public InternalResourceSaveableComparison(ICompareInput input, + CompareEditorInput editorInput, ITypedElement element) { + super(input, editorInput, element); + if (element instanceof LocalResourceTypedElement) { + lrte = (LocalResourceTypedElement) element; + if (lrte.isConnected()) { + registerSaveable(true); + } else { + lrte.setSharedDocumentListener(this); + } + } + } + + protected void fireInputChange() { + SaveablesCompareEditorInput.this.fireInputChange(); + } + + public void dispose() { + super.dispose(); + if (lrte != null) + lrte.setSharedDocumentListener(null); + } + + public void handleDocumentConnected() { + if (connected) + return; + connected = true; + registerSaveable(false); + if (lrte != null) + lrte.setSharedDocumentListener(null); + } + + private void registerSaveable(boolean init) { + ICompareContainer container = getContainer(); + IWorkbenchPart part = container.getWorkbenchPart(); + if (part != null) { + ISaveablesLifecycleListener lifecycleListener = getSaveablesLifecycleListener(part); + // Remove this saveable from the lifecycle listener + if (!init) + lifecycleListener + .handleLifecycleEvent(new SaveablesLifecycleEvent( + part, SaveablesLifecycleEvent.POST_CLOSE, + new Saveable[] { this }, false)); + // Now fix the hashing so it uses the connected document + initializeHashing(); + // Finally, add this saveable back to the listener + lifecycleListener + .handleLifecycleEvent(new SaveablesLifecycleEvent(part, + SaveablesLifecycleEvent.POST_OPEN, + new Saveable[] { this }, false)); + } + } + + public void handleDocumentDeleted() { + // Ignore + } + + public void handleDocumentDisconnected() { + // Ignore + } + + public void handleDocumentFlushed() { + // Ignore + } + + public void handleDocumentSaved() { + // Ignore + } + + /* + * @see org.eclipse.ui.Saveable#equals(java.lang.Object) + */ + public boolean equals(Object obj) { + if (this == obj) + return true; + + if (!(obj instanceof Saveable)) + return false; + + if (document != null) { + Object otherDocument = ((Saveable) obj) + .getAdapter(IDocument.class); + + if (document == null && otherDocument == null) + return false; + + return document != null && document.equals(otherDocument); + } + + if (obj instanceof InternalResourceSaveableComparison) { + InternalResourceSaveableComparison rscm = (InternalResourceSaveableComparison) obj; + return rscm.input.equals(input) && rscm.lrte.equals(lrte); + } + return false; + } + } +} Index: src/org/eclipse/team/internal/ui/actions/CompareAction.java =================================================================== RCS file: src/org/eclipse/team/internal/ui/actions/CompareAction.java diff -N src/org/eclipse/team/internal/ui/actions/CompareAction.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/team/internal/ui/actions/CompareAction.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,155 @@ +/******************************************************************************* + * Copyright (c) 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.team.internal.ui.actions; + +import java.lang.reflect.InvocationTargetException; + +import org.eclipse.compare.*; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.window.Window; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.*; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.*; +import org.eclipse.team.internal.ui.TeamUIMessages; +import org.eclipse.team.internal.ui.synchronize.SaveablesCompareEditorInput; +import org.eclipse.ui.*; + +public class CompareAction extends TeamAction { + + protected void execute(IAction action) throws InvocationTargetException, + InterruptedException { + + IResource[] selectedResources = getSelectedResources(); + + ITypedElement ancestor = null; + ITypedElement left = null; + ITypedElement right = null; + + if (selectedResources.length == 2) { + if (selectedResources[0] != null) + left = getElementFor(selectedResources[0]); + + if (selectedResources[1] != null) + right = getElementFor(selectedResources[1]); + + } else if (selectedResources.length == 3) { + // prompt for ancestor + SelectAncestorDialog dialog = new SelectAncestorDialog(getShell(), + selectedResources); + int code = dialog.open(); + if (code == Window.CANCEL) + return; + + ancestor = getElementFor(dialog.ancestorResource); + left = getElementFor(dialog.leftResource); + right = getElementFor(dialog.rightResource); + } else { + return; + } + openInCompare(ancestor, left, right); + } + + // XXX: from CompareRevisionAction* + private void openInCompare(ITypedElement ancestor, ITypedElement left, + ITypedElement right) { + IWorkbenchPage workBenchPage = getTargetPage(); + CompareEditorInput input = new SaveablesCompareEditorInput(ancestor, + left, right, workBenchPage); + IEditorPart editor = CompareRevisionAction.findReusableCompareEditor( + input, workBenchPage); + if (editor != null) { + IEditorInput otherInput = editor.getEditorInput(); + if (otherInput.equals(input)) { + // simply provide focus to editor + workBenchPage.activate(editor); + } else { + // if editor is currently not open on that input either re-use + // existing + CompareUI.reuseCompareEditor(input, (IReusableEditor) editor); + workBenchPage.activate(editor); + } + } else { + CompareUI.openCompareEditor(input); + } + } + + public boolean isEnabled() { + int l = getSelectedResources().length; + return l == 2 || l == 3; + } + + // XXX: from CompareRevisionAction + private ITypedElement getElementFor(IResource resource) { + return SaveablesCompareEditorInput.createFileElement((IFile) resource); + } + + // see + // org.eclipse.compare.internal.ResourceCompareInput.SelectAncestorDialog + private class SelectAncestorDialog extends MessageDialog { + private IResource[] theResources; + IResource ancestorResource; + IResource leftResource; + IResource rightResource; + + private Button[] buttons; + + public SelectAncestorDialog(Shell parentShell, IResource[] theResources) { + super(parentShell, TeamUIMessages.SelectAncestorDialog_title, null, + TeamUIMessages.SelectAncestorDialog_message, + MessageDialog.QUESTION, new String[] { + IDialogConstants.OK_LABEL, + IDialogConstants.CANCEL_LABEL }, 0); + this.theResources = theResources; + } + + protected Control createCustomArea(Composite parent) { + Composite composite = new Composite(parent, SWT.NONE); + composite.setLayout(new GridLayout()); + buttons = new Button[3]; + for (int i = 0; i < 3; i++) { + buttons[i] = new Button(composite, SWT.RADIO); + buttons[i].addSelectionListener(selectionListener); + buttons[i].setText(NLS.bind( + TeamUIMessages.SelectAncestorDialog_option, + theResources[i].getFullPath().toPortableString())); + buttons[i].setFont(parent.getFont()); + // set initial state + buttons[i].setSelection(i == 0); + } + pickAncestor(0); + return composite; + } + + private void pickAncestor(int i) { + ancestorResource = theResources[i]; + leftResource = theResources[i == 0 ? 1 : 0]; + rightResource = theResources[i == 2 ? 1 : 2]; + } + + private SelectionListener selectionListener = new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + Button selectedButton = (Button) e.widget; + if (!selectedButton.getSelection()) + return; + for (int i = 0; i < 3; i++) + if (selectedButton == buttons[i]) + pickAncestor(i); + } + }; + } + +}