| /******************************************************************************* |
| * 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; |
| } |
| |
| } |
| |