package org.eclipse.core.internal.resources;
import java.util.LinkedList;
import java.util.Queue;
import org.eclipse.core.internal.utils.*;
import org.eclipse.core.internal.watson.*;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.content.IContentTypeManager;
import org.eclipse.core.runtime.content.IContentTypeManager.ContentTypeChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.osgi.framework.Bundle;
public class CharsetDeltaJob extends Job implements IContentTypeManager.IContentTypeChangeListener {
public final static String FAMILY_CHARSET_DELTA = ResourcesPlugin.PI_RESOURCES + "charsetJobFamily";
interface ICharsetListenerFilter {
IPath getRoot();
boolean isAffected(ResourceInfo info, IPathRequestor requestor);
}
private ThreadLocal<Boolean> disabled = new ThreadLocal<>();
private final Bundle systemBundle = Platform.getBundle("org.eclipse.osgi");
private Queue<ICharsetListenerFilter> work = new LinkedList<>();
Workspace workspace;
private static final int CHARSET_DELTA_DELAY = 500;
public CharsetDeltaJob(Workspace workspace) {
super(Messages.resources_charsetBroadcasting);
this.workspace = workspace;
}
private void addToQueue(ICharsetListenerFilter filter) {
synchronized (work) {
work.add(filter);
}
schedule(CHARSET_DELTA_DELAY);
}
@Override
public boolean belongsTo(Object family) {
return FAMILY_CHARSET_DELTA.equals(family);
}
public void charsetPreferencesChanged(final IProject project) {
if (isDisabled())
return;
ResourceInfo projectInfo = ((Project) project).getResourceInfo(false, false);
if (projectInfo == null)
return;
final long projectId = projectInfo.getNodeId();
ICharsetListenerFilter filter = new ICharsetListenerFilter() {
@Override
public IPath getRoot() {
ResourceInfo currentInfo = ((Project) project).getResourceInfo(false, false);
if (currentInfo == null)
return null;
long currentId = currentInfo.getNodeId();
if (currentId != projectId)
return null;
return project.getFullPath();
}
@Override
public boolean isAffected(ResourceInfo info, IPathRequestor requestor) {
return true;
}
};
addToQueue(filter);
}
@Override
public void contentTypeChanged(final ContentTypeChangeEvent event) {
ICharsetListenerFilter filter = new ICharsetListenerFilter() {
@Override
public IPath getRoot() {
return Path.ROOT;
}
@Override
public boolean isAffected(ResourceInfo info, IPathRequestor requestor) {
if (info.getType() != IResource.FILE)
return false;
return event.getContentType().isAssociatedWith(requestor.requestName());
}
};
addToQueue(filter);
}
private boolean isDisabled() {
return disabled.get() != null;
}
private void processNextEvent(final ICharsetListenerFilter filter, IProgressMonitor monitor) throws CoreException {
IElementContentVisitor visitor = (tree, requestor, elementContents) -> {
ResourceInfo info = (ResourceInfo) elementContents;
if (!filter.isAffected(info, requestor))
return true;
info = workspace.getResourceInfo(requestor.requestPath(), false, true);
if (info == null)
return false;
info.incrementCharsetGenerationCount();
return true;
};
try {
IPath root = filter.getRoot();
if (root != null)
new ElementTreeIterator(workspace.getElementTree(), root).iterate(visitor);
} catch (WrappedRuntimeException e) {
throw (CoreException) e.getTargetException();
}
if (monitor.isCanceled())
throw new OperationCanceledException();
}
private ICharsetListenerFilter removeFromQueue() {
synchronized (work) {
return work.poll();
}
}
@Override
public IStatus run(IProgressMonitor monitor) {
monitor = Policy.monitorFor(monitor);
try {
String message = Messages.resources_charsetBroadcasting;
monitor.beginTask(message, Policy.totalWork);
try {
workspace.prepareOperation(null, monitor);
workspace.beginOperation(true);
ICharsetListenerFilter next;
while (systemBundle.getState() != Bundle.STOPPING && (next = removeFromQueue()) != null)
processNextEvent(next, monitor);
} catch (OperationCanceledException e) {
workspace.getWorkManager().operationCanceled();
return Status.CANCEL_STATUS;
} finally {
workspace.endOperation(null, true);
}
monitor.worked(Policy.opWork);
} catch (CoreException sig) {
return sig.getStatus();
} finally {
monitor.done();
}
return Status.OK_STATUS;
}
public void setDisabled(boolean disabled) {
this.disabled.set(disabled ? Boolean.TRUE : null);
}
public void shutdown() {
IContentTypeManager contentTypeManager = Platform.getContentTypeManager();
if (contentTypeManager != null)
contentTypeManager.removeContentTypeChangeListener(this);
}
public void startup() {
Platform.getContentTypeManager().addContentTypeChangeListener(this);
}
}