blob: d6bfe1d03b4d3b79f5289990c4db7fa72c741d29 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2005 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.ccvs.ui;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import org.eclipse.compare.CompareConfiguration;
import org.eclipse.compare.CompareEditorInput;
import org.eclipse.compare.CompareUI;
import org.eclipse.compare.ITypedElement;
import org.eclipse.compare.ResourceNode;
import org.eclipse.compare.structuremergeviewer.DiffContainer;
import org.eclipse.compare.structuremergeviewer.DiffNode;
import org.eclipse.compare.structuremergeviewer.Differencer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.team.core.TeamException;
import org.eclipse.team.internal.ccvs.core.CVSTag;
import org.eclipse.team.internal.ccvs.core.ICVSFile;
import org.eclipse.team.internal.ccvs.core.ICVSRemoteFile;
import org.eclipse.team.internal.ccvs.core.ICVSRemoteResource;
import org.eclipse.team.internal.ccvs.core.ILogEntry;
import org.eclipse.team.internal.ccvs.core.client.Command;
import org.eclipse.team.internal.ccvs.core.client.Update;
import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
import org.eclipse.team.internal.ccvs.ui.actions.CVSAction;
import org.eclipse.team.internal.ccvs.ui.operations.UpdateOperation;
import org.eclipse.team.internal.ui.Utils;
import org.eclipse.team.ui.ISaveableWorkbenchPart;
import org.eclipse.ui.IPropertyListener;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.help.WorkbenchHelp;
public class CVSCompareRevisionsInput extends CompareEditorInput implements ISaveableWorkbenchPart {
IFile resource;
ILogEntry[] editions;
TableViewer viewer;
Action getRevisionAction;
Action getContentsAction;
Shell shell;
// Provide the widget for the history table
private HistoryTableProvider historyTableProvider;
/**
* Provide a wrapper for a resource node that doesn't buffer. Changes are saved directly to the
* underlying file.
*/
class TypedBufferedContent extends ResourceNode {
public TypedBufferedContent(IFile resource) {
super(resource);
}
protected InputStream createStream() throws CoreException {
return ((IFile)getResource()).getContents();
}
public void setContent(byte[] contents) {
if (contents == null) contents = new byte[0];
final InputStream is = new ByteArrayInputStream(contents);
IRunnableWithProgress runnable = new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
try {
IFile file = resource;
if (is != null) {
if (!file.exists()) {
file.create(is, false, monitor);
} else {
file.setContents(is, false, true, monitor);
}
} else {
file.delete(false, true, monitor);
}
} catch (CoreException e) {
throw new InvocationTargetException(e);
}
}
};
try {
new ProgressMonitorDialog(shell).run(false, false, runnable);
} catch (InvocationTargetException e) {
CVSUIPlugin.openError(CVSUIPlugin.getPlugin().getWorkbench().getActiveWorkbenchWindow().getShell(), Policy.bind("TeamFile.saveChanges", resource.getName()), null, e); //$NON-NLS-1$
} catch (InterruptedException e) {
// Ignore
}
fireContentChanged();
}
public ITypedElement replace(ITypedElement child, ITypedElement other) {
return null;
}
public void fireChange() {
fireContentChanged();
}
}
/**
* This class is an edition node which knows the log entry it came from.
*/
class ResourceRevisionNode extends ResourceEditionNode {
ILogEntry entry;
public ResourceRevisionNode(ILogEntry entry) {
super(entry.getRemoteFile());
this.entry = entry;
}
public ILogEntry getLogEntry() {
return entry;
}
public String getName() {
String revisionName = entry.getRevision();
if (revisionName != null) {
IResource resource = CVSCompareRevisionsInput.this.resource;
try {
ICVSRemoteFile currentEdition = (ICVSRemoteFile) CVSWorkspaceRoot.getRemoteResourceFor(resource);
if (currentEdition != null && currentEdition.getRevision().equals(revisionName)) {
Policy.bind("currentRevision", revisionName); //$NON-NLS-1$
} else {
return revisionName;
}
} catch (TeamException e) {
handle(e);
}
}
return super.getName();
}
}
/**
* A compare node that gets its label from the right element
*/
class VersionCompareDiffNode extends DiffNode implements IAdaptable {
public VersionCompareDiffNode(ITypedElement left, ITypedElement right) {
super(left, right);
}
public String getName() {
return getRight().getName();
}
public Object getAdapter(Class adapter) {
if (adapter == ILogEntry.class) {
return ((ResourceRevisionNode)getRight()).getLogEntry();
}
return null;
}
public void fireContentChanges() {
fireChange();
}
}
/**
* A content provider which knows how to get the children of the diff container
*/
class VersionCompareContentProvider implements IStructuredContentProvider {
public void dispose() {
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
public Object[] getElements(Object inputElement) {
if (inputElement instanceof DiffContainer) {
return ((DiffContainer)inputElement).getChildren();
}
return null;
}
}
public CVSCompareRevisionsInput(IFile resource, ILogEntry[] editions) {
super(new CompareConfiguration());
this.resource = resource;
this.editions = editions;
updateCurrentEdition();
initializeActions();
}
/* (non-Javadoc)
* @see org.eclipse.compare.CompareEditorInput#createContents(org.eclipse.swt.widgets.Composite)
*/
public Control createContents(Composite parent) {
Control c = super.createContents(parent);
c.setLayoutData(new GridData(GridData.FILL_BOTH));
return c;
}
public Viewer createDiffViewer(Composite parent) {
this.shell = parent.getShell();
viewer = getHistoryTableProvider().createTable(parent);
Table table = viewer.getTable();
table.setData(CompareUI.COMPARE_VIEWER_TITLE, getTitle()); //$NON-NLS-1$
viewer.setContentProvider(new VersionCompareContentProvider());
MenuManager mm = new MenuManager();
mm.setRemoveAllWhenShown(true);
mm.addMenuListener(
new IMenuListener() {
public void menuAboutToShow(IMenuManager mm) {
mm.add(getContentsAction);
mm.add(getRevisionAction);
}
}
);
table.setMenu(mm.createContextMenu(table));
viewer.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
ISelection selection = event.getSelection();
if (!(selection instanceof IStructuredSelection)) {
getRevisionAction.setEnabled(false);
getContentsAction.setEnabled(false);
return;
}
IStructuredSelection ss = (IStructuredSelection)selection;
getRevisionAction.setEnabled(ss.size() == 1);
getContentsAction.setEnabled(ss.size() == 1);
}
});
// Add F1 help.
WorkbenchHelp.setHelp(table, IHelpContextIds.COMPARE_REVISIONS_VIEW);
return viewer;
}
private void initLabels() {
CompareConfiguration cc = getCompareConfiguration();
cc.setLeftEditable(true);
cc.setRightEditable(false);
String resourceName = resource.getName();
String leftLabel = Policy.bind("CVSCompareRevisionsInput.workspace", new Object[] {resourceName}); //$NON-NLS-1$
cc.setLeftLabel(leftLabel);
String rightLabel = Policy.bind("CVSCompareRevisionsInput.repository", new Object[] {resourceName}); //$NON-NLS-1$
cc.setRightLabel(rightLabel);
}
private void initializeActions() {
getRevisionAction = new Action(Policy.bind("HistoryView.getRevisionAction")) { //$NON-NLS-1$
public void run() {
try {
new ProgressMonitorDialog(shell).run(false, true, new WorkspaceModifyOperation(null) {
protected void execute(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
IStructuredSelection selection = (IStructuredSelection)viewer.getSelection();
if (selection.size() != 1) return;
VersionCompareDiffNode node = (VersionCompareDiffNode)selection.getFirstElement();
ResourceEditionNode right = (ResourceEditionNode)node.getRight();
ICVSRemoteResource edition = right.getRemoteResource();
// Do the load. This just consists of setting the local contents. We don't
// actually want to change the base.
try {
CVSTag revisionTag = new CVSTag(((ICVSRemoteFile)edition).getRevision(), CVSTag.VERSION);
if(CVSAction.checkForMixingTags(shell, new IResource[] {resource}, revisionTag)) {
new UpdateOperation(
null,
new IResource[] {resource},
new Command.LocalOption[] {Update.IGNORE_LOCAL_CHANGES},
revisionTag)
.run(monitor);
getHistoryTableProvider().setFile((ICVSFile)edition);
}
} catch (TeamException e) {
throw new InvocationTargetException(e);
}
}
});
} catch (InterruptedException e) {
// Do nothing
return;
} catch (InvocationTargetException e) {
handle(e);
}
// fire change
IStructuredSelection selection = (IStructuredSelection)viewer.getSelection();
if (selection.size() != 1) return;
VersionCompareDiffNode node = (VersionCompareDiffNode)selection.getFirstElement();
TypedBufferedContent left = (TypedBufferedContent)node.getLeft();
left.fireChange();
// recompute the labels on the viewer
viewer.refresh();
}
};
getContentsAction = new Action(Policy.bind("HistoryView.getContentsAction")) { //$NON-NLS-1$
public void run() {
try {
replaceLocalWithCurrentlySelectedRevision();
} catch (CoreException e) {
Utils.handle(e);
}
}
};
}
protected Object prepareInput(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
initLabels();
DiffNode diffRoot = new DiffNode(Differencer.NO_CHANGE);
ITypedElement left = new TypedBufferedContent(resource);
for (int i = 0; i < editions.length; i++) {
ITypedElement right = new ResourceRevisionNode(editions[i]);
diffRoot.add(new VersionCompareDiffNode(left, right));
}
return diffRoot;
}
private void updateCurrentEdition() {
try {
getHistoryTableProvider().setFile((ICVSFile) CVSWorkspaceRoot.getRemoteResourceFor(resource));
} catch (TeamException e) {
handle(e);
}
}
private void handle(Exception e) {
setMessage(CVSUIPlugin.openError(shell, null, null, e, CVSUIPlugin.LOG_NONTEAM_EXCEPTIONS).getMessage());
}
/**
* Returns the historyTableProvider.
* @return HistoryTableProvider
*/
public HistoryTableProvider getHistoryTableProvider() {
if (historyTableProvider == null) {
historyTableProvider = new HistoryTableProvider();
}
return historyTableProvider;
}
/* (non-Javadoc)
* @see org.eclipse.compare.CompareEditorInput#saveChanges(org.eclipse.core.runtime.IProgressMonitor)
*/
public void saveChanges(IProgressMonitor pm) throws CoreException {
super.saveChanges(pm);
}
public void replaceLocalWithCurrentlySelectedRevision() throws CoreException {
IStructuredSelection selection = (IStructuredSelection)viewer.getSelection();
if (selection.size() != 1) return;
VersionCompareDiffNode node = (VersionCompareDiffNode)selection.getFirstElement();
ResourceRevisionNode right = (ResourceRevisionNode)node.getRight();
TypedBufferedContent left = (TypedBufferedContent)node.getLeft();
left.setContent(Utils.readBytes(right.getContents()));
}
public Viewer getViewer() {
return viewer;
}
/* (non-Javadoc)
* @see org.eclipse.compare.CompareEditorInput#getTitle()
*/
public String getTitle() {
return Policy.bind("CVSCompareRevisionsInput.compareResourceAndVersions", new Object[] {resource.getFullPath().toString()}); //$NON-NLS-1$
}
/* (non-Javadoc)
* @see org.eclipse.ui.ISaveablePart#doSave(org.eclipse.core.runtime.IProgressMonitor)
*/
public void doSave(IProgressMonitor monitor) {
try {
saveChanges(monitor);
} catch (CoreException e) {
Utils.handle(e);
}
}
/* (non-Javadoc)
* @see org.eclipse.ui.ISaveablePart#doSaveAs()
*/
public void doSaveAs() {
// noop
}
/* (non-Javadoc)
* @see org.eclipse.ui.ISaveablePart#isDirty()
*/
public boolean isDirty() {
return isSaveNeeded();
}
/* (non-Javadoc)
* @see org.eclipse.ui.ISaveablePart#isSaveAsAllowed()
*/
public boolean isSaveAsAllowed() {
return true;
}
/* (non-Javadoc)
* @see org.eclipse.ui.ISaveablePart#isSaveOnCloseNeeded()
*/
public boolean isSaveOnCloseNeeded() {
return true;
}
/* (non-Javadoc)
* @see org.eclipse.ui.IWorkbenchPart#addPropertyListener(org.eclipse.ui.IPropertyListener)
*/
public void addPropertyListener(IPropertyListener listener) {
// noop
}
/* (non-Javadoc)
* @see org.eclipse.ui.IWorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
*/
public void createPartControl(Composite parent) {
createContents(parent);
}
/* (non-Javadoc)
* @see org.eclipse.ui.IWorkbenchPart#dispose()
*/
public void dispose() {
}
/* (non-Javadoc)
* @see org.eclipse.ui.IWorkbenchPart#getSite()
*/
public IWorkbenchPartSite getSite() {
return null;
}
/* (non-Javadoc)
* @see org.eclipse.ui.IWorkbenchPart#getTitleToolTip()
*/
public String getTitleToolTip() {
return null;
}
/* (non-Javadoc)
* @see org.eclipse.ui.IWorkbenchPart#removePropertyListener(org.eclipse.ui.IPropertyListener)
*/
public void removePropertyListener(IPropertyListener listener) {
// noop
}
}