/******************************************************************************* * Copyright (c) 2007, 2009 Google, Inc 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: * Sergey Prigogin (Google) - initial API and implementation * Markus Schorn (Wind River Systems) *******************************************************************************/ package org.eclipse.cdt.internal.core.pdom.indexer; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.CCorePreferenceConstants; import org.eclipse.cdt.core.dom.ast.IASTComment; import org.eclipse.cdt.core.index.IIndexFileLocation; import org.eclipse.cdt.core.index.IndexLocationFactory; import org.eclipse.cdt.core.model.ICModelMarker; import org.eclipse.cdt.internal.core.pdom.ITodoTaskUpdater; import org.eclipse.cdt.internal.core.pdom.indexer.TodoTaskParser.Task; 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.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.resources.WorkspaceJob; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.MultiRule; import org.eclipse.osgi.util.NLS; public class TodoTaskUpdater implements ITodoTaskUpdater { private static final String SOURCE_ID = "CDT"; //$NON-NLS-1$ private static final String[] TASK_MARKER_ATTRIBUTE_NAMES = { IMarker.MESSAGE, IMarker.PRIORITY, IMarker.CHAR_START, IMarker.CHAR_END, IMarker.LINE_NUMBER, IMarker.USER_EDITABLE, IMarker.SOURCE_ID, }; private final TodoTaskParser taskParser; public TodoTaskUpdater() { String value = CCorePlugin.getOption(CCorePreferenceConstants.TODO_TASK_TAGS); if (value == null) { value = CCorePreferenceConstants.DEFAULT_TASK_TAGS; } String[] tags = split(value, ","); //$NON-NLS-1$ char[][] taskTags = new char[tags.length][]; for (int i = 0; i < tags.length; i++) { taskTags[i] = tags[i].toCharArray(); } value = CCorePlugin.getOption(CCorePreferenceConstants.TODO_TASK_PRIORITIES); if (value == null) { value = CCorePreferenceConstants.DEFAULT_TASK_PRIORITY; } String[] priorities = split(value, ","); //$NON-NLS-1$ int[] taskPriorities = new int[taskTags.length]; for (int i = 0; i < taskPriorities.length; i++) { String priority = i < priorities.length ? priorities[i] : CCorePreferenceConstants.DEFAULT_TASK_PRIORITY; taskPriorities[i] = CCorePreferenceConstants.TASK_PRIORITY_HIGH.equals(priority) ? IMarker.PRIORITY_HIGH : CCorePreferenceConstants.TASK_PRIORITY_LOW.equals(priority) ? IMarker.PRIORITY_LOW : IMarker.PRIORITY_NORMAL; } value = CCorePlugin.getOption(CCorePreferenceConstants.TODO_TASK_CASE_SENSITIVE); if (value == null) { value = CCorePreferenceConstants.DEFAULT_TASK_CASE_SENSITIVE; } boolean isTaskCaseSensitive = Boolean.valueOf(value).booleanValue(); taskParser = new TodoTaskParser(taskTags, taskPriorities, isTaskCaseSensitive); } public void updateTasks(IASTComment[] comments, IIndexFileLocation[] filesToUpdate) { class TaskList { IFile fFile; List<Task> fTasks; public TaskList(IFile file) { fFile= file; } public void add(Task task) { if (fTasks == null) { fTasks= new ArrayList<Task>(); } fTasks.add(task); } } final IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); // first collect all valid file-locations final Map<IPath, TaskList> pathToTaskList= new HashMap<IPath, TaskList>(); final Set<IProject> projects= new HashSet<IProject>(); for (final IIndexFileLocation indexFileLocation : filesToUpdate) { final String filepath = indexFileLocation.getFullPath(); if (filepath != null) { IFile file = workspaceRoot.getFile(new Path(filepath)); if (file != null && file.exists()) { projects.add(file.getProject()); pathToTaskList.put(IndexLocationFactory.getAbsolutePath(indexFileLocation), new TaskList(file)); } } } if (comments.length > 0) { final Task[] tasks = taskParser.parse(comments); for (final Task task : tasks) { TaskList list= pathToTaskList.get(new Path(task.getFileLocation())); if (list != null) { list.add(task); } } } // run this in a job in order not to block the indexer (bug 210730). if (!pathToTaskList.isEmpty()) { WorkspaceJob job= new WorkspaceJob(Messages.TodoTaskUpdater_UpdateJob) { @Override public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException { MultiStatus status= new MultiStatus(CCorePlugin.PLUGIN_ID, 0, Messages.TodoTaskUpdater_UpdateJob, null); for (TaskList tasklist : pathToTaskList.values()) { final IFile file= tasklist.fFile; try { if (file.exists()) { file.deleteMarkers(ICModelMarker.TASK_MARKER, false, IResource.DEPTH_INFINITE); final List<Task> tasks= tasklist.fTasks; if (tasks != null) { for (Task task : tasks) { applyTask(task, file); } } } } catch (CoreException e) { if (file.exists()) { status.add(e.getStatus()); } } } return status; } }; job.setRule(new MultiRule(projects.toArray(new IProject[projects.size()]))); job.setSystem(true); job.schedule(); } } private void applyTask(Task task, IResource resource) throws CoreException { IMarker marker = resource.createMarker(ICModelMarker.TASK_MARKER); String description = NLS.bind(Messages.TodoTaskUpdater_taskFormat, task.getTag(), task.getMessage()); marker.setAttributes( TASK_MARKER_ATTRIBUTE_NAMES, new Object[] { description, new Integer(task.getPriority()), new Integer(task.getStart()), new Integer(task.getEnd()), new Integer(task.getLineNumber()), Boolean.FALSE, SOURCE_ID }); } private String[] split(String value, String delimiters) { StringTokenizer tokenizer = new StringTokenizer(value, delimiters); int size = tokenizer.countTokens(); String[] tokens = new String[size]; for (int i = 0; i < size; i++) tokens[i] = tokenizer.nextToken(); return tokens; } public static void removeTasksFor(final IResource resource) { if (resource == null || !resource.exists()) { return; } // run this in a job in order not to block the indexer (bug 210730). WorkspaceJob job= new WorkspaceJob(Messages.TodoTaskUpdater_DeleteJob) { @Override public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException { try { if (!resource.exists()) { return Status.CANCEL_STATUS; } resource.deleteMarkers(ICModelMarker.TASK_MARKER, false, IResource.DEPTH_INFINITE); } catch (CoreException e) { if (resource.exists()) { return e.getStatus(); } } return Status.OK_STATUS; } }; job.setRule(resource); job.setSystem(true); job.schedule(); } }