blob: 042aac14c28327f145e4c96d5ea5ccb1e00b1834 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.compare.internal;
import java.text.MessageFormat;
import java.lang.reflect.InvocationTargetException;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.compare.*;
import org.eclipse.compare.structuremergeviewer.*;
/**
* A two-way or three-way compare for arbitrary IResources.
*/
class ResourceCompareInput extends CompareEditorInput {
private static final boolean NORMALIZE_CASE= true;
private boolean fThreeWay= false;
private Object fRoot;
private IStructureComparator fAncestor;
private IStructureComparator fLeft;
private IStructureComparator fRight;
private IResource fAncestorResource;
private IResource fLeftResource;
private IResource fRightResource;
private DiffTreeViewer fDiffViewer;
private IAction fOpenAction;
class MyDiffNode extends DiffNode {
private boolean fDirty= false;
private ITypedElement fLastId;
private String fLastName;
public MyDiffNode(IDiffContainer parent, int description, ITypedElement ancestor, ITypedElement left, ITypedElement right) {
super(parent, description, ancestor, left, right);
}
public void fireChange() {
super.fireChange();
setDirty(true);
fDirty= true;
if (fDiffViewer != null)
fDiffViewer.refresh(this);
}
void clearDirty() {
fDirty= false;
}
public String getName() {
if (fLastName == null)
fLastName= super.getName();
if (fDirty)
return '<' + fLastName + '>';
return fLastName;
}
public ITypedElement getId() {
ITypedElement id= super.getId();
if (id == null)
return fLastId;
fLastId= id;
return id;
}
}
/**
* Creates an compare editor input for the given selection.
*/
ResourceCompareInput(CompareConfiguration config) {
super(config);
}
public Viewer createDiffViewer(Composite parent) {
fDiffViewer= new DiffTreeViewer(parent, getCompareConfiguration()) {
protected void fillContextMenu(IMenuManager manager) {
if (fOpenAction == null) {
fOpenAction= new Action() {
public void run() {
handleOpen(null);
}
};
Utilities.initAction(fOpenAction, getBundle(), "action.CompareContents."); //$NON-NLS-1$
}
boolean enable= false;
ISelection selection= getSelection();
if (selection instanceof IStructuredSelection) {
IStructuredSelection ss= (IStructuredSelection)selection;
if (ss.size() == 1) {
Object element= ss.getFirstElement();
if (element instanceof MyDiffNode) {
ITypedElement te= ((MyDiffNode) element).getId();
if (te != null)
enable= !ITypedElement.FOLDER_TYPE.equals(te.getType());
} else
enable= true;
}
}
fOpenAction.setEnabled(enable);
manager.add(fOpenAction);
super.fillContextMenu(manager);
}
};
return fDiffViewer;
}
void setSelection(ISelection s) {
IResource[] selection= Utilities.getResources(s);
fThreeWay= selection.length == 3;
fAncestorResource= null;
fLeftResource= selection[0];
fRightResource= selection[1];
if (fThreeWay) {
fLeftResource= selection[1];
fRightResource= selection[2];
}
fAncestor= null;
fLeft= getStructure(fLeftResource);
fRight= getStructure(fRightResource);
if (fThreeWay) {
fAncestorResource= selection[0];
fAncestor= getStructure(fAncestorResource);
}
}
/**
* Returns true if compare can be executed for the given selection.
*/
public boolean isEnabled(ISelection s) {
IResource[] selection= Utilities.getResources(s);
if (selection.length < 2 || selection.length > 3)
return false;
fThreeWay= selection.length == 3;
fLeftResource= selection[0];
fRightResource= selection[1];
if (fThreeWay) {
fLeftResource= selection[1];
fRightResource= selection[2];
}
if (!comparable(fLeftResource, fRightResource))
return false;
if (fThreeWay) {
fAncestorResource= selection[0];
if (!comparable(fLeftResource, fRightResource))
return false;
}
return true;
}
/**
* Initializes the images in the compare configuration.
*/
void initializeCompareConfiguration() {
CompareConfiguration cc= getCompareConfiguration();
if (fLeftResource != null) {
cc.setLeftLabel(buildLabel(fLeftResource));
cc.setLeftImage(CompareUIPlugin.getImage(fLeftResource));
}
if (fRightResource != null) {
cc.setRightLabel(buildLabel(fRightResource));
cc.setRightImage(CompareUIPlugin.getImage(fRightResource));
}
if (fThreeWay && fAncestorResource != null) {
cc.setAncestorLabel(buildLabel(fAncestorResource));
cc.setAncestorImage(CompareUIPlugin.getImage(fAncestorResource));
}
}
/**
* Returns true if both resources are either structured or unstructured.
*/
private boolean comparable(IResource c1, IResource c2) {
return hasStructure(c1) == hasStructure(c2);
}
/**
* Returns true if the given argument has a structure.
*/
private boolean hasStructure(IResource input) {
if (input instanceof IContainer)
return true;
if (input instanceof IFile) {
IFile file= (IFile) input;
String type= file.getFileExtension();
if (type != null) {
type= normalizeCase(type);
return "JAR".equals(type) || "ZIP".equals(type); //$NON-NLS-2$ //$NON-NLS-1$
}
}
return false;
}
/**
* Creates a <code>IStructureComparator</code> for the given input.
* Returns <code>null</code> if no <code>IStructureComparator</code>
* can be found for the <code>IResource</code>.
*/
private IStructureComparator getStructure(IResource input) {
if (input instanceof IContainer)
return new BufferedResourceNode(input);
if (input instanceof IFile) {
IStructureComparator rn= new BufferedResourceNode(input);
IFile file= (IFile) input;
String type= normalizeCase(file.getFileExtension());
if ("JAR".equals(type) || "ZIP".equals(type)) //$NON-NLS-2$ //$NON-NLS-1$
return new ZipFileStructureCreator().getStructure(rn);
return rn;
}
return null;
}
/**
* Performs a two-way or three-way diff on the current selection.
*/
public Object prepareInput(IProgressMonitor pm) throws InvocationTargetException {
try {
// fix for PR 1GFMLFB: ITPUI:WIN2000 - files that are out of sync with the file system appear as empty
fLeftResource.refreshLocal(IResource.DEPTH_INFINITE, pm);
fRightResource.refreshLocal(IResource.DEPTH_INFINITE, pm);
if (fThreeWay && fAncestorResource != null)
fAncestorResource.refreshLocal(IResource.DEPTH_INFINITE, pm);
// end fix
pm.beginTask(Utilities.getString("ResourceCompare.taskName"), IProgressMonitor.UNKNOWN); //$NON-NLS-1$
String leftLabel= fLeftResource.getName();
String rightLabel= fRightResource.getName();
String title;
if (fThreeWay) {
String format= Utilities.getString("ResourceCompare.threeWay.title"); //$NON-NLS-1$
String ancestorLabel= fAncestorResource.getName();
title= MessageFormat.format(format, new String[] {ancestorLabel, leftLabel, rightLabel});
} else {
String format= Utilities.getString("ResourceCompare.twoWay.title"); //$NON-NLS-1$
title= MessageFormat.format(format, new String[] {leftLabel, rightLabel});
}
setTitle(title);
Differencer d= new Differencer() {
protected Object visit(Object parent, int description, Object ancestor, Object left, Object right) {
return new MyDiffNode((IDiffContainer) parent, description, (ITypedElement)ancestor, (ITypedElement)left, (ITypedElement)right);
}
};
fRoot= d.findDifferences(fThreeWay, pm, null, fAncestor, fLeft, fRight);
return fRoot;
} catch (CoreException ex) {
throw new InvocationTargetException(ex);
} finally {
pm.done();
}
}
public String getToolTipText() {
if (fLeftResource != null && fRightResource != null) {
String leftLabel= fLeftResource.getFullPath().makeRelative().toString();
String rightLabel= fRightResource.getFullPath().makeRelative().toString();
if (fThreeWay) {
String format= Utilities.getString("ResourceCompare.threeWay.tooltip"); //$NON-NLS-1$
String ancestorLabel= fAncestorResource.getFullPath().makeRelative().toString();
return MessageFormat.format(format, new String[] {ancestorLabel, leftLabel, rightLabel});
} else {
String format= Utilities.getString("ResourceCompare.twoWay.tooltip"); //$NON-NLS-1$
return MessageFormat.format(format, new String[] {leftLabel, rightLabel});
}
}
// fall back
return super.getToolTipText();
}
private String buildLabel(IResource r) {
String n= r.getFullPath().toString();
if (n.charAt(0) == IPath.SEPARATOR)
return n.substring(1);
return n;
}
public void saveChanges(IProgressMonitor pm) throws CoreException {
super.saveChanges(pm);
if (fRoot instanceof DiffNode) {
try {
commit(pm, (DiffNode) fRoot);
} finally {
if (fDiffViewer != null)
fDiffViewer.refresh();
setDirty(false);
}
}
}
/*
* Recursively walks the diff tree and commits all changes.
*/
private static void commit(IProgressMonitor pm, DiffNode node) throws CoreException {
if (node instanceof MyDiffNode)
((MyDiffNode)node).clearDirty();
ITypedElement left= node.getLeft();
if (left instanceof BufferedResourceNode)
((BufferedResourceNode) left).commit(pm);
ITypedElement right= node.getRight();
if (right instanceof BufferedResourceNode)
((BufferedResourceNode) right).commit(pm);
IDiffElement[] children= node.getChildren();
if (children != null) {
for (int i= 0; i < children.length; i++) {
IDiffElement element= children[i];
if (element instanceof DiffNode)
commit(pm, (DiffNode) element);
}
}
}
private static String normalizeCase(String s) {
if (NORMALIZE_CASE && s != null)
return s.toUpperCase();
return s;
}
}