diff --git a/parsing.api/src/org/netbeans/modules/parsing/impl/indexing/errors/ErrorAnnotator.java b/parsing.api/src/org/netbeans/modules/parsing/impl/indexing/errors/ErrorAnnotator.java --- a/parsing.api/src/org/netbeans/modules/parsing/impl/indexing/errors/ErrorAnnotator.java +++ b/parsing.api/src/org/netbeans/modules/parsing/impl/indexing/errors/ErrorAnnotator.java @@ -40,8 +40,10 @@ */ package org.netbeans.modules.parsing.impl.indexing.errors; +import java.beans.PropertyChangeEvent; import org.netbeans.api.java.classpath.ClassPath; import java.awt.Image; +import java.beans.PropertyChangeListener; import java.io.File; import java.io.IOException; import java.net.URL; @@ -59,13 +61,16 @@ import org.netbeans.api.fileinfo.NonRecursiveFolder; import org.netbeans.api.project.FileOwnerQuery; import org.netbeans.api.project.Project; +import org.netbeans.api.project.ui.OpenProjects; import org.netbeans.modules.masterfs.providers.AnnotationProvider; import org.netbeans.modules.masterfs.providers.InterceptionListener; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileStateInvalidException; import org.openide.filesystems.FileStatusEvent; import org.openide.filesystems.FileUtil; +import org.openide.util.Exceptions; import org.openide.util.Lookup; +import org.openide.util.Mutex.ExceptionAction; import org.openide.util.RequestProcessor; import static org.openide.util.ImageUtilities.assignToolTipToImage; @@ -237,9 +242,10 @@ return null; } - private static final int IN_ERROR_REC = 1; - private static final int IN_ERROR_NONREC = 2; - private static final int INVALID = 4; + static final int IN_ERROR_REC = 1; + static final int IN_ERROR_NONREC = 2; + static final int INVALID = 4; + static final int FILE_IN_ERROR_NONREC_HACK = 8; private Map knownFiles2Error = new WeakHashMap(); @@ -276,7 +282,7 @@ private long cumulativeTime; private Collection toProcess = null; - + private final RequestProcessor.Task WORKER = new RequestProcessor("ErrorAnnotator worker", 1).create(new Runnable() { public void run() { long startTime = System.currentTimeMillis(); @@ -345,4 +351,76 @@ Logger.getLogger(ErrorAnnotator.class.getName()).log(Level.FINE, "time spent in error annotations computation: {0}, cumulative time: {1}", new Object[] {(endTime - startTime), (cumulativeTime += (endTime - startTime))}); } }); + + private static void fillInErrorCache(FileObject root, Map errors) { + TaskCache.getDefault().fillIn(root, errors); + } + + private static final RequestProcessor PRELOAD_WORKER = new RequestProcessor("ErrorAnnotator preload worker", 1, true, false); + private final Set preloaded = new HashSet(); + + private void preloadAll() { + long start = System.currentTimeMillis(); + try { + TaskCache.getDefault().refreshTransaction(new ExceptionAction() { + @Override + public Void run() throws Exception { + synchronized(ErrorAnnotator.this) { + Project[] open = OpenProjects.getDefault().getOpenProjects(); + Set removed = new HashSet(preloaded); + + for (Project prj : open) { + if (Thread.interrupted()) { + return null; + } + for (FileObject root : Utilities.findIndexedRootsUnderDirectory(prj, prj.getProjectDirectory())) { + if (Thread.interrupted()) { + return null; + } + fillInErrorCache(root, knownFiles2Error); + if (Thread.interrupted()) { + return null; + } + removed.remove(root); + preloaded.add(root); + } + } + + preloaded.removeAll(removed); + + return null; + } + } + }); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } finally { + long end = System.currentTimeMillis(); + + System.err.println("preloading took: " + (end - start)); + } + } + + private final RequestProcessor.Task preloadTask = PRELOAD_WORKER.create(new Runnable() { + @Override + public void run() { + preloadAll(); + } + }); + + private static final class ProjectOpenedListenerImpl implements PropertyChangeListener { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + ErrorAnnotator a = getAnnotator(); + + a.preloadTask.cancel(); + a.preloadTask.schedule(0); + } + + } + + public static void setProjectListener() { + OpenProjects.getDefault().addPropertyChangeListener(new ProjectOpenedListenerImpl()); + } } diff --git a/parsing.api/src/org/netbeans/modules/parsing/impl/indexing/errors/TaskCache.java b/parsing.api/src/org/netbeans/modules/parsing/impl/indexing/errors/TaskCache.java --- a/parsing.api/src/org/netbeans/modules/parsing/impl/indexing/errors/TaskCache.java +++ b/parsing.api/src/org/netbeans/modules/parsing/impl/indexing/errors/TaskCache.java @@ -58,6 +58,7 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.Queue; import java.util.Set; import java.util.logging.Level; @@ -374,6 +375,65 @@ } } } + + public boolean fillIn(FileObject root, Map errorsCache) { + try { + ClassPath cp = ClassPath.getClassPath(root, ClassPath.SOURCE); + + if (cp == null) { + return false; + } + + File cacheRoot = getCacheRoot(root.getURL(), true); + + if (cacheRoot == null) { + //index does not exist: + return false; + } + + fillInRecursivelly(root, cacheRoot, errorsCache); + return true; + } catch (IOException e) { + Logger.getLogger("global").log(Level.WARNING, null, e); + return false; + } + } + + private int fillInRecursivelly(FileObject fileOrFolder, File cache, Map errorsCache) { + if (true) fillInNoErrorBadge(fileOrFolder, errorsCache); + if (fileOrFolder.isFolder()) { + if (!cache.exists()) { + fillInNoErrorBadge(fileOrFolder, errorsCache); + return 0; + } + + int v = 0; + + for (FileObject c : fileOrFolder.getChildren()) { + int res = fillInRecursivelly(c, new File(cache, c.getNameExt()), errorsCache); + + v |= (res & ErrorAnnotator.IN_ERROR_REC) | (((res & ErrorAnnotator.FILE_IN_ERROR_NONREC_HACK) != 0) ? ErrorAnnotator.IN_ERROR_NONREC : 0); + } + + errorsCache.put(fileOrFolder, v); + + return v; + } else { + File c = new File(cache.getParentFile(), fileOrFolder.getName() + "." + ERR_EXT); + + return c.exists() ? ErrorAnnotator.IN_ERROR_NONREC | ErrorAnnotator.IN_ERROR_REC | ErrorAnnotator.FILE_IN_ERROR_NONREC_HACK : 0; + } + } + + private void fillInNoErrorBadge(FileObject fileOrFolder, Map errorsCache) { + if (fileOrFolder.isFolder()) { + for (FileObject c : fileOrFolder.getChildren()) { + fillInNoErrorBadge(c, errorsCache); + } + } + + errorsCache.put(fileOrFolder, 0); + } private boolean folderContainsErrors(File folder, boolean recursively) throws IOException { File[] errors = folder.listFiles(new FilenameFilter() {