blob: 5a2f1863d4c1ec284da3faeaf2a9e72655160954 [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.compare.internal.patch;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.compare.internal.CompareUIPlugin;
import org.eclipse.compare.structuremergeviewer.Differencer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.osgi.util.NLS;
import org.eclipse.ui.model.IWorkbenchAdapter;
public class Diff implements IWorkbenchAdapter, IAdaptable {
IPath fOldPath, fNewPath;
long fOldDate, fNewDate; // if 0: no file
List fHunks= new ArrayList();
boolean fMatches= false;
private boolean fIsEnabled2= true;
String fRejected;
DiffProject fProject; //the project that contains this diff
boolean fDiffProblem;
String fErrorMessage;
int fStrip;
int fFuzzFactor;
static ImageDescriptor addId= CompareUIPlugin.getImageDescriptor("ovr16/add_ov.gif"); //$NON-NLS-1$
static ImageDescriptor delId= CompareUIPlugin.getImageDescriptor("ovr16/del_ov.gif"); //$NON-NLS-1$
private WorkspacePatcher patcher;
/* package */ Diff(IPath oldPath, long oldDate, IPath newPath, long newDate) {
fOldPath= oldPath;
fOldDate= oldPath == null ? 0 : oldDate;
fNewPath= newPath;
fNewDate= newPath == null ? 0 : newDate;
}
boolean isEnabled() {
return fIsEnabled2;
}
void setEnabled(boolean b) {
fIsEnabled2= b;
}
void reverse() {
IPath tp= fOldPath;
fOldPath= fNewPath;
fNewPath= tp;
long t= fOldDate;
fOldDate= fNewDate;
fNewDate= t;
Iterator iter= fHunks.iterator();
while (iter.hasNext()) {
Hunk hunk= (Hunk) iter.next();
hunk.reverse();
}
}
Hunk[] getHunks() {
return (Hunk[]) fHunks.toArray(new Hunk[fHunks.size()]);
}
IPath getPath() {
if (fOldPath != null)
return fOldPath;
return fNewPath;
}
void finish() {
if (fHunks.size() == 1) {
Hunk h= (Hunk) fHunks.get(0);
if (h.fNewLength == 0) {
fNewDate= 0;
fNewPath= fOldPath;
}
}
}
/* package */ void add(Hunk hunk) {
fHunks.add(hunk);
}
/* package */ int getType() {
if (fOldDate == 0)
return Differencer.ADDITION;
if (fNewDate == 0)
return Differencer.DELETION;
return Differencer.CHANGE;
}
/* package */ String getDescription(int strip) {
IPath path= getStrippedPath(strip);
return path.toOSString();
}
private IPath getStrippedPath(int strip) {
IPath path= fOldPath;
if (fOldDate == 0)
path= fNewPath;
if (strip > 0 && strip < path.segmentCount())
path= path.removeFirstSegments(strip);
return path;
}
DiffProject getProject() {
return fProject;
}
public void setProject(DiffProject diffProject) {
this.fProject= diffProject;
fProject.addDiff(this);
}
/**
* Resets the state of this diff to {no matches, no problems} and checks to see what hunks contained
* by this Diff can actually be applied
* @param wspatcher
* @param strip
* @param fuzzfactor
* @return ArrayList containing which hunks contained by this diff can be checked
*/
ArrayList reset(WorkspacePatcher wspatcher, int strip, int fuzzfactor) {
//reset state - no matches, no problems
this.fMatches= false;
this.fDiffProblem= false;
this.fStrip= strip;
this.fFuzzFactor= fuzzfactor;
this.patcher= wspatcher;
//Make sure that the file that contains this diff exists and is modifiable
ArrayList failedHunks= checkForFileExistance();
ArrayList hunksToCheck= new ArrayList();
//Ensure that, for workspace patches, the containing project exists in the workspace
boolean projectExistsInWorkspace=true;
if (fProject != null){
projectExistsInWorkspace = fProject.getProject().exists();
}
//Verify if any of the hunks have failed, and reset the state of each hunk
//accordingly
for (Iterator iter= fHunks.iterator(); iter.hasNext();) {
Hunk hunk= (Hunk) iter.next();
boolean hunkFailed= failedHunks.contains(hunk);
//if any hunk has failed we have to alter this Diff's fMatches field
if (hunkFailed)
this.fMatches= false;
hunk.reset(hunkFailed);
//If the hunk can be applied and the project exists in the workspace and
//there are no problems with the hunk's containing diff, then check the hunk
if (!hunkFailed && projectExistsInWorkspace && !fDiffProblem)
hunksToCheck.add(hunk);
}
return hunksToCheck;
}
/**
* Checks to see:
* 1) if the target file specified in fNewPath exists and is patchable
* 2) which hunks contained by this diff can be catually applied to the file
* @return a list containg the hunks that could not be applied
*/
private ArrayList checkForFileExistance() {
IFile file= getTargetFile();
boolean create= false;
//If this diff is an addition, make sure that it doesn't already exist
if (getType() == Differencer.ADDITION) {
if (file == null || !file.exists()) {
fMatches= true;
} else {
// file already exists
fDiffProblem= true;
fErrorMessage= PatchMessages.PreviewPatchPage_FileExists_error;
}
create= true;
} else { //This diff is not an addition, try to find a match for it
//Ensure that the file described by the path exists and is modifiable
if (file != null) {
fMatches= true;
} else {
// file doesn't exist
fDiffProblem= true;
fErrorMessage= PatchMessages.PreviewPatchPage_FileDoesNotExist_error;
}
}
ArrayList failedHunks= new ArrayList();
patcher.setFuzz(fFuzzFactor);
//If this diff has no problems discovered so far, try applying the patch
if (!fDiffProblem)
patcher.apply(this, file, create, failedHunks);
if (failedHunks.size() > 0)
fRejected= patcher.getRejected(failedHunks);
return failedHunks;
}
public WorkspacePatcher getPatcher() {
return patcher;
}
public IFile getTargetFile() {
if (fProject != null)
return fProject.getFile(getStrippedPath(fStrip));
return getPatcher().existsInTarget(getStrippedPath(fStrip));
}
//IWorkbenchAdapter methods
public Object[] getChildren(Object o) {
return fHunks.toArray();
}
public ImageDescriptor getImageDescriptor(Object object) {
if (object instanceof Diff) {
Diff diff= (Diff) object;
switch (diff.getType()) {
case Differencer.ADDITION :
return addId;
case Differencer.DELETION :
return delId;
}
}
return null;
}
public String getLabel(Object o) {
String label= getDescription(fStrip);
if (this.fDiffProblem)
return NLS.bind(PatchMessages.Diff_2Args, new String[] {label, fErrorMessage});
return label;
}
public Object getParent(Object o) {
return fProject;
}
//IAdaptable methods
public Object getAdapter(Class adapter) {
if (adapter == IWorkbenchAdapter.class)
return this;
return null;
}
protected boolean getDiffProblem() {
return fDiffProblem;
}
/**
* Returns whether this Diff has any problems
* @return true if this Diff or any of its children Hunks have a problem, false if it doesn't
*/
protected boolean containsProblems() {
if (fDiffProblem)
return true;
for (Iterator iter = fHunks.iterator(); iter.hasNext();) {
Hunk element = (Hunk) iter.next();
if (element.getHunkProblem()) {
return true;
}
}
return false;
}
}