diff options
4 files changed, 107 insertions, 48 deletions
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFile.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFile.java index 9fb627e63..ac4a27d1b 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFile.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFile.java @@ -101,11 +101,7 @@ public class EclipseFile extends EclipseResource implements ICVSFile { } else { time = date.getTime(); } - try { - EclipseSynchronizer.getInstance().setTimeStamp(getIFile(), time); - } finally { - setModified(false); - } + EclipseSynchronizer.getInstance().setTimeStamp(getIFile(), time); } /* @@ -136,27 +132,7 @@ public class EclipseFile extends EclipseResource implements ICVSFile { ResourceSyncInfo info = getSyncInfo(); if (info == null && isIgnored()) return false; // unmanaged files are reported as modified - boolean dirty = computeModified(info); - setModified(dirty); - return dirty; - } - - /* - * Deteremine if the receiver is modified when compared with the given sync - * info. - */ - private boolean computeModified(ResourceSyncInfo info) throws CVSException { - // if there is no sync info and it doesn't exist then it is a phantom we don't care - // about. - if (info == null) { - return exists(); - } - - // isMerged() must be called because when a file is updated and merged by the cvs server the timestamps - // are equal. Merged files should however be reported as dirty because the user should take action and commit - // or review the merged contents. - if(info.isAdded() || info.isMerged() || !exists()) return true; - return !getTimeStamp().equals(info.getTimeStamp()); + return EclipseSynchronizer.getInstance().setModified(getIFile(), info, getTimeStamp(), UNKNOWN); } /* @@ -406,7 +382,7 @@ public class EclipseFile extends EclipseResource implements ICVSFile { setSyncInfo(newInfo, ICVSFile.CLEAN); } else { // an unedited file is no longer modified - setModified(false); + EclipseSynchronizer.getInstance().setModified(getIFile(), null, null, CLEAN); } } else { // We still need to report a state change @@ -520,16 +496,16 @@ public class EclipseFile extends EclipseResource implements ICVSFile { private void setSyncBytes(byte[] syncBytes, ResourceSyncInfo info, int modificationState) throws CVSException { Assert.isNotNull(syncBytes); setSyncBytes(syncBytes); - boolean modified; + Date timestamp = null; if (modificationState == UNKNOWN) { + // The sync info is only need if the modification state is unknown if (info == null) { info = new ResourceSyncInfo(syncBytes); } - modified = computeModified(info); - } else { - modified = modificationState == DIRTY; - } - setModified(modified); + // The timesatmp is only need if the modification state is unknown + timestamp = getTimeStamp(); + } + EclipseSynchronizer.getInstance().setModified(getIFile(), info, timestamp, modificationState); } public void handleModification(boolean forAddition) throws CVSException { @@ -541,12 +517,12 @@ public class EclipseFile extends EclipseResource implements ICVSFile { // There may be a better was of handling resources that transition from un-managed to // ignored but for now this seems like the safest change. if(! resource.isDerived()) { - setModified(false); + EclipseSynchronizer.getInstance().setModified(getIFile(), null, null, CLEAN); } return; } // set the modification state to what it really is and return true if the modification state changed - setModified(computeModified(getSyncInfo())); + EclipseSynchronizer.getInstance().setModified(getIFile(), getSyncInfo(), getTimeStamp(), UNKNOWN); } /** diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java index 17be9e028..e388633b0 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java @@ -340,7 +340,7 @@ class EclipseFolder extends EclipseResource implements ICVSFolder { IContainer container = (IContainer)getIResource(); - // TODO: Added optimization to avoid loading sync info if possible + // Added optimization to avoid loading sync info if possible // This will place a modified indicator on non-cvs folders // (i.e. the call to getModifiedState will cache a session property) int state = EclipseSynchronizer.getInstance().getModificationState(getIResource()); @@ -356,7 +356,7 @@ class EclipseFolder extends EclipseResource implements ICVSFolder { // caching as go. This will recursively determined the modified state // for all child resources until a modified child is found. modified = calculateAndSaveChildModificationStates(monitor); - setModified(modified); + EclipseSynchronizer.getInstance().setModified(this, modified); } else { modified = (state == ICVSFile.DIRTY); } @@ -375,7 +375,7 @@ class EclipseFolder extends EclipseResource implements ICVSFolder { // if the folder has sync info, it was handled is setFolderInfo // otherwise, flush the ancestors to recalculate if (info == null) { - setModified(true); + EclipseSynchronizer.getInstance().setDirtyIndicator(getIResource(), true); } } diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseResource.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseResource.java index 9a0bee1ce..6818ea96b 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseResource.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseResource.java @@ -260,14 +260,4 @@ abstract class EclipseResource implements ICVSResource, Comparable { * lock */ protected abstract void run(final ICVSRunnable job, IProgressMonitor monitor) throws CVSException; - - /** - * Sets the modified status of the receiver. This is done to ensure that any - * cached state kept by it or its parents is updated properly. The invoked method - * (setDirtyIndicator) will adjust the parent dirty state if the modification - * state of the resource has changed. - */ - protected void setModified(boolean modified) throws CVSException { - EclipseSynchronizer.getInstance().setDirtyIndicator(getIResource(), modified); - } } diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java index b758d310a..a17356945 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java @@ -13,6 +13,7 @@ package org.eclipse.team.internal.ccvs.core.resources; import java.util.ArrayList; import java.util.Arrays; +import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -42,6 +43,8 @@ import org.eclipse.team.internal.ccvs.core.CVSException; import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin; import org.eclipse.team.internal.ccvs.core.CVSStatus; import org.eclipse.team.internal.ccvs.core.ICVSFile; +import org.eclipse.team.internal.ccvs.core.ICVSFolder; +import org.eclipse.team.internal.ccvs.core.ICVSResource; import org.eclipse.team.internal.ccvs.core.ICVSRunnable; import org.eclipse.team.internal.ccvs.core.Policy; import org.eclipse.team.internal.ccvs.core.syncinfo.BaserevInfo; @@ -1548,6 +1551,14 @@ public class EclipseSynchronizer implements IFlushOperation { return resourceLock.isWithinActiveOperationScope(resource); } + /** + * Set the timestamp of the given file and set it to be CLEAN. It is + * assumed that this method is only invoked to reset the file timestamp + * to the timestamp that is in the CVS/Entries file. + * @param file + * @param time + * @throws CVSException + */ public void setTimeStamp(IFile file, long time) throws CVSException { ISchedulingRule rule = null; try { @@ -1556,6 +1567,7 @@ public class EclipseSynchronizer implements IFlushOperation { beginOperation(); try { file.setLocalTimeStamp(time); + setModified(file, null, null, ICVSFile.CLEAN); } catch (CoreException e) { throw CVSException.wrapException(e); } @@ -1634,4 +1646,85 @@ public class EclipseSynchronizer implements IFlushOperation { monitor.done(); } } + + /** + * Compute the modification state for the given file. If the modificationState is + * ICVSFile.UNKNOWN, it is computed. However, if it is CLEAN or DIRTY, + * it is set accordingly. CLEAN or DIRTY can only be used if the caller is protected + * from resource modifications (either by a scheduling rule or inside a delta handler). + * The info and modificationTime are only used if the modificationType is UNKNOWN. + * Otherwise, they can be null. + * @param file + * @param info + * @param modificationTime + * @param modificationState + * @return true if the file is dirty + */ + public boolean setModified(IFile file, ResourceSyncInfo info, Date modificationTime, int modificationState) throws CVSException { + try { + beginOperation(); + boolean dirty; + if (modificationState == ICVSFile.UNKNOWN) { + // if there is no sync info and it doesn't exist then it is a phantom we don't care about. + if (info == null) { + dirty = file.exists(); + } else { + // isMerged() must be called because when a file is updated and merged by the cvs server the timestamps + // are equal. Merged files should however be reported as dirty because the user should take action and commit + // or review the merged contents. + if(info.isAdded() || info.isMerged() || !file.exists()) { + dirty = true; + } else { + dirty = !modificationTime.equals(info.getTimeStamp()); + } + } + } else { + dirty = modificationState == ICVSFile.DIRTY; + } + setDirtyIndicator(file, dirty); + return dirty; + } finally { + endOperation(); + } + + } + + /** + * Set the modified state of the folder. This method can be called when no resource locks are + * held. It will check the cached modification state of all the folder's children before setting. + * If the states of the children do not match, the state for the folder is not cached. + * @param folder + * @param modified + */ + public void setModified(ICVSFolder cvsFolder, boolean modified) throws CVSException { + try { + beginOperation(); + IContainer folder = (IContainer)cvsFolder.getIResource(); + // The drop out condition for clean or dirty are the opposite. + // (i.e. if modified and a dirty is found we can set the indicator + // and if not modified and a dirty or unknown is found we cannot set the indicator) + boolean okToSet = !modified; + // Obtain the children while we're locked to ensure some were not added or changed + ICVSResource[] children = cvsFolder.members(ICVSFolder.ALL_UNIGNORED_MEMBERS); + for (int i = 0; i < children.length; i++) { + IResource resource = children[i].getIResource(); + if (modified) { + if (getDirtyIndicator(resource) == IS_DIRTY_INDICATOR) { + okToSet = true; + break; + } + } else { + if (getDirtyIndicator(resource) != NOT_DIRTY_INDICATOR) { + okToSet = false; + break; + } + } + } + if (okToSet) { + setDirtyIndicator(folder, modified); + } + } finally { + endOperation(); + } + } } |