blob: ad53bbac8e66f749e0e8e11260d93088a4beb272 [file] [log] [blame]
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
package org.eclipse.compare.internal;
import java.text.MessageFormat;
import java.lang.reflect.InvocationTargetException;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.jface.viewers.ISelection;
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;
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);
}
public String getName() {
if (fLastName == null)
fLastName= super.getName();
if (fDirty)
return fLastName + " *"; //$NON-NLS-1$
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) {
Viewer v= super.createDiffViewer(parent);
if (v instanceof DiffTreeViewer)
fDiffViewer= (DiffTreeViewer) v;
return v;
}
/**
* Returns true if compare can be executed for the given selection.
*/
boolean setSelection(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];
}
fAncestor= null;
fLeft= getStructure(fLeftResource);
fRight= getStructure(fRightResource);
if (incomparable(fLeft, fRight))
return false;
if (fThreeWay) {
fAncestorResource= selection[0];
fAncestor= getStructure(fAncestorResource);
if (incomparable(fAncestor, fRight))
return false;
}
return true;
}
/**
* Returns true if the given arguments cannot be compared.
*/
private boolean incomparable(IStructureComparator c1, IStructureComparator c2) {
if (c1 == null || c2 == null)
return true;
return isLeaf(c1) != isLeaf(c2);
}
/**
* Returns true if the given arguments is a leaf.
*/
private boolean isLeaf(IStructureComparator c) {
if (c instanceof ITypedElement) {
ITypedElement te= (ITypedElement) c;
return !ITypedElement.FOLDER_TYPE.equals(te.getType());
}
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 {
CompareConfiguration cc= (CompareConfiguration) getCompareConfiguration();
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$
cc.setLeftLabel(buildLabel(fLeftResource));
cc.setLeftImage(CompareUIPlugin.getImage(fLeftResource));
cc.setRightLabel(buildLabel(fRightResource));
cc.setRightImage(CompareUIPlugin.getImage(fRightResource));
String leftLabel= fLeftResource.getName();
String rightLabel= fRightResource.getName();
String title;
if (fThreeWay) {
cc.setAncestorLabel(buildLabel(fAncestorResource));
cc.setAncestorImage(CompareUIPlugin.getImage(fAncestorResource));
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();
}
}
private String buildLabel(IResource r) {
//return r.getName();
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 {
setDirty(false);
}
}
}
/*
* Recursively walks the diff tree and commits all changes.
*/
private static void commit(IProgressMonitor pm, DiffNode node) throws CoreException {
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;
}
}