blob: bde6235b1a6673e526179012a36292ea4242e955 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2010 Tasktop Technologies 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:
* Tasktop Technologies - initial API and implementation
*******************************************************************************/
package org.eclipse.mylyn.internal.resources.ui;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.mylyn.commons.core.StatusHandler;
import org.eclipse.mylyn.context.core.ContextCore;
import org.eclipse.mylyn.monitor.core.InteractionEvent;
import org.eclipse.mylyn.resources.ui.ResourcesUi;
/**
* @author Mik Kersten
*/
public class ResourceChangeMonitor implements IResourceChangeListener {
private static final int MAX_FILE_DELTA_SIZE = 10;
private static final int MAX_NEW_FOLDER_DELTA_SIZE = 3;
private class ResourceDeltaVisitor implements IResourceDeltaVisitor {
private final Set<IResource> addedResources;
private final Set<IResource> changedResources;
private boolean haveTeamPrivateMember;
private final List<IResourceExclusionStrategy> resourceExclusions;
private int numNonExcludedFiles = 0;
private int numAddedFolders = 0;
public ResourceDeltaVisitor(List<IResourceExclusionStrategy> resourceExclusions) {
this.resourceExclusions = resourceExclusions;
this.addedResources = new HashSet<IResource>();
this.changedResources = new HashSet<IResource>();
// make sure that the exclusions are updated
for (IResourceExclusionStrategy exclusion : exclusions) {
exclusion.update();
}
}
public boolean hasValidResult() {
return !haveTeamPrivateMember;
}
public boolean visit(IResourceDelta delta) {
IResource deltaResource = delta.getResource();
if (deltaResource instanceof IProject
&& (delta.getKind() == IResourceDelta.REMOVED || (delta.getFlags() & IResourceDelta.OPEN) != 0)) {
// the project was either opened, closed or deleted, so lets ignore this so that we don't add every file to the context
return false;
}
if (hasTeamPrivate(deltaResource)) {
return false;
}
if (isExcluded(deltaResource)) {
return false;
}
IResourceDelta[] added = delta.getAffectedChildren(IResourceDelta.ADDED);
for (IResourceDelta element : added) {
IResource resource = element.getResource();
if ((resource instanceof IFile || resource instanceof IFolder) && !isExcluded(resource)) {
if (hasTeamPrivate(resource)) {
return false;
}
if (resource instanceof IFile) {
numNonExcludedFiles++;
} else if (resource instanceof IFolder) {
numAddedFolders++;
}
addedResources.add(resource);
}
}
IResourceDelta[] changed = delta.getAffectedChildren(IResourceDelta.CHANGED | IResourceDelta.REMOVED);
for (IResourceDelta element : changed) {
IResource resource = element.getResource();
// special rule for feature.xml files: bug 249856
if (resource instanceof IFile && !isExcluded(resource) && !"feature.xml".equals(resource.getName())) { //$NON-NLS-1$
if (element.getKind() == IResourceDelta.CHANGED
&& (element.getFlags() & IResourceDelta.CONTENT) == 0) {
// make sure that there was a content change and not just a markers change
continue;
}
if (hasTeamPrivate(resource)) {
return false;
}
if (resource instanceof IFile) {
numNonExcludedFiles++;
}
changedResources.add(resource);
}
}
return true;
}
private boolean hasTeamPrivate(IResource resource) {
if (haveTeamPrivateMember) {
return true;
}
if (resource.isTeamPrivateMember()) {
haveTeamPrivateMember = true;
return true;
}
return false;
}
private boolean isExcluded(IResource resource) {
for (IResourceExclusionStrategy exclusion : resourceExclusions) {
if (exclusion.isExcluded(resource)) {
return true;
}
}
return false;
}
public Set<IResource> getChangedResources() {
return changedResources;
}
public Set<IResource> getAddedResources() {
return addedResources;
}
public int getNumChangedAndAddedFiles() {
return numNonExcludedFiles;
}
public int getNumAddedFolders() {
return numAddedFolders;
}
};
private boolean enabled;
private final List<IResourceExclusionStrategy> exclusions = new ArrayList<IResourceExclusionStrategy>();
public ResourceChangeMonitor() {
this.enabled = true;
// ant based pattern exclusion
exclusions.add(new ResourcePatternExclusionStrategy());
// exclude resources not modified while task active
exclusions.add(new ResourceModifiedDateExclusionStrategy());
for (IResourceExclusionStrategy exclusion : exclusions) {
exclusion.init();
}
}
public void dispose() {
for (IResourceExclusionStrategy exclusion : exclusions) {
exclusion.dispose();
}
exclusions.clear();
}
// TODO investigate moving computation to the background?
public void resourceChanged(IResourceChangeEvent event) {
if (!enabled || !ContextCore.getContextManager().isContextActive()) {
return;
}
if (event.getType() != IResourceChangeEvent.POST_CHANGE) {
return;
}
IResourceDelta rootDelta = event.getDelta();
if (rootDelta != null) {
ResourceDeltaVisitor visitor = new ResourceDeltaVisitor(exclusions);
try {
rootDelta.accept(visitor, IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS | IContainer.INCLUDE_HIDDEN);
if (visitor.hasValidResult()) {
// discard large changes as to not pollute the task context
if (visitor.getNumChangedAndAddedFiles() <= MAX_FILE_DELTA_SIZE
&& visitor.getNumAddedFolders() <= MAX_NEW_FOLDER_DELTA_SIZE) {
ResourcesUi.addResourceToContext(visitor.getChangedResources(),
InteractionEvent.Kind.PREDICTION);
ResourcesUi.addResourceToContext(visitor.getAddedResources(), InteractionEvent.Kind.PROPAGATION);
}
}
} catch (CoreException e) {
StatusHandler.log(new Status(IStatus.ERROR, ResourcesUiBridgePlugin.ID_PLUGIN,
"Could not accept marker visitor", e)); //$NON-NLS-1$
}
}
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}