Skip to main content

This CGIT instance is deprecated, and repositories have been moved to Gitlab or Github. See the repository descriptions for specific locations.

summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornitind2005-06-03 20:10:06 +0000
committernitind2005-06-03 20:10:06 +0000
commitb2adeabdded1c81215c37e8bc6152d7f8dfec5c2 (patch)
tree399e0754d441da6074de24c7f430184520db9702 /bundles/org.eclipse.wst.sse.core/src-tasktags/org
parentf74f77b039f2900392176d48632b4458dbdf5398 (diff)
downloadwebtools.sourceediting-b2adeabdded1c81215c37e8bc6152d7f8dfec5c2.tar.gz
webtools.sourceediting-b2adeabdded1c81215c37e8bc6152d7f8dfec5c2.tar.xz
webtools.sourceediting-b2adeabdded1c81215c37e8bc6152d7f8dfec5c2.zip
update task tags for separate source folder, new preferences, naming
Diffstat (limited to 'bundles/org.eclipse.wst.sse.core/src-tasktags/org')
-rw-r--r--bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/provisional/tasks/IFileTaskScanner.java69
-rw-r--r--bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/provisional/tasks/TaskTag.java42
-rw-r--r--bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/tasks/FileTaskScannerRegistryReader.java185
-rw-r--r--bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/tasks/StructuredFileTaskScanner.java336
-rw-r--r--bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/tasks/TaskScanningJob.java217
-rw-r--r--bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/tasks/TaskScanningScheduler.java143
-rw-r--r--bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/tasks/TaskTagPreferenceKeys.java24
-rw-r--r--bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/tasks/WorkspaceTaskScanner.java427
8 files changed, 1443 insertions, 0 deletions
diff --git a/bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/provisional/tasks/IFileTaskScanner.java b/bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/provisional/tasks/IFileTaskScanner.java
new file mode 100644
index 0000000000..1b9d9f0a0f
--- /dev/null
+++ b/bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/provisional/tasks/IFileTaskScanner.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 IBM Corporation 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:
+ * IBM Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.sse.core.internal.provisional.tasks;
+
+import java.util.Map;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.wst.sse.core.internal.SSECorePlugin;
+
+/**
+ * Delegates for the main Task Scanner. Delegates may be contributed using the
+ * org.eclipse.wst.sse.core.taskscanner extension point. For resources and
+ * resource deltas with matching content types, the main scanner will first
+ * call the startup() method, scan(), and then shutdown() in sequence. Scanner
+ * instances will be reused across projects but are not shared per content
+ * type. Delegates should not hold on to references to models or resources
+ * after shutdown() and should take care not to leak memory or resources.
+ */
+public interface IFileTaskScanner {
+ String TASK_MARKER_ID = SSECorePlugin.ID + ".task"; //$NON-NLS-1$;
+
+ /**
+ * Requests that the list of automatically discovered tasks for the given
+ * file be updated. Once completed, the list of tasks should correspond
+ * exactly to the file's contents.
+ *
+ * @param file -
+ * the file to be scanned
+ * @param taskTags -
+ * the list of task tags for which to scan
+ * @param monitor -
+ * a progress monitor
+ * @return an array of maps containing the attributes for task markers to
+ * be created
+ */
+ Map[] scan(IFile file, TaskTag[] taskTags, IProgressMonitor monitor);
+
+ /**
+ * Notifies the delegate that scanning is done for now. Resources held
+ * from startup should now be released.
+ *
+ * @param project -
+ * the project that was just scanned
+ */
+ void shutdown(IProject project);
+
+ /**
+ * Notifies the delegate that a sequence of scans is about to be
+ * requested. Ideally the time to load preferences and perform any
+ * expensive configuration for the given project.
+ *
+ * @param project -
+ * the project that is about to be scanned
+ *
+ */
+ void startup(IProject project);
+}
diff --git a/bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/provisional/tasks/TaskTag.java b/bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/provisional/tasks/TaskTag.java
new file mode 100644
index 0000000000..80353586fe
--- /dev/null
+++ b/bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/provisional/tasks/TaskTag.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2005 IBM Corporation 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:
+ * IBM Corporation - initial API and implementation
+ *
+ *******************************************************************************/
+package org.eclipse.wst.sse.core.internal.provisional.tasks;
+
+import org.eclipse.core.resources.IMarker;
+
+public final class TaskTag {
+
+ public static final int PRIORITY_HIGH = IMarker.PRIORITY_HIGH;
+ public static final int PRIORITY_LOW = IMarker.PRIORITY_LOW;
+ public static final int PRIORITY_NORMAL = IMarker.PRIORITY_NORMAL;
+
+ private int fPriority = PRIORITY_NORMAL;
+ private String fTag = null;
+
+ public TaskTag(String tag, int priority) {
+ super();
+ fTag = tag;
+ fPriority = priority;
+ }
+
+ public int getPriority() {
+ return fPriority;
+ }
+
+ public String getTag() {
+ return fTag;
+ }
+
+ public String toString() {
+ return getTag() + ":" + getPriority();
+ }
+}
diff --git a/bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/tasks/FileTaskScannerRegistryReader.java b/bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/tasks/FileTaskScannerRegistryReader.java
new file mode 100644
index 0000000000..d78354fd00
--- /dev/null
+++ b/bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/tasks/FileTaskScannerRegistryReader.java
@@ -0,0 +1,185 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 IBM Corporation 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:
+ * IBM Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.sse.core.internal.tasks;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.content.IContentType;
+import org.eclipse.core.runtime.content.IContentTypeManager;
+import org.eclipse.wst.sse.core.internal.Logger;
+import org.eclipse.wst.sse.core.internal.SSECorePlugin;
+import org.eclipse.wst.sse.core.internal.provisional.tasks.IFileTaskScanner;
+import org.eclipse.wst.sse.core.internal.util.StringUtils;
+
+public class FileTaskScannerRegistryReader {
+ private class ScannerInfo {
+ String fId;
+ IFileTaskScanner fScanner;
+
+ ScannerInfo(String id, IFileTaskScanner scanner) {
+ super();
+ fId = id;
+ fScanner = scanner;
+ }
+
+ public boolean equals(Object obj) {
+ return obj instanceof ScannerInfo && fId.equals(((ScannerInfo) obj).fId);
+ }
+
+ public String getId() {
+ return fId;
+ }
+
+ public IFileTaskScanner getScanner() {
+ return fScanner;
+ }
+ }
+
+ private static final boolean _debugReader = "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.wst.sse.core/tasks/registry")); //$NON-NLS-1$ //$NON-NLS-2$
+
+ private static FileTaskScannerRegistryReader _instance = null;
+
+ public static FileTaskScannerRegistryReader getInstance() {
+ if (_instance == null) {
+ _instance = new FileTaskScannerRegistryReader();
+ }
+ return _instance;
+ }
+
+ private String ATT_CLASS = "class"; //$NON-NLS-1$
+
+ private String ATT_CONTENT_TYPES = "contentTypeIds"; //$NON-NLS-1$
+
+ private String ATT_ID = "id"; //$NON-NLS-1$
+
+ private IConfigurationElement[] fScannerElements;
+
+ // a mapping from content types to ScannerInfo instances
+ private Map fScannerInfos = null;
+
+ private String NAME_SCANNER = "scanner"; //$NON-NLS-1$
+
+ private String SCANNER_EXTENSION_POINT_ID = SSECorePlugin.ID + ".taskscanner"; //$NON-NLS-1$
+
+ private FileTaskScannerRegistryReader() {
+ super();
+ }
+
+ IFileTaskScanner[] getFileTaskScanners(IContentType[] contentTypes) {
+ if (fScannerElements == null) {
+ readRegistry();
+ }
+
+ List scannerInfos = new ArrayList(1);
+
+ for (int i = 0; i < contentTypes.length; i++) {
+ ScannerInfo[] scannerInfosForContentType = (ScannerInfo[]) fScannerInfos.get(contentTypes[i].getId());
+ if (scannerInfosForContentType == null) {
+ scannerInfosForContentType = loadScanners(contentTypes[i]);
+ }
+ // only add non-duplicate scanners
+ for (int j = 0; j < scannerInfosForContentType.length; j++) {
+ if (!scannerInfos.contains(scannerInfosForContentType[j])) {
+ scannerInfos.add(scannerInfosForContentType[j]);
+ }
+ }
+ }
+ IFileTaskScanner[] scanners = new IFileTaskScanner[scannerInfos.size()];
+ for (int i = 0; i < scanners.length; i++) {
+ scanners[i] = ((ScannerInfo) scannerInfos.get(i)).getScanner();
+ }
+ return scanners;
+ }
+
+ public String[] getSupportedContentTypeIds() {
+ if (fScannerElements == null) {
+ readRegistry();
+ }
+
+ // find the relevant extensions
+ List types = new ArrayList(0);
+ IConfigurationElement[] scannerElements = fScannerElements;
+ for (int j = 0; j < scannerElements.length; j++) {
+ if (!scannerElements[j].getName().equals(NAME_SCANNER))
+ continue;
+ String[] contentTypeIds = StringUtils.unpack(scannerElements[j].getAttribute(ATT_CONTENT_TYPES));
+ for (int i = 0; i < contentTypeIds.length; i++) {
+ if (!types.contains(contentTypeIds[i])) {
+ types.add(contentTypeIds[i]);
+ }
+ }
+ }
+
+ return (String[]) types.toArray(new String[types.size()]);
+ }
+
+ private ScannerInfo[] loadScanners(IContentType contentType) {
+ List elements = new ArrayList(0);
+ ScannerInfo[] scannerInfos = null;
+ IConfigurationElement[] delegateElements = fScannerElements;
+ if (contentType != null) {
+ IContentTypeManager contentTypeManager = Platform.getContentTypeManager();
+ for (int j = 0; j < delegateElements.length; j++) {
+ if (!delegateElements[j].getName().equals(NAME_SCANNER))
+ continue;
+ String[] supportedContentTypeIds = StringUtils.unpack(delegateElements[j].getAttribute(ATT_CONTENT_TYPES));
+ IContentType[] supportedContentTypes = new IContentType[supportedContentTypeIds.length];
+ for (int k = 0; k < supportedContentTypeIds.length; k++) {
+ supportedContentTypes[k] = contentTypeManager.getContentType(supportedContentTypeIds[k].trim());
+ }
+ for (int k = 0; k < supportedContentTypeIds.length; k++) {
+ // allow subtypes to be returned as well
+ if (supportedContentTypes[k] != null && contentType.isKindOf(supportedContentTypes[k])) {
+ elements.add(delegateElements[j]);
+ }
+ }
+ }
+ // instantiate and save the scanners
+ List scannerInfoList = new ArrayList(elements.size());
+ for (int i = 0; i < elements.size(); i++) {
+ try {
+ IFileTaskScanner scanner = (IFileTaskScanner) ((IConfigurationElement) elements.get(i)).createExecutableExtension(ATT_CLASS);
+ if (scanner != null) {
+ scannerInfoList.add(new ScannerInfo(((IConfigurationElement) elements.get(i)).getAttribute(ATT_ID), scanner));
+ }
+ }
+ catch (CoreException e) {
+ Logger.logException("Non-fatal exception creating task scanner for " + contentType.getId(), e); //$NON-NLS-1$
+ }
+ }
+ scannerInfos = (ScannerInfo[]) scannerInfoList.toArray(new ScannerInfo[scannerInfoList.size()]);
+ fScannerInfos.put(contentType.getId(), scannerInfos);
+ if (_debugReader) {
+ System.out.println("Created " + scannerInfos.length + " task scanner for " + contentType.getId()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+ return scannerInfos;
+ }
+
+ private void readRegistry() {
+ fScannerInfos = new HashMap();
+ // Just remember the elements, so plugins don't have to be activated,
+ // unless extension attributes match those of interest
+ IExtensionPoint point = Platform.getExtensionRegistry().getExtensionPoint(SCANNER_EXTENSION_POINT_ID);
+ if (point != null) {
+ fScannerElements = point.getConfigurationElements();
+ }
+ }
+}
diff --git a/bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/tasks/StructuredFileTaskScanner.java b/bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/tasks/StructuredFileTaskScanner.java
new file mode 100644
index 0000000000..c24ce9432f
--- /dev/null
+++ b/bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/tasks/StructuredFileTaskScanner.java
@@ -0,0 +1,336 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 IBM Corporation 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:
+ * IBM Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.sse.core.internal.tasks;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.CharacterCodingException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.core.runtime.content.IContentDescription;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.Document;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.wst.sse.core.internal.Logger;
+import org.eclipse.wst.sse.core.internal.document.DocumentReader;
+import org.eclipse.wst.sse.core.internal.ltk.modelhandler.IModelHandler;
+import org.eclipse.wst.sse.core.internal.ltk.parser.RegionParser;
+import org.eclipse.wst.sse.core.internal.ltk.parser.StructuredDocumentRegionHandler;
+import org.eclipse.wst.sse.core.internal.ltk.parser.StructuredDocumentRegionParser;
+import org.eclipse.wst.sse.core.internal.modelhandler.ModelHandlerRegistry;
+import org.eclipse.wst.sse.core.internal.provisional.document.IEncodedDocument;
+import org.eclipse.wst.sse.core.internal.provisional.tasks.IFileTaskScanner;
+import org.eclipse.wst.sse.core.internal.provisional.tasks.TaskTag;
+import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
+import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
+import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionList;
+
+/**
+ * A delegate to create IMarker.TASKs for "todos" and similiar comments.
+ */
+public abstract class StructuredFileTaskScanner implements IFileTaskScanner {
+
+ private static final boolean _debug = "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.wst.sse.core/tasks")); //$NON-NLS-1$ //$NON-NLS-2$
+ protected static final boolean _debugPerf = "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.wst.sse.core/tasks/time")); //$NON-NLS-1$ //$NON-NLS-2$
+
+ // the list of attributes for the new tasks for the current file
+ protected List fNewMarkerAttributeMaps = null;
+
+ List oldMarkers = null;
+ private long time0;
+
+ public StructuredFileTaskScanner() {
+ super();
+ fNewMarkerAttributeMaps = new ArrayList();
+ if (_debug) {
+ System.out.println(getClass().getName() + " instance created"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Returns the attributes with which a newly created marker will be
+ * initialized. Modified from the method in MarkerRulerAction
+ *
+ * @return the initial marker attributes
+ */
+ protected Map createInitialMarkerAttributes(String text, int documentLine, int startOffset, int length, int priority) {
+ Map attributes = new HashMap(6);
+ // marker line numbers are 1-based
+ attributes.put(IMarker.LINE_NUMBER, new Integer(documentLine + 1));
+ attributes.put(IMarker.CHAR_START, new Integer(startOffset));
+ attributes.put(IMarker.CHAR_END, new Integer(startOffset + length));
+ attributes.put(IMarker.MESSAGE, text);
+ attributes.put(IMarker.USER_EDITABLE, Boolean.TRUE);
+ attributes.put("org.eclipse.ui.part.IShowInTarget", new String[]{""});
+
+ switch (priority) {
+ case IMarker.PRIORITY_HIGH : {
+ attributes.put(IMarker.PRIORITY, new Integer(IMarker.PRIORITY_HIGH));
+ }
+ break;
+ case IMarker.PRIORITY_LOW : {
+ attributes.put(IMarker.PRIORITY, new Integer(IMarker.PRIORITY_LOW));
+ }
+ break;
+ default : {
+ attributes.put(IMarker.PRIORITY, new Integer(IMarker.PRIORITY_NORMAL));
+ }
+ }
+
+ return attributes;
+ }
+
+ private String detectCharset(IFile file) {
+ if (file.getType() == IResource.FILE && file.isAccessible()) {
+ IContentDescription d = null;
+ try {
+ // optimized description lookup, might not succeed
+ d = file.getContentDescription();
+ if (d != null)
+ return d.getCharset();
+ }
+ catch (CoreException e) {
+ /*
+ * should not be possible given the accessible and file type
+ * check above
+ */
+ }
+ InputStream contents = null;
+ try {
+ contents = file.getContents();
+ IContentDescription description = Platform.getContentTypeManager().getDescriptionFor(contents, file.getName(), new QualifiedName[]{IContentDescription.CHARSET});
+ if (description != null) {
+ return description.getCharset();
+ }
+ }
+ catch (IOException e) {
+ // will try to cleanup in finally
+ }
+ catch (CoreException e) {
+ Logger.logException(e);
+ }
+ finally {
+ if (contents != null) {
+ try {
+ contents.close();
+ }
+ catch (Exception e) {
+ // not sure how to recover at this point
+ }
+ }
+ }
+ }
+ return ResourcesPlugin.getEncoding();
+ }
+
+ /**
+ * @param document
+ * @param documentRegion
+ * @param comment
+ */
+ protected void findTasks(IDocument document, TaskTag[] taskTags, IStructuredDocumentRegion documentRegion, ITextRegion comment) {
+ if (isCommentRegion(documentRegion, comment)) {
+ int startOffset = documentRegion.getStartOffset(comment);
+ int endOffset = documentRegion.getTextEndOffset(comment);
+ try {
+ int startLine = document.getLineOfOffset(startOffset);
+ int endLine = document.getLineOfOffset(endOffset);
+ for (int lineNumber = startLine; lineNumber <= endLine; lineNumber++) {
+ IRegion line = document.getLineInformation(lineNumber);
+ int begin = Math.max(startOffset, line.getOffset());
+ int end = Math.min(endOffset, line.getOffset() + line.getLength());
+ int length = end - begin;
+
+ /* XXX: This generates a lot of garbage objects */
+
+ String commentedText = getCommentedText(document, begin, length);
+ String comparisonText = commentedText.toLowerCase(Locale.ENGLISH);
+
+ for (int i = 0; i < taskTags.length; i++) {
+ int tagIndex = comparisonText.indexOf(taskTags[i].getTag().toLowerCase(Locale.ENGLISH));
+ if (tagIndex >= 0) {
+ String markerDescription = commentedText.substring(tagIndex);
+ int markerOffset = begin + tagIndex;
+ int markerLength = end - markerOffset;
+ fNewMarkerAttributeMaps.add(createInitialMarkerAttributes(markerDescription, lineNumber, markerOffset, markerLength, taskTags[i].getPriority()));
+ }
+ }
+ }
+ }
+ catch (BadLocationException e) {
+ Logger.logException(e);
+ }
+ }
+ }
+
+ private void findTasks(IFile file, final TaskTag[] taskTags, IProgressMonitor monitor) {
+ try {
+ IModelHandler handler = ModelHandlerRegistry.getInstance().getHandlerFor(file);
+
+ // records if the optimized streamish parse was possible
+ boolean didStreamParse = false;
+ final IProgressMonitor progressMonitor = monitor;
+ final IEncodedDocument defaultDocument = handler.getDocumentLoader().createNewStructuredDocument();
+ if (defaultDocument instanceof IStructuredDocument) {
+ RegionParser parser = ((IStructuredDocument) defaultDocument).getParser();
+ if (parser instanceof StructuredDocumentRegionParser) {
+ didStreamParse = true;
+ String charset = detectCharset(file);
+ StructuredDocumentRegionParser documentParser = (StructuredDocumentRegionParser) parser;
+ final IDocument textDocument = new Document();
+ setDocumentContent(textDocument, file.getContents(true), charset);
+ documentParser.reset(new DocumentReader(textDocument));
+ documentParser.addStructuredDocumentRegionHandler(new StructuredDocumentRegionHandler() {
+ public void nodeParsed(IStructuredDocumentRegion documentRegion) {
+ ITextRegionList regions = documentRegion.getRegions();
+ for (int j = 0; j < regions.size(); j++) {
+ ITextRegion comment = regions.get(j);
+ findTasks(textDocument, taskTags, documentRegion, comment);
+ }
+ // disconnect the document regions
+ if (documentRegion.getPrevious() != null) {
+ documentRegion.getPrevious().setPrevious(null);
+ documentRegion.getPrevious().setNext(null);
+ }
+ if (progressMonitor.isCanceled()) {
+ textDocument.set(""); //$NON-NLS-1$
+ }
+ }
+
+ public void resetNodes() {
+ }
+ });
+ documentParser.getDocumentRegions();
+ }
+ }
+ if (!didStreamParse) {
+ // Use a StructuredDocument
+ IEncodedDocument document = handler.getDocumentLoader().createNewStructuredDocument(file);
+ if (document instanceof IStructuredDocument) {
+ IStructuredDocumentRegion documentRegion = ((IStructuredDocument) document).getFirstStructuredDocumentRegion();
+ while (documentRegion != null) {
+ ITextRegionList regions = documentRegion.getRegions();
+ for (int j = 0; j < regions.size(); j++) {
+ ITextRegion comment = regions.get(j);
+ findTasks(document, taskTags, documentRegion, comment);
+ }
+ documentRegion = documentRegion.getNext();
+ }
+ }
+ }
+ }
+ catch (CoreException e) {
+ Logger.logException("Exception with " + file.getFullPath().toString(), e); //$NON-NLS-1$
+ }
+ catch (CharacterCodingException e) {
+ Logger.log(Logger.INFO, "StructuredFileTaskScanner encountered CharacterCodingException reading " + file.getLocation()); //$NON-NLS-1$
+ }
+ catch (IOException e) {
+ Logger.logException(e);
+ }
+ }
+
+ protected String getCommentedText(IDocument document, int begin, int length) throws BadLocationException {
+ return document.get(begin, length);
+ }
+
+ protected abstract boolean isCommentRegion(IStructuredDocumentRegion region, ITextRegion textRegion);
+
+ public synchronized Map[] scan(IFile file, TaskTag[] taskTags, IProgressMonitor monitor) {
+ fNewMarkerAttributeMaps.clear();
+ if (monitor.isCanceled() || !shouldScan(file)) {
+ return new Map[0];
+ }
+ if (_debugPerf) {
+ time0 = System.currentTimeMillis();
+ }
+ if (taskTags.length > 0) {
+ findTasks(file, taskTags, monitor);
+ }
+ if (_debugPerf) {
+ System.out.println("" + (System.currentTimeMillis() - time0) + "ms for " + file.getLocation()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ return (Map[]) fNewMarkerAttributeMaps.toArray(new Map[fNewMarkerAttributeMaps.size()]);
+ }
+
+ /**
+ * Sets the document content from this stream and closes the stream
+ */
+ protected void setDocumentContent(IDocument document, InputStream contentStream, String charset) {
+ Reader in = null;
+ try {
+ in = new BufferedReader(new InputStreamReader(contentStream, charset), 2048);
+ StringBuffer buffer = new StringBuffer(2048);
+ char[] readBuffer = new char[2048];
+ int n = in.read(readBuffer);
+ while (n > 0) {
+ buffer.append(readBuffer, 0, n);
+ n = in.read(readBuffer);
+ }
+ document.set(buffer.toString());
+ }
+ catch (IOException x) {
+ }
+ finally {
+ if (in != null) {
+ try {
+ in.close();
+ }
+ catch (IOException x) {
+ }
+ }
+ }
+ }
+
+ boolean shouldScan(IResource r) {
+ // skip "dot" files
+ String s = r.getName();
+ return s.length() == 0 || s.charAt(0) != '.';
+ }
+
+ public void shutdown(IProject project) {
+ if (_debug) {
+ System.out.println(this + " shutdown for " + project.getName()); //$NON-NLS-1$
+ }
+ }
+
+ public void startup(IProject project) {
+ if (_debug) {
+ System.out.println(this + " startup for " + project.getName()); //$NON-NLS-1$
+ }
+ if (_debugPerf) {
+ time0 = System.currentTimeMillis();
+ }
+ if (_debugPerf) {
+ System.out.println("" + (System.currentTimeMillis() - time0) + "ms loading prefs for " + project.getName()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+}
diff --git a/bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/tasks/TaskScanningJob.java b/bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/tasks/TaskScanningJob.java
new file mode 100644
index 0000000000..a46b5cbdfd
--- /dev/null
+++ b/bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/tasks/TaskScanningJob.java
@@ -0,0 +1,217 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2005 IBM Corporation 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:
+ * IBM Corporation - initial API and implementation
+ *
+ *******************************************************************************/
+package org.eclipse.wst.sse.core.internal.tasks;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.wst.sse.core.internal.SSECoreMessages;
+import org.eclipse.wst.sse.core.internal.SSECorePlugin;
+import org.eclipse.wst.sse.core.internal.util.StringUtils;
+import org.osgi.framework.Bundle;
+
+/**
+ * Queueing Job for processing deltas and projects.
+ */
+class TaskScanningJob extends Job {
+ public static final boolean _debugJob = "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.wst.sse.core/tasks/job"));
+ static final String TASK_TAG_PROJECTS_ALREADY_SCANNED = "task-tag-projects-already-scanned"; //$NON-NLS-1$
+ private List fQueue = null;
+
+ /** symbolic name for OSGI framework */
+ private final String OSGI_FRAMEWORK_ID = "org.eclipse.osgi"; //$NON-NLS-1$
+
+ TaskScanningJob() {
+ super(SSECoreMessages.TaskScanner_0);
+ fQueue = new ArrayList();
+ setPriority(Job.DECORATE);
+ setSystem(false);
+
+ SSECorePlugin.getDefault().getPluginPreferences().setDefault(TASK_TAG_PROJECTS_ALREADY_SCANNED, "");
+ }
+
+ synchronized void addDelta(IResourceDelta delta) {
+ fQueue.add(delta);
+ if (_debugJob) {
+ String kind = null;
+ switch (delta.getKind()) {
+ case IResourceDelta.ADDED :
+ kind = " [IResourceDelta.ADDED]"; //$NON-NLS-1$
+ break;
+ case IResourceDelta.CHANGED :
+ kind = " [IResourceDelta.CHANGED]"; //$NON-NLS-1$
+ break;
+ case IResourceDelta.REMOVED :
+ kind = " [IResourceDelta.REMOVED]"; //$NON-NLS-1$
+ break;
+ case IResourceDelta.ADDED_PHANTOM :
+ kind = " [IResourceDelta.ADDED_PHANTOM]"; //$NON-NLS-1$
+ break;
+ case IResourceDelta.REMOVED_PHANTOM :
+ kind = " [IResourceDelta.REMOVED_PHANTOM]"; //$NON-NLS-1$
+ break;
+ }
+ System.out.println("Adding delta " + delta.getFullPath() + kind);
+ }
+ schedule(100);
+ }
+
+ synchronized void addProject(IProject project) {
+ if (isEnabledProject(project)) {
+ fQueue.add(project);
+ if (_debugJob) {
+ System.out.println("Adding project " + project.getName());
+ }
+ schedule(600);
+ }
+ }
+
+ /**
+ * A check to see if the OSGI framework is shutting down.
+ *
+ * @return true if the System Bundle is stopped (ie. the framework is
+ * shutting down)
+ */
+ boolean frameworkIsShuttingDown() {
+ // in the Framework class there's a note:
+ // set the state of the System Bundle to STOPPING.
+ // this must be done first according to section 4.19.2 from the OSGi
+ // R3 spec.
+ boolean shuttingDown = Platform.getBundle(OSGI_FRAMEWORK_ID).getState() == Bundle.STOPPING;
+ if (_debugJob && shuttingDown) {
+ System.out.println("TaskScanningJob: system is shutting down!"); //$NON-NLS-1$
+ }
+ return shuttingDown;
+ }
+
+ private boolean isEnabledProject(IResource project) {
+ String[] projectsScanned = StringUtils.unpack(SSECorePlugin.getDefault().getPluginPreferences().getString(TASK_TAG_PROJECTS_ALREADY_SCANNED));
+
+ boolean shouldScan = true;
+ String name = project.getName();
+ for (int j = 0; shouldScan && j < projectsScanned.length; j++) {
+ if (projectsScanned[j].equals(name)) {
+ if (_debugJob)
+ System.out.println("Scanning Job skipping " + project.getName());
+ shouldScan = false;
+ }
+ }
+ return shouldScan;
+ }
+
+ synchronized List retrieveQueue() {
+ List queue = fQueue;
+ fQueue = new ArrayList();
+ return queue;
+ }
+
+ protected IStatus run(IProgressMonitor monitor) {
+ validateRememberedProjectList(TASK_TAG_PROJECTS_ALREADY_SCANNED);
+
+ IStatus status = null;
+ List currentQueue = retrieveQueue();
+ List errors = null;
+ int ticks = currentQueue.size();
+ String taskName = null;
+ if (_debugJob) {
+ taskName = "Scanning (" + ticks + " work items)";
+ }
+ else {
+ taskName = "Scanning";
+ }
+ monitor.beginTask(taskName, ticks);
+
+ IProgressMonitor scanMonitor = null;
+ while (!currentQueue.isEmpty()) {
+ Object o = currentQueue.remove(0);
+ if (frameworkIsShuttingDown())
+ return Status.OK_STATUS;
+ try {
+ scanMonitor = new SubProgressMonitor(monitor, 1);
+ if (o instanceof IResourceDelta) {
+ WorkspaceTaskScanner.getInstance().scan((IResourceDelta) o, scanMonitor);
+ }
+ else if (o instanceof IProject) {
+ WorkspaceTaskScanner.getInstance().scan((IProject) o, scanMonitor);
+ String[] projectsPreviouslyScanned = StringUtils.unpack(SSECorePlugin.getDefault().getPluginPreferences().getString(TASK_TAG_PROJECTS_ALREADY_SCANNED));
+ String[] updatedProjects = new String[projectsPreviouslyScanned.length + 1];
+ updatedProjects[projectsPreviouslyScanned.length] = ((IResource) o).getName();
+ System.arraycopy(projectsPreviouslyScanned, 0, updatedProjects, 0, projectsPreviouslyScanned.length);
+ SSECorePlugin.getDefault().getPluginPreferences().setValue(TASK_TAG_PROJECTS_ALREADY_SCANNED, StringUtils.pack(updatedProjects));
+ }
+ }
+ catch (Exception e) {
+ if (errors == null) {
+ errors = new ArrayList();
+ }
+ errors.add(new Status(IStatus.ERROR, SSECorePlugin.ID, IStatus.ERROR, "", e));
+ }
+ }
+ monitor.done();
+
+ if (errors == null || errors.isEmpty()) {
+ status = Status.OK_STATUS;
+ }
+ else {
+ if (errors.size() == 1) {
+ status = (IStatus) errors.get(0);
+ }
+ else {
+ IStatus[] statii = (IStatus[]) errors.toArray(new IStatus[errors.size()]);
+ status = new MultiStatus(SSECorePlugin.ID, IStatus.ERROR, statii, "Errors while detecting Tasks", null);
+ }
+ }
+
+ SSECorePlugin.getDefault().savePluginPreferences();
+ return status;
+ }
+
+ private void validateRememberedProjectList(String preferenceName) {
+ String[] rememberedProjectNames = StringUtils.unpack(SSECorePlugin.getDefault().getPluginPreferences().getString(preferenceName));
+ IResource[] workspaceProjects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
+ String[] projectNames = new String[workspaceProjects.length];
+ for (int i = 0; i < projectNames.length; i++) {
+ projectNames[i] = workspaceProjects[i].getName();
+ }
+
+ List projectNamesToRemember = new ArrayList(rememberedProjectNames.length);
+ for (int i = 0; i < rememberedProjectNames.length; i++) {
+ boolean rememberedProjectExists = false;
+ for (int j = 0; !rememberedProjectExists && j < projectNames.length; j++) {
+ if (rememberedProjectNames[i].equals(projectNames[j])) {
+ rememberedProjectExists = true;
+ }
+ }
+ if (rememberedProjectExists) {
+ projectNamesToRemember.add(rememberedProjectNames[i]);
+ }
+ else if (_debugJob) {
+ System.out.println("Removing " + rememberedProjectNames[i] + " removed from " + preferenceName);
+ }
+ }
+
+ if (projectNamesToRemember.size() != rememberedProjectNames.length) {
+ SSECorePlugin.getDefault().getPluginPreferences().setValue(preferenceName, StringUtils.pack((String[]) projectNamesToRemember.toArray(new String[projectNamesToRemember.size()])));
+ }
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/tasks/TaskScanningScheduler.java b/bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/tasks/TaskScanningScheduler.java
new file mode 100644
index 0000000000..ce8156f794
--- /dev/null
+++ b/bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/tasks/TaskScanningScheduler.java
@@ -0,0 +1,143 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2005 IBM Corporation 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:
+ * IBM Corporation - initial API and implementation
+ *
+ *******************************************************************************/
+package org.eclipse.wst.sse.core.internal.tasks;
+
+import java.util.ArrayList;
+import java.util.List;
+
+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.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.wst.sse.core.internal.Logger;
+import org.eclipse.wst.sse.core.internal.SSECorePlugin;
+import org.eclipse.wst.sse.core.internal.provisional.tasks.IFileTaskScanner;
+import org.eclipse.wst.sse.core.internal.util.StringUtils;
+
+public class TaskScanningScheduler {
+ private class ListenerVisitor implements IResourceChangeListener, IResourceDeltaVisitor {
+ public void resourceChanged(IResourceChangeEvent event) {
+ IResourceDelta delta = event.getDelta();
+ if (delta.getResource() != null) {
+ int resourceType = delta.getResource().getType();
+ if (resourceType == IResource.PROJECT || resourceType == IResource.ROOT) {
+ try {
+ delta.accept(this);
+ }
+ catch (CoreException e) {
+ Logger.logException("Exception handling resource change", e); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ public boolean visit(IResourceDelta delta) throws CoreException {
+ if ((delta.getKind() & IResourceDelta.MARKERS) > 0 || (delta.getKind() & IResourceDelta.ENCODING) > 0 || (delta.getKind() & IResourceDelta.NO_CHANGE) > 0)
+ return false;
+
+ IResource resource = delta.getResource();
+ if (resource != null) {
+ if (resource.getType() == IResource.ROOT)
+ return true;
+ else if (resource.getType() == IResource.PROJECT) {
+ fJob.addDelta(delta);
+ return false;
+ }
+ }
+ return false;
+ }
+
+ }
+
+ private static TaskScanningScheduler scheduler;
+
+ public static void refresh() {
+ SSECorePlugin.getDefault().getPluginPreferences().setValue(TaskScanningJob.TASK_TAG_PROJECTS_ALREADY_SCANNED, ""); //$NON-NLS-1$
+ scheduler.enqueue(ResourcesPlugin.getWorkspace().getRoot());
+ }
+
+ public static void refresh(IProject project) {
+ String[] projectNames = StringUtils.unpack(SSECorePlugin.getDefault().getPluginPreferences().getString(TaskScanningJob.TASK_TAG_PROJECTS_ALREADY_SCANNED)); //$NON-NLS-1$
+ List freshProjectList = new ArrayList();
+ for (int i = 0; i < projectNames.length; i++) {
+ if (!projectNames[i].equals(project.getName())) {
+ freshProjectList.add(projectNames[i]);
+ }
+ }
+ String freshProjects = StringUtils.pack((String[]) freshProjectList.toArray(new String[freshProjectList.size()]));
+ SSECorePlugin.getDefault().getPluginPreferences().setValue(TaskScanningJob.TASK_TAG_PROJECTS_ALREADY_SCANNED, freshProjects); //$NON-NLS-1$
+
+ scheduler.enqueue(project);
+ }
+
+
+ /**
+ * Only for use by SSECorePlugin class
+ */
+ public static void shutdown() {
+ if (scheduler != null) {
+ ResourcesPlugin.getWorkspace().removeResourceChangeListener(scheduler.visitor);
+ }
+ }
+
+ /**
+ * Only for use by SSECorePlugin class
+ */
+ public static void startup() {
+ scheduler = new TaskScanningScheduler();
+
+ /*
+ * According to
+ * http://www.eclipse.org/eclipse/development/performance/bloopers.html,
+ * POST_CHANGE listeners add a trivial performance cost
+ */
+ ResourcesPlugin.getWorkspace().addResourceChangeListener(scheduler.visitor, IResourceChangeEvent.POST_CHANGE);
+
+ scheduler.enqueue(ResourcesPlugin.getWorkspace().getRoot());
+ }
+
+ TaskScanningJob fJob = null;
+
+ ListenerVisitor visitor = null;
+
+ private TaskScanningScheduler() {
+ super();
+ fJob = new TaskScanningJob();
+ visitor = new ListenerVisitor();
+ }
+
+ void enqueue(IProject project) {
+ try {
+ project.deleteMarkers(IFileTaskScanner.TASK_MARKER_ID, true, IResource.DEPTH_INFINITE);
+ }
+ catch (CoreException e) {
+ }
+ fJob.addProject(project);
+ }
+
+ void enqueue(IWorkspaceRoot root) {
+ try {
+ root.deleteMarkers(IFileTaskScanner.TASK_MARKER_ID, true, IResource.DEPTH_INFINITE);
+ }
+ catch (CoreException e) {
+ }
+ IProject[] allProjects = root.getProjects();
+ for (int i = 0; i < allProjects.length; i++) {
+ fJob.addProject(allProjects[i]);
+ }
+ }
+}
diff --git a/bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/tasks/TaskTagPreferenceKeys.java b/bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/tasks/TaskTagPreferenceKeys.java
new file mode 100644
index 0000000000..bb3e305a84
--- /dev/null
+++ b/bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/tasks/TaskTagPreferenceKeys.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2005 IBM Corporation 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:
+ * IBM Corporation - initial API and implementation
+ *
+ *******************************************************************************/
+package org.eclipse.wst.sse.core.internal.tasks;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.wst.sse.core.internal.SSECorePlugin;
+
+public final class TaskTagPreferenceKeys {
+ public static final String TASK_TAG_CONTENTTYPES_IGNORED = "ignored-contentTypes"; //$NON-NLS-1$
+ public static final String TASK_TAG_ENABLE = "enabled"; //$NON-NLS-1$
+ public static final String TASK_TAG_NODE = SSECorePlugin.ID + IPath.SEPARATOR + "task-tags"; //$NON-NLS-1$
+ public static final String TASK_TAG_PER_PROJECT = "use-project-settings"; //$NON-NLS-1$
+ public static final String TASK_TAG_PRIORITIES = "taskPriorities"; //$NON-NLS-1$
+ public static final String TASK_TAG_TAGS = "taskTags"; //$NON-NLS-1$
+}
diff --git a/bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/tasks/WorkspaceTaskScanner.java b/bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/tasks/WorkspaceTaskScanner.java
new file mode 100644
index 0000000000..8d31ff647d
--- /dev/null
+++ b/bundles/org.eclipse.wst.sse.core/src-tasktags/org/eclipse/wst/sse/core/internal/tasks/WorkspaceTaskScanner.java
@@ -0,0 +1,427 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 IBM Corporation 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:
+ * IBM Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.sse.core.internal.tasks;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.IWorkspaceRunnable;
+import org.eclipse.core.resources.ProjectScope;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.content.IContentDescription;
+import org.eclipse.core.runtime.content.IContentType;
+import org.eclipse.core.runtime.content.IContentTypeManager;
+import org.eclipse.core.runtime.preferences.DefaultScope;
+import org.eclipse.core.runtime.preferences.IPreferencesService;
+import org.eclipse.core.runtime.preferences.IScopeContext;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.wst.sse.core.internal.Logger;
+import org.eclipse.wst.sse.core.internal.provisional.tasks.IFileTaskScanner;
+import org.eclipse.wst.sse.core.internal.provisional.tasks.TaskTag;
+import org.eclipse.wst.sse.core.internal.util.StringUtils;
+
+/**
+ * Dispatcher for scanning based on deltas and requested projects
+ */
+class WorkspaceTaskScanner {
+ private static final boolean _debug = "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.wst.sse.core/tasks")); //$NON-NLS-1$ //$NON-NLS-2$
+ private static final boolean _debugContentTypeDetection = "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.wst.sse.core/tasks/detection")); //$NON-NLS-1$ //$NON-NLS-2$
+ private static final boolean _debugOverallPerf = "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.wst.sse.core/tasks/overalltime")); //$NON-NLS-1$ //$NON-NLS-2$
+ private static final boolean _debugPreferences = "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.wst.sse.core/tasks/preferences")); //$NON-NLS-1$ //$NON-NLS-2$
+
+ private static WorkspaceTaskScanner _instance = null;
+
+ static synchronized WorkspaceTaskScanner getInstance() {
+ if (_instance == null) {
+ _instance = new WorkspaceTaskScanner();
+ }
+ return _instance;
+ }
+
+ static String getTaskMarkerType() {
+ return IFileTaskScanner.TASK_MARKER_ID;
+ }
+
+ private List fActiveScanners = null;
+ private IContentType[] fCurrentIgnoreContentTypes = null;
+ private TaskTag[] fCurrentTaskTags = null;
+ private FileTaskScannerRegistryReader registry = null;
+
+ private long time0;
+
+
+ /**
+ *
+ */
+ private WorkspaceTaskScanner() {
+ super();
+ registry = FileTaskScannerRegistryReader.getInstance();
+ fActiveScanners = new ArrayList();
+ fCurrentTaskTags = new TaskTag[0];
+ fCurrentIgnoreContentTypes = new IContentType[0];
+ }
+
+ private IContentType[] detectContentTypes(IResource resource) {
+ IContentType[] types = null;
+ if (resource.getType() == IResource.FILE && resource.isAccessible()) {
+ types = Platform.getContentTypeManager().findContentTypesFor(resource.getName());
+ if (types.length == 0) {
+ IContentDescription d = null;
+ try {
+ // optimized description lookup, might not succeed
+ d = ((IFile) resource).getContentDescription();
+ if (d != null) {
+ types = new IContentType[]{d.getContentType()};
+ }
+ }
+ catch (CoreException e) {
+ /*
+ * should not be possible given the accessible and file
+ * type check above
+ */
+ }
+ }
+ if (types == null) {
+ types = Platform.getContentTypeManager().findContentTypesFor(resource.getName());
+ }
+ if (_debugContentTypeDetection) {
+ if (types.length > 0) {
+ if (types.length > 1) {
+ System.out.println(resource.getFullPath() + ": " + "multiple based on name (probably hierarchical)"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ for (int i = 0; i < types.length; i++) {
+ System.out.println(resource.getFullPath() + " matched: " + types[i].getId()); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+ return types;
+ }
+
+ /**
+ * @param resource
+ * @return
+ */
+ private IProject getProject(IResource resource) {
+ IProject project = null;
+ if (resource.getType() == IResource.PROJECT) {
+ project = (IProject) resource;
+ }
+ else {
+ project = resource.getProject();
+ }
+ return project;
+ }
+
+ private boolean init(IResource resource) {
+ IProject project = getProject(resource);
+
+ IPreferencesService preferencesService = Platform.getPreferencesService();
+ IScopeContext[] lookupOrder = new IScopeContext[]{new ProjectScope(project), new InstanceScope(), new DefaultScope()};
+
+ boolean proceed = preferencesService.getBoolean(TaskTagPreferenceKeys.TASK_TAG_NODE, TaskTagPreferenceKeys.TASK_TAG_ENABLE, false, lookupOrder);
+
+ if (_debugPreferences) {
+ System.out.println(getClass().getName() + " scan of " + resource.getFullPath() + ":" + proceed); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ if (proceed) {
+ String[] tags = StringUtils.unpack(preferencesService.getString(TaskTagPreferenceKeys.TASK_TAG_NODE, TaskTagPreferenceKeys.TASK_TAG_TAGS, null, lookupOrder));
+ String[] priorities = StringUtils.unpack(preferencesService.getString(TaskTagPreferenceKeys.TASK_TAG_NODE, TaskTagPreferenceKeys.TASK_TAG_PRIORITIES, null, lookupOrder));
+ String[] currentIgnoreContentTypeIDs = StringUtils.unpack(preferencesService.getString(TaskTagPreferenceKeys.TASK_TAG_NODE, TaskTagPreferenceKeys.TASK_TAG_CONTENTTYPES_IGNORED, null, lookupOrder));
+ if (_debugPreferences) {
+ System.out.print(getClass().getName() + " tags: "); //$NON-NLS-1$
+ for (int i = 0; i < tags.length; i++) {
+ if (i > 0) {
+ System.out.print(","); //$NON-NLS-1$
+ }
+ System.out.print(tags[i]);
+ }
+ System.out.println();
+ System.out.print(getClass().getName() + " priorities: "); //$NON-NLS-1$
+ for (int i = 0; i < priorities.length; i++) {
+ if (i > 0) {
+ System.out.print(","); //$NON-NLS-1$
+ }
+ System.out.print(priorities[i]);
+ }
+ System.out.println();
+ System.out.print(getClass().getName() + " ignored content types: "); //$NON-NLS-1$
+ for (int i = 0; i < currentIgnoreContentTypeIDs.length; i++) {
+ if (i > 0) {
+ System.out.print(","); //$NON-NLS-1$
+ }
+ System.out.print(currentIgnoreContentTypeIDs[i]);
+ }
+ System.out.println();
+ }
+ fCurrentIgnoreContentTypes = new IContentType[currentIgnoreContentTypeIDs.length];
+ IContentTypeManager contentTypeManager = Platform.getContentTypeManager();
+ for (int i = 0; i < currentIgnoreContentTypeIDs.length; i++) {
+ fCurrentIgnoreContentTypes[i] = contentTypeManager.getContentType(currentIgnoreContentTypeIDs[i]);
+ }
+ int max = Math.min(tags.length, priorities.length);
+ fCurrentTaskTags = new TaskTag[max];
+ for (int i = 0; i < max; i++) {
+ int priority = TaskTag.PRIORITY_NORMAL;
+ try {
+ priority = Integer.parseInt(priorities[i]);
+ }
+ catch (NumberFormatException e) {
+ // default to normal priority
+ }
+ fCurrentTaskTags[i] = new TaskTag(tags[i], priority);
+ }
+ }
+ return proceed;
+ }
+
+ void internalScan(final IProject project, final IResource resource, final IProgressMonitor scanMonitor) {
+ if (scanMonitor.isCanceled())
+ return;
+ try {
+ String name = resource.getName();
+ if (!resource.isDerived() && !resource.isPhantom() && !resource.isTeamPrivateMember() && name.length() != 0 && name.charAt(0) != '.') {
+ if ((resource.getType() & IResource.FOLDER) > 0 || (resource.getType() & IResource.PROJECT) > 0) {
+ SubProgressMonitor childMonitor = new SubProgressMonitor(scanMonitor, 1, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
+ IResource[] children = ((IContainer) resource).members();
+ childMonitor.beginTask("", children.length); //$NON-NLS-1$
+ for (int i = 0; i < children.length; i++) {
+ internalScan(project, children[i], childMonitor);
+ }
+ childMonitor.done();
+ }
+ else if ((resource.getType() & IResource.FILE) > 0) {
+ scanFile(project, fCurrentTaskTags, (IFile) resource, scanMonitor);
+ scanMonitor.worked(1);
+ }
+ }
+ else {
+ scanMonitor.worked(1);
+
+ }
+ scanMonitor.done();
+ }
+ catch (CoreException e) {
+ Logger.logException(e);
+ }
+ }
+
+ void internalScan(IResourceDelta delta, final IProgressMonitor monitor) {
+ if (monitor.isCanceled())
+ return;
+ try {
+ String name = delta.getFullPath().lastSegment();
+ IResource resource = delta.getResource();
+ if (!resource.isDerived() && !resource.isPhantom() && !resource.isTeamPrivateMember() && name.length() != 0 && name.charAt(0) != '.') {
+ if ((resource.getType() & IResource.FOLDER) > 0 || (resource.getType() & IResource.PROJECT) > 0) {
+ IResourceDelta[] children = delta.getAffectedChildren();
+ if (name.length() != 0 && name.charAt(0) != '.' && children.length > 0) {
+ SubProgressMonitor childMonitor = new SubProgressMonitor(monitor, 1, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
+ childMonitor.beginTask("", children.length); //$NON-NLS-1$
+ for (int i = children.length - 1; i >= 0; i--) {
+ internalScan(children[i], new SubProgressMonitor(childMonitor, 1, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK));
+ }
+ childMonitor.done();
+ }
+ else {
+ monitor.worked(1);
+ }
+ }
+ else if ((resource.getType() & IResource.FILE) > 0) {
+ if ((delta.getKind() & IResourceDelta.ADDED) > 0 || ((delta.getKind() & IResourceDelta.CHANGED) > 0 && (delta.getFlags() & IResourceDelta.CONTENT) > 0)) {
+ IFile file = (IFile) resource;
+ scanFile(file.getProject(), fCurrentTaskTags, file, monitor);
+ }
+ monitor.worked(1);
+ }
+ }
+ else {
+ monitor.worked(1);
+ }
+ }
+ catch (Exception e) {
+ monitor.done();
+ Logger.logException(e);
+ }
+ }
+
+ private void replaceMarkers(final IFile file, final Map markerAttributes[], IProgressMonitor monitor) {
+ final IFile finalFile = file;
+ if (file.isAccessible()) {
+ try {
+ IWorkspaceRunnable r = new IWorkspaceRunnable() {
+ public void run(IProgressMonitor progressMonitor) throws CoreException {
+ try {
+ // Delete old Task markers
+ file.deleteMarkers(getTaskMarkerType(), true, IResource.DEPTH_ZERO);
+ }
+ catch (CoreException e) {
+ Logger.logException("exception deleting old tasks", e); //$NON-NLS-1$
+ }
+ if (markerAttributes != null && markerAttributes.length > 0) {
+ if (_debug) {
+ System.out.println("" + markerAttributes.length + " tasks for " + file.getFullPath()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ for (int i = 0; i < markerAttributes.length; i++) {
+ IMarker marker = finalFile.createMarker(getTaskMarkerType());
+ marker.setAttributes(markerAttributes[i]);
+ }
+ }
+ }
+ };
+ finalFile.getWorkspace().run(r, file, IWorkspace.AVOID_UPDATE, monitor);
+ }
+ catch (CoreException e1) {
+ Logger.logException(e1);
+ }
+ }
+ }
+
+ void scan(final IProject project, final IProgressMonitor scanMonitor) {
+ if (scanMonitor.isCanceled())
+ return;
+ if (_debug) {
+ System.out.println(getClass().getName() + " scanning project " + project.getName()); //$NON-NLS-1$
+ }
+ if (_debugOverallPerf) {
+ time0 = System.currentTimeMillis();
+ }
+ try {
+ scanMonitor.beginTask("", project.members().length); //$NON-NLS-1$
+ if (init(project)) {
+ internalScan(project, project, scanMonitor);
+ shutdownDelegates(project);
+ }
+ scanMonitor.done();
+ }
+ catch (CoreException e) {
+ Logger.logException(e);
+ }
+ if (_debugOverallPerf) {
+ System.out.println("" + (System.currentTimeMillis() - time0) + "ms for " + project.getFullPath()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+
+ void scan(IResourceDelta delta, final IProgressMonitor monitor) {
+ if (monitor.isCanceled())
+ return;
+ if (_debugOverallPerf) {
+ time0 = System.currentTimeMillis();
+ }
+ monitor.beginTask("", 1); //$NON-NLS-1$
+ if (init(delta.getResource())) {
+ internalScan(delta, monitor);
+ shutdownDelegates(delta.getResource().getProject());
+ }
+ monitor.done();
+ if (_debugOverallPerf) {
+ System.out.println("" + (System.currentTimeMillis() - time0) + "ms for " + delta.getFullPath()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ void scanFile(IProject project, TaskTag[] taskTags, IFile file, IProgressMonitor monitor) {
+ if (monitor.isCanceled())
+ return;
+
+ SubProgressMonitor scannerMonitor = new SubProgressMonitor(monitor, 1, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
+ scannerMonitor.setTaskName(file.getFullPath().toString());
+ List markerAttributes = null;
+ IContentType[] types = detectContentTypes(file);
+ if (types != null) {
+ IFileTaskScanner[] fileScanners = null;
+ if (fCurrentIgnoreContentTypes.length == 0) {
+ fileScanners = registry.getFileTaskScanners(types);
+ }
+ else {
+ List validTypes = new ArrayList();
+ // obtain a filtered list of delegates
+ for (int i = 0; i < types.length; i++) {
+ boolean ignoreContentType = false;
+ for (int j = 0; j < fCurrentIgnoreContentTypes.length; j++) {
+ ignoreContentType = ignoreContentType || types[i].isKindOf(fCurrentIgnoreContentTypes[j]);
+ }
+ if (!ignoreContentType) {
+ validTypes.add(types[i]);
+ }
+ }
+ fileScanners = registry.getFileTaskScanners((IContentType[]) validTypes.toArray(new IContentType[validTypes.size()]));
+ }
+ if (fileScanners.length > 0) {
+ for (int j = 0; fileScanners != null && j < fileScanners.length; j++) {
+ if (scannerMonitor.isCanceled())
+ continue;
+ scannerMonitor.beginTask("", fileScanners.length);
+ try {
+ if (!fActiveScanners.contains(fileScanners[j]) && !monitor.isCanceled()) {
+ fileScanners[j].startup(file.getProject());
+ fActiveScanners.add(fileScanners[j]);
+ }
+ Map[] taskMarkerAttributes = fileScanners[j].scan(file, taskTags, scannerMonitor);
+ /*
+ * TODO: pool the marker results so there's only one
+ * operation creating them
+ */
+ for (int i = 0; i < taskMarkerAttributes.length; i++) {
+ if (markerAttributes == null) {
+ markerAttributes = new ArrayList();
+ }
+ markerAttributes.add(taskMarkerAttributes[i]);
+ }
+ scannerMonitor.worked(1);
+ }
+ catch (Exception e) {
+ Logger.logException(file.getFullPath().toString(), e);
+ }
+ }
+ scannerMonitor.done();
+ }
+ else {
+ monitor.worked(1);
+ }
+ }
+ if (markerAttributes != null) {
+ replaceMarkers(file, (Map[]) markerAttributes.toArray(new Map[markerAttributes.size()]), monitor);
+ }
+ else {
+ replaceMarkers(file, null, monitor);
+ }
+ }
+
+ /**
+ *
+ */
+ private void shutdownDelegates(IProject project) {
+ for (int j = 0; j < fActiveScanners.size(); j++) {
+ try {
+ ((IFileTaskScanner) fActiveScanners.get(j)).shutdown(project);
+ }
+ catch (Exception e) {
+ Logger.logException(project.getFullPath().toString(), e);
+ }
+ }
+ fActiveScanners = new ArrayList(1);
+ }
+}

Back to the top