Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: c6cf43b37879a9efb88f375dd2ef4e696763a655 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/*******************************************************************************
 * Copyright (c) 2000, 2007 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.team.internal.ccvs.core.resources;

import java.util.HashSet;
import java.util.Set;

import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.team.core.RepositoryProvider;
import org.eclipse.team.internal.ccvs.core.*;
import org.eclipse.team.internal.ccvs.core.util.ResourceStateChangeListeners;

/**
 * This class performs several functions related to determining the modified
 * status of files under CVS control. First, it listens for change delta's for
 * files and brodcasts them to all listeners. It also registers as a save
 * participant so that deltas generated before the plugin are loaded are not
 * missed. Secondly, it listens for CVS resource state change events and uses
 * these to properly mark files and folders as modified.
 */
public class FileModificationManager implements IResourceChangeListener {
	
	private static final QualifiedName UPDATE_TIMESTAMP = new QualifiedName(CVSProviderPlugin.ID, "update-timestamp"); //$NON-NLS-1$
	
	/* private */Set modifiedResources = new HashSet();

	// consider the following changes types and ignore the others (e.g. marker and description changes are ignored)
	protected int INTERESTING_CHANGES = 	IResourceDelta.CONTENT | 
																	IResourceDelta.MOVED_FROM | 
																	IResourceDelta.MOVED_TO |
																	IResourceDelta.OPEN | 
																	IResourceDelta.REPLACED |
																	IResourceDelta.TYPE;

	/**
	 * Listen for file modifications and fire modification state changes
	 * 
	 * @see org.eclipse.core.resources.IResourceChangeListener#resourceChanged(org.eclipse.core.resources.IResourceChangeEvent)
	 */
	public void resourceChanged(IResourceChangeEvent event) {
		try {
			event.getDelta().accept(new IResourceDeltaVisitor() {
				public boolean visit(IResourceDelta delta) {
					IResource resource = delta.getResource();
					
					if (resource.getType()==IResource.PROJECT) {
						IProject project = (IProject)resource;
						if (!project.isAccessible()) {
							return false;
						}
						if ((delta.getFlags() & IResourceDelta.OPEN) != 0) {
							return false;
						} 
						if (RepositoryProvider.getProvider(project, CVSProviderPlugin.getTypeId()) == null) {
							return false;
						}
					}
					
					if (resource.getType()==IResource.FILE && delta.getKind() == IResourceDelta.CHANGED && resource.exists()) {
						int flags = delta.getFlags();
						if((flags & INTERESTING_CHANGES) != 0) {
							resourceChanged(resource, false);
						}
					} else if (delta.getKind() == IResourceDelta.ADDED) {
						try {
							EclipseSynchronizer.getInstance().handleAdded(resource);
						} catch (CVSException e) {
							CVSProviderPlugin.log(e);
						}
						resourceChanged(resource, true);
					} else if (delta.getKind() == IResourceDelta.REMOVED) {
						try {
							EclipseSynchronizer.getInstance().handleDeleted(resource);
						} catch (CVSException e) {
							CVSProviderPlugin.log(e);
						}
						modifiedResources.add(resource);
					}

					return true;
				}
			});
			if (!modifiedResources.isEmpty()) {
				ResourceStateChangeListeners.getListener().resourceModified(
					(IResource[])modifiedResources.toArray(new IResource[modifiedResources.size()]));
				modifiedResources.clear();
			}
		} catch (CoreException e) {
			CVSProviderPlugin.log(e);
		}

	}

	/**
	 * Method updated flags the objetc as having been modfied by the updated
	 * handler. This flag is read during the resource delta to determine whether
	 * the modification made the file dirty or not.
	 * 
	 * @param mFile
	 */
	public void updated(ICVSFile mFile) {
		try {
			if (mFile instanceof EclipseFile) {
				IFile file = (IFile)mFile.getIResource();
				file.setSessionProperty(UPDATE_TIMESTAMP, Long.valueOf(file.getModificationStamp()));
			}
		} catch (CoreException e) {
			CVSProviderPlugin.log(e);
		}
	}
	
	/*
	 * Handle added and changed resources by signaling the change to the corresponding
	 * CVS resource and recording the change for broadcast to interested listeners.
	 */
	/* private */void resourceChanged(IResource resource, boolean addition) {
		if (isCleanUpdate(resource)) return;
		try {
			EclipseResource cvsResource = (EclipseResource)CVSWorkspaceRoot.getCVSResourceFor(resource);
			if (!cvsResource.isIgnored()) {
				cvsResource.handleModification(addition);
				modifiedResources.add(resource);
			}
			// see bug 170743
			// ignored .cvsignore should always be clean and do not affect the path
			if(cvsResource.getName().equals(".cvsignore") && cvsResource.isIgnored()){ //$NON-NLS-1$
				EclipseSynchronizer.getInstance().setModified((EclipseFile) cvsResource, ICVSFile.CLEAN);
				modifiedResources.add(resource);
			}
		} catch (CVSException e) {
			// Log the exception and continue
			CVSProviderPlugin.log(e);
		}
	}

	/**
	 * If the file was the result of a clean update, the cached timestamp will
	 * be removed.
	 * 
	 * @param resource
	 * @return boolean
	 */
	private boolean isCleanUpdate(IResource resource) {
		if(resource.getType() != IResource.FILE) return false;
		long modStamp = resource.getModificationStamp();
		Long whenWeWrote;
		try {
			whenWeWrote = (Long)resource.getSessionProperty(UPDATE_TIMESTAMP);
			resource.setSessionProperty(UPDATE_TIMESTAMP, null);
		} catch(CoreException e) {
			CVSProviderPlugin.log(e);
			whenWeWrote = null;
		}
		return (whenWeWrote!=null && whenWeWrote.longValue() == modStamp);
	}
}

Back to the top