Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/AllTypesCache.java')
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/AllTypesCache.java295
1 files changed, 295 insertions, 0 deletions
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/AllTypesCache.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/AllTypesCache.java
new file mode 100644
index 00000000000..1257fa18cae
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/AllTypesCache.java
@@ -0,0 +1,295 @@
+/*******************************************************************************
+ * Copyright (c) 2004 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.cdt.core.model.CoreModel;
+import org.eclipse.cdt.core.model.ElementChangedEvent;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.model.ICElementDelta;
+import org.eclipse.cdt.core.model.IElementChangedListener;
+import org.eclipse.cdt.core.model.IWorkingCopy;
+import org.eclipse.cdt.core.search.ICSearchScope;
+import org.eclipse.cdt.core.search.SearchEngine;
+import org.eclipse.cdt.internal.core.browser.cache.TypeCache;
+import org.eclipse.cdt.internal.core.browser.cache.TypeCacherJob;
+import org.eclipse.cdt.internal.core.browser.util.ArrayUtil;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.jobs.Job;
+
+/**
+ * Manages a search cache for types in the workspace. Instead of returning objects of type <code>ICElement</code>
+ * the methods of this class returns a list of the lightweight objects <code>TypeInfo</code>.
+ * <P>
+ * AllTypesCache runs asynchronously using a background job to rebuild the cache as needed.
+ * If the cache becomes dirty again while the background job is running, the job is restarted.
+ * <P>
+ * If <code>getTypes</code> is called in response to a user action, a progress dialog is shown.
+ * If called before the background job has finished, getTypes waits
+ * for the completion of the background job.
+ */
+public class AllTypesCache {
+
+ private static final int INITIAL_DELAY= 5000;
+ private static TypeCache fgCache;
+ private static TypeCacherJob fgJob;
+ private static TypeCacheDeltaListener fgDeltaListener;
+
+ /**
+ * Defines a simple interface in order to provide
+ * a level of abstraction between the Core and UI
+ * code.
+ */
+ public static interface IWorkingCopyProvider {
+ public IWorkingCopy[] getWorkingCopies();
+ }
+
+ /**
+ * Initializes the AllTypesCache service.
+ *
+ * @param provider A working copy provider.
+ */
+ public static void initialize(IWorkingCopyProvider provider) {
+ fgCache= new TypeCache();
+ fgJob= new TypeCacherJob(fgCache, provider);
+ fgDeltaListener= new TypeCacheDeltaListener(fgCache, fgJob);
+
+ // add delta listener
+ CoreModel.getDefault().addElementChangedListener(fgDeltaListener);
+
+ // schedule job to run after INITIAL_DELAY
+ if (fgJob.getState() != Job.RUNNING) {
+ fgJob.setSearchPaths(null);
+ fgJob.setPriority(Job.BUILD);
+ fgJob.schedule(INITIAL_DELAY);
+ }
+ }
+
+ /**
+ * Terminates the service provided by AllTypesCache.
+ */
+ public static void terminate() {
+ // remove delta listener
+ CoreModel.getDefault().removeElementChangedListener(fgDeltaListener);
+
+ // terminate background job
+ fgJob.cancel();
+ }
+
+ /*
+ * Returns the actual type cache.
+ */
+ public static TypeCache getCache() {
+ return fgCache;
+ }
+
+ /**
+ * Returns true if the type cache is up to date.
+ */
+ public static boolean isCacheUpToDate() {
+ return !fgCache.isDirty();
+ }
+
+ /**
+ * Returns all types in the given scope.
+ * @param scope The search scope
+ * @param kinds Array containing CElement types:
+ * C_NAMESPACE, C_CLASS, C_UNION, C_ENUMERATION, C_TYPEDEF
+ * @param monitor Progress monitor to display search progress
+ * @param typesFound The resulting <code>TypeInfo</code> elements are added to this collection
+ */
+ public static void getTypes(ICSearchScope scope, int[] kinds, IProgressMonitor monitor, Collection typesFound) {
+ if (!isCacheUpToDate()) {
+ // start job if not already running
+ if (fgJob.getState() != Job.RUNNING) {
+ // boost priority since action was user-initiated
+ fgJob.setSearchPaths(null);
+ fgJob.setPriority(Job.SHORT);
+ fgJob.schedule();
+ }
+
+ // wait for job to finish
+ try {
+ fgJob.join(monitor);
+ if (monitor != null)
+ monitor.done();
+ } catch (InterruptedException ex) {
+ return;
+ }
+ }
+
+ boolean isWorkspaceScope= scope.equals(SearchEngine.createWorkspaceScope());
+ for (Iterator typesIter= fgCache.getAllTypes().iterator(); typesIter.hasNext(); ) {
+ ITypeInfo info= (ITypeInfo) typesIter.next();
+ if ( ArrayUtil.contains(kinds, info.getType()) &&
+ (isWorkspaceScope || info.isEnclosed(scope)) ) {
+ typesFound.add(info);
+ }
+ }
+ }
+
+ /**
+ * Listener for changes to CModel.
+ * @see org.eclipse.cdt.core.model.IElementChangedListener
+ * @since 3.0
+ */
+ private static class TypeCacheDeltaListener implements IElementChangedListener {
+
+ private TypeCache fTypeCache;
+ private TypeCacherJob fTypeCacherJob;
+ private Set fPaths= new HashSet(5);
+ private Set fPrefixes= new HashSet(5);
+ private boolean fFlushAll= false;
+
+ public TypeCacheDeltaListener(TypeCache cache, TypeCacherJob job) {
+ fTypeCache= cache;
+ fTypeCacherJob= job;
+ }
+
+ /*
+ * @see IElementChangedListener#elementChanged
+ */
+ public void elementChanged(ElementChangedEvent event) {
+ fPaths.clear();
+ fPrefixes.clear();
+ fFlushAll= false;
+
+ boolean needsFlushing= processDelta(event.getDelta());
+ if (needsFlushing) {
+ // cancel background job
+ if (fTypeCacherJob.getState() == Job.RUNNING) {
+ // wait for job to finish?
+ try {
+ fTypeCacherJob.cancel();
+ fTypeCacherJob.join();
+ } catch (InterruptedException ex) {
+ }
+ }
+
+ if (fFlushAll) {
+ // flush the entire cache
+ fTypeCacherJob.setSearchPaths(null);
+ fTypeCache.flushAll();
+ } else {
+ // flush affected files from cache
+ Set searchPaths= new HashSet(10);
+ getPrefixMatches(fPrefixes, searchPaths);
+ searchPaths.addAll(fPaths);
+ fTypeCacherJob.setSearchPaths(searchPaths);
+ fTypeCache.flush(searchPaths);
+ }
+
+ // restart the background job
+ fTypeCacherJob.setPriority(Job.BUILD);
+ fTypeCacherJob.schedule();
+ }
+ }
+
+ /*
+ * returns true if the cache needs to be flushed
+ */
+ private boolean processDelta(ICElementDelta delta) {
+ ICElement elem= delta.getElement();
+ int pathEntryChanged= ICElementDelta.F_ADDED_PATHENTRY_SOURCE | ICElementDelta.F_REMOVED_PATHENTRY_SOURCE |
+ ICElementDelta.F_CHANGED_PATHENTRY_INCLUDE | ICElementDelta.F_CHANGED_PATHENTRY_MACRO;
+ boolean isAddedOrRemoved= (delta.getKind() != ICElementDelta.CHANGED)
+ || ((delta.getFlags() & pathEntryChanged) != 0);
+
+ switch (elem.getElementType()) {
+ case ICElement.C_MODEL:
+ {
+ if (isAddedOrRemoved) {
+ // CModel has changed
+ // flush the entire cache
+ fFlushAll= true;
+ return true;
+ }
+ return processDeltaChildren(delta);
+ }
+
+ case ICElement.C_PROJECT:
+ case ICElement.C_CCONTAINER:
+ {
+ if (isAddedOrRemoved) {
+ // project or folder has changed
+ // flush all files with matching prefix
+ IPath path= elem.getPath();
+ if (path != null)
+ fPrefixes.add(path);
+ return true;
+ }
+ return processDeltaChildren(delta);
+ }
+
+ case ICElement.C_NAMESPACE:
+ case ICElement.C_TEMPLATE_CLASS:
+ case ICElement.C_CLASS:
+ case ICElement.C_STRUCT:
+ case ICElement.C_UNION:
+ case ICElement.C_ENUMERATION:
+ case ICElement.C_TYPEDEF:
+ case ICElement.C_INCLUDE:
+ case ICElement.C_UNIT:
+ {
+ if (isAddedOrRemoved) {
+ // CElement has changed
+ // flush file from cache
+ IPath path= elem.getPath();
+ if (path != null)
+ fPaths.add(path);
+ return true;
+ }
+ return processDeltaChildren(delta);
+ }
+
+ default:
+ // fields, methods, imports ect
+ return false;
+ }
+ }
+
+ private boolean processDeltaChildren(ICElementDelta delta) {
+ ICElementDelta[] children= delta.getAffectedChildren();
+ for (int i= 0; i < children.length; i++) {
+ if (processDelta(children[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean getPrefixMatches(Set prefixes, Set results) {
+ Set pathSet= fTypeCache.getAllFiles();
+ if (pathSet.isEmpty() || prefixes == null || prefixes.isEmpty())
+ return false;
+
+ for (Iterator pathIter= pathSet.iterator(); pathIter.hasNext(); ) {
+ IPath path= (IPath) pathIter.next();
+
+ // find paths which match prefix
+ for (Iterator prefixIter= prefixes.iterator(); prefixIter.hasNext(); ) {
+ IPath prefix= (IPath) prefixIter.next();
+ if (prefix.isPrefixOf(path)) {
+ results.add(path);
+ break;
+ }
+ }
+ }
+
+ return !results.isEmpty();
+ }
+ }
+}

Back to the top