/** * Copyright (c) 2005-2013 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Eclipse Public License (EPL). * Please see the license.txt included with this distribution for details. * Any modifications to this file must keep this entire header intact. */ /* * Created on 11/09/2005 */ package org.python.pydev.builder; import java.util.ArrayList; import java.util.List; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.text.IDocument; import org.python.pydev.core.FileUtilsFileBuffer; import org.python.pydev.core.IPythonNature; import org.python.pydev.core.log.Log; import org.python.pydev.plugin.nature.PythonNature; import org.python.pydev.shared_core.callbacks.ICallback0; import org.python.pydev.shared_core.string.FastStringBuffer; /** * Groups the visitors to be added and visits them according to their priority * * @author fabioz */ public class PydevGrouperVisitor extends PydevInternalResourceDeltaVisitor { private final List<PyDevBuilderVisitor> visitors; //variables used to communicate the progress /** * number of total resources to be visited (only used when the monitor is set) * (set externally) */ private final int totalResources; /** * number of resources visited to the moment * (updated in this class) */ private int currentResourcesVisited = 0; //end variables used to communicate the progress private final List<IResourceDelta> delayedVisits; public PydevGrouperVisitor(List<PyDevBuilderVisitor> _visitors, IProgressMonitor monitor, int totalResources) { super(monitor); this.monitor = monitor; this.totalResources = totalResources; this.delayedVisits = new ArrayList<>(); //make a copy - should be already sorted at this point this.visitors = new ArrayList<PyDevBuilderVisitor>(_visitors); } private final int VISIT_ADD = 1; private final int VISIT_CHANGE = 2; private final int VISIT_REMOVE = 3; /** * @param name determines the name of the method to visit (added removed or changed) * @param resource the resource to visit * @param document the document from the resource * @param monitor */ private void visitWith(int visitType, final IResource resource, ICallback0<IDocument> document, IProgressMonitor monitor) { if (monitor.isCanceled()) { return; //it's already cancelled } IPythonNature nature = PythonNature.getPythonNature(resource); if (nature == null) { return; } if (!nature.startRequests()) { return; } nature.updateMtime(); try { try { //we visit external because we must index them if (!isResourceInPythonpathProjectSources(resource, nature, true)) { return; // we only analyze resources that are in the pythonpath } } catch (Exception e1) { Log.log(e1); return; // we only analyze resources that are in the pythonpath } VisitorMemo copyMemo = new VisitorMemo(this.memo); FastStringBuffer bufferToCommunicateProgress = new FastStringBuffer(); for (PyDevBuilderVisitor visitor : visitors) { // some visitors cannot visit too many elements because they do a lot of processing if (visitor.maxResourcesToVisit() == PyDevBuilderVisitor.MAX_TO_VISIT_INFINITE || visitor.maxResourcesToVisit() >= totalResources) { visitor.memo = copyMemo; //setting the memo must be the first thing. try { //communicate progress for each visitor PyDevBuilder.communicateProgress(monitor, totalResources, currentResourcesVisited, resource, visitor, bufferToCommunicateProgress); switch (visitType) { case VISIT_ADD: visitor.visitAddedResource(resource, document, monitor); break; case VISIT_CHANGE: visitor.visitChangedResource(resource, document, monitor); break; case VISIT_REMOVE: visitor.visitRemovedResource(resource, document, monitor); break; default: throw new RuntimeException("Error: visit type not properly given!"); //$NON-NLS-1$ } } catch (Exception e) { Log.log(e); } } } } finally { nature.endRequests(); } } /** * This will use the internal builders to traverse the delta. Note that the resource is always a valid * python file and is also always located in the pythonpath. */ @Override protected void onVisitDelta(IResourceDelta delta) { //Note: removals happen now, additions and changes happen later (so that renames are //properly treated). switch (delta.getKind()) { case IResourceDelta.ADDED: case IResourceDelta.CHANGED: delayedVisits.add(delta); break; case IResourceDelta.REMOVED: IResource resource = delta.getResource(); memo.put(PyDevBuilderVisitor.DOCUMENT_TIME, System.currentTimeMillis()); visitRemovedResource(resource, null, monitor); break; } } @Override public void visitAddedResource(IResource resource, ICallback0<IDocument> document, IProgressMonitor monitor) { visitWith(VISIT_ADD, resource, document, monitor); } @Override public void visitChangedResource(IResource resource, ICallback0<IDocument> document, IProgressMonitor monitor) { visitWith(VISIT_CHANGE, resource, document, monitor); } @Override public void visitRemovedResource(IResource resource, ICallback0<IDocument> document, IProgressMonitor monitor) { visitWith(VISIT_REMOVE, resource, document, monitor); } public void finishDelayedVisits() { for (IResourceDelta delta : delayedVisits) { try { IResource resource = delta.getResource(); boolean isAddRemove = false; switch (delta.getKind()) { case IResourceDelta.ADDED: memo.put(PyDevBuilderVisitor.DOCUMENT_TIME, System.currentTimeMillis()); visitAddedResource(resource, FileUtilsFileBuffer.getDocOnCallbackFromResource(resource), monitor); isAddRemove = true; break; case IResourceDelta.CHANGED: memo.put(PyDevBuilderVisitor.DOCUMENT_TIME, System.currentTimeMillis()); visitChangedResource(resource, FileUtilsFileBuffer.getDocOnCallbackFromResource(resource), monitor); isAddRemove = true; break; } if (isAddRemove) { //communicate the progress currentResourcesVisited++; FastStringBuffer bufferToCreateString = new FastStringBuffer(); PyDevBuilder.communicateProgress(monitor, totalResources, currentResourcesVisited, resource, this, bufferToCreateString); } } catch (Exception e) { Log.log(e); } } } }