/******************************************************************************* * Copyright (c) 2000, 2017 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.ui.synchronize; import java.lang.reflect.InvocationTargetException; import org.eclipse.compare.*; import org.eclipse.compare.structuremergeviewer.ICompareInput; import org.eclipse.compare.structuremergeviewer.IDiffContainer; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.*; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.osgi.util.NLS; import org.eclipse.team.core.TeamException; import org.eclipse.team.core.synchronize.SyncInfo; import org.eclipse.team.internal.ui.*; import org.eclipse.team.internal.ui.synchronize.SyncInfoModelElement; import org.eclipse.team.internal.ui.synchronize.SynchronizePageConfiguration; import org.eclipse.ui.progress.UIJob; /** * A {@link SyncInfo} editor input used as input to a two-way or three-way * compare viewer. It defines methods for accessing the three sides for the * compare, and a name and image which is used when displaying the three way input * in an editor. This input can alternately be used to show compare results in * a dialog by calling {@link CompareUI#openCompareDialog(org.eclipse.compare.CompareEditorInput)}. *

* The editor will not update when the elements in the sync info are changed. *

*

* Supports saving the local resource that is changed in the editor and will be updated * when the local resources is changed. *

* @see SyncInfo * @since 3.0 */ public final class SyncInfoCompareInput extends SaveableCompareEditorInput implements IResourceChangeListener { private MyDiffNode node; private String description; private IResource resource; private ISynchronizeParticipant participant; private ISynchronizePageConfiguration synchronizeConfiguration; /* * This class exists so that we can force the text merge viewers to update by * calling #fireChange when we save the compare input to disk. The side * effect is that the compare viewers will be updated to reflect the new changes * that have been made. Compare doesn't do this by default. */ private static class MyDiffNode extends SyncInfoModelElement { public MyDiffNode(IDiffContainer parent, SyncInfo info) { super(parent, info); } @Override public void fireChange() { super.fireChange(); } } /** * Creates a compare editor input based on an existing SyncInfo. * * @param description a description of the context of this sync info. This * is displayed to the user. * @param sync the SyncInfo used as the base for the compare input. */ public SyncInfoCompareInput(String description, SyncInfo sync) { super(getDefaultCompareConfiguration(), null); Assert.isNotNull(sync); Assert.isNotNull(description); this.description = description; this.resource = sync.getLocal(); this.node = new MyDiffNode(null, sync); setTitle(NLS.bind(TeamUIMessages.SyncInfoCompareInput_title, new String[] { sync.getLocal().getName() })); } /** * Creates a compare editor input based on an existing SyncInfo * from the given participant. * * @param participant the participant from which the sync info was obtained. The * name of the participant is used as the description which is displayed to the user. * @param sync the SyncInfo used as the base for the compare input. * * @since 3.1 */ public SyncInfoCompareInput(ISynchronizeParticipant participant, SyncInfo sync) { this(participant.getName(), sync); this.participant = participant; } public SyncInfoCompareInput(ISynchronizePageConfiguration configuration, SyncInfo info) { this(configuration.getParticipant(), info); this.synchronizeConfiguration = configuration; } @Override protected void handleDispose() { super.handleDispose(); if (synchronizeConfiguration != null) { ICompareNavigator navigator = (ICompareNavigator)synchronizeConfiguration.getProperty(SynchronizePageConfiguration.P_INPUT_NAVIGATOR); if (navigator != null && navigator == super.getNavigator()) { synchronizeConfiguration.setProperty(SynchronizePageConfiguration.P_INPUT_NAVIGATOR, new CompareNavigator() { @Override protected INavigatable[] getNavigatables() { return new INavigatable[0]; } }); } } } @SuppressWarnings("unchecked") @Override public T getAdapter(Class adapter) { if (IFile.class.equals(adapter) && resource.getType() == IResource.FILE) { return (T) resource; } return super.getAdapter(adapter); } private static CompareConfiguration getDefaultCompareConfiguration() { CompareConfiguration cc = new CompareConfiguration(); //cc.setProperty(CompareConfiguration.USE_OUTLINE_VIEW, true); return cc; } /** * Note that until the compare editor inputs can be part of the compare editors lifecycle we * can't register as a listener because there is no dispose() method to remove the listener. */ @Override public void resourceChanged(IResourceChangeEvent event) { IResourceDelta delta = event.getDelta(); if (delta != null) { IResourceDelta resourceDelta = delta.findMember(resource.getFullPath()); if (resourceDelta != null) { UIJob job = new UIJob("") { //$NON-NLS-1$ @Override public IStatus runInUIThread(IProgressMonitor monitor) { if (!isSaveNeeded()) { //updateNode(); } return Status.OK_STATUS; } }; job.setSystem(true); job.schedule(); } } } @Override protected ICompareInput prepareCompareInput(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { // update the title now that the remote revision number as been fetched // from the server setTitle(getTitle()); monitor.beginTask(TeamUIMessages.SyncInfoCompareInput_3, 100); monitor.setTaskName(TeamUIMessages.SyncInfoCompareInput_3); try { if (participant != null) { participant.prepareCompareInput(node, getCompareConfiguration(), Policy.subMonitorFor(monitor, 100)); } else { Utils.updateLabels(node.getSyncInfo(), getCompareConfiguration(), monitor); node.cacheContents(Policy.subMonitorFor(monitor, 100)); } } catch (TeamException e) { throw new InvocationTargetException(e); } finally { monitor.done(); } return node; } @Override public String getToolTipText() { return NLS.bind(TeamUIMessages.SyncInfoCompareInput_tooltip, new String[] { Utils.shortenText(30, description), node.getResource().getFullPath().toString() }); } @Override public boolean equals(Object other) { if (other == this) return true; if (other instanceof SyncInfoCompareInput) { SyncInfo otherSyncInfo = ((SyncInfoCompareInput) other).getSyncInfo(); SyncInfo thisSyncInfo = getSyncInfo(); // Consider the inputs equal if the sync info are equal and the // left nodes are equal (i.e they have the same timestamp) return thisSyncInfo.equals(otherSyncInfo) && node.getLeft().equals(((SyncInfoCompareInput) other).node.getLeft()); } return false; } @Override public int hashCode() { return getSyncInfo().hashCode(); } public SyncInfo getSyncInfo() { return node.getSyncInfo(); } @Override public boolean canRunAsJob() { return true; } @Override public synchronized ICompareNavigator getNavigator() { if (synchronizeConfiguration != null && isSelectedInSynchronizeView()) { ICompareNavigator nav = (ICompareNavigator)synchronizeConfiguration.getProperty(SynchronizePageConfiguration.P_NAVIGATOR); synchronizeConfiguration.setProperty(SynchronizePageConfiguration.P_INPUT_NAVIGATOR, super.getNavigator()); return nav; } return super.getNavigator(); } private boolean isSelectedInSynchronizeView() { if (synchronizeConfiguration != null) { ISelection s = synchronizeConfiguration.getSite().getSelectionProvider().getSelection(); if (s instanceof IStructuredSelection) { IStructuredSelection ss = (IStructuredSelection) s; Object element = ss.getFirstElement(); if (element instanceof SyncInfoModelElement) { SyncInfoModelElement sime = (SyncInfoModelElement) element; return sime.getSyncInfo().getLocal().equals(resource); } } } return false; } @Override protected void fireInputChange() { node.fireChange(); } }