/******************************************************************************* * Copyright (c) 2009, 2016 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 * Zend Technologies *******************************************************************************/ package org.eclipse.php.internal.core.preferences; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Set; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.dltk.annotations.NonNull; import org.eclipse.dltk.annotations.Nullable; import org.eclipse.php.internal.core.PHPCoreConstants; import org.eclipse.php.internal.core.PHPCorePlugin; import org.eclipse.wst.sse.core.internal.provisional.tasks.TaskTag; import org.eclipse.wst.sse.core.utils.StringUtils; /** * A task tags provider listens to any task-tags preferences changes and notify * any listener about the changes. * * @author shalom */ public class TaskTagsProvider { private static TaskTagsProvider instance; private HashMap<IProject, ITaskTagsListener> projectToTaskTagListener; private HashMap<IProject, IPreferencesPropagatorListener[]> projectToPropagatorListeners; private boolean isInstalled; private PreferencesSupport preferencesSupport; private PreferencesPropagator preferencesPropagator; private static final String NODES_QUALIFIER = PHPCorePlugin.ID; /** * Constructs a new TaskTagsProvider. */ private TaskTagsProvider() { install(); } /** * Returns a single instance of the TaskTagsProvider. * * @return A TaskTagsProvider instance */ public @NonNull static TaskTagsProvider getInstance() { if (instance == null) { instance = new TaskTagsProvider(); } return instance; } /** * Returns the Workspace task tags. * * @return The task tags defined for the workspace preferences. */ public @NonNull TaskTag[] getWorkspaceTaskTags() { String priorities = preferencesSupport.getWorkspacePreferencesValue(PHPCoreConstants.TASK_PRIORITIES); String tags = preferencesSupport.getWorkspacePreferencesValue(PHPCoreConstants.TASK_TAGS); TaskTag[] workspaceTags = getTagsAndPropertiesFrom(tags, priorities); return workspaceTags; } /** * Returns true if the defined workspace task tags are case sensitive. * * @return true if the defined workspace task tags are case sensitive; false * otherwise. */ public boolean isWorkspaceTagsCaseSensitive() { String caseSensitive = preferencesSupport.getWorkspacePreferencesValue(PHPCoreConstants.TASK_CASE_SENSITIVE); return PHPCoreConstants.ENABLED.equals(caseSensitive); } /** * Returns the IProject's task tags. In case the given project does not have * a specific task tags, null is returned (since the project uses the * workspace definitions). * * @param project * An IProject reference. * @return The specific task tags for the given project, or null if the * project uses the workspace defined tags. */ public @Nullable TaskTag[] getProjectTaskTags(IProject project) { if (project == null) { return null; } String priorities = preferencesSupport.getProjectSpecificPreferencesValue(PHPCoreConstants.TASK_PRIORITIES, null, project); String projectTags = preferencesSupport.getProjectSpecificPreferencesValue(PHPCoreConstants.TASK_TAGS, null, project); if (projectTags == null || priorities == null) { return null; } TaskTag[] tags = getTagsAndPropertiesFrom(projectTags, priorities); return tags; } /** * Returns true if the defined project's task tags are case sensitive. In * case that the project does not have a specific settings, the return value * is by isWorkspaceTagsCaseSensitive. * * @param project * An IProject reference. * @return true if the defined project's task tags are case sensitive; false * otherwise. */ public boolean getProjectTagsCaseSensitive(IProject project) { if (project == null) { return isWorkspaceTagsCaseSensitive(); } String caseSensitive = preferencesSupport .getProjectSpecificPreferencesValue(PHPCoreConstants.TASK_CASE_SENSITIVE, null, project); if (caseSensitive == null) { return isWorkspaceTagsCaseSensitive(); } return PHPCoreConstants.ENABLED.equals(caseSensitive); } /** * Sets a TaskTagsListener to a related project. * * @param listener * A TaskTagsListener. * @param project * A related project. */ public void addTaskTagsListener(ITaskTagsListener listener, IProject project) { if (listener == null || project == null) { return; } projectToTaskTagListener.put(project, listener); installPropagatorListeners(project); } /** * Removes the TaskTagsListener attached to a related project. Don't use * this method directly but use * {@link TaskPatternsProvider#unregisterProject(IProject)} to clean up * everything correctly. * * @param project * A related project. */ public void removeTaskTagsListener(IProject project) { if (project == null) { return; } projectToTaskTagListener.remove(project); uninstallPropagatorListeners(project); } // Install propagator listeners for the given project. private void installPropagatorListeners(IProject project) { IPreferencesPropagatorListener[] listeners = new IPreferencesPropagatorListener[] { new InnerTaskTagsListener(project), new InnerTaskPrioritiesListener(project), new InnerTaskCaseListener(project) }; preferencesPropagator.addPropagatorListener(listeners[0], PHPCoreConstants.TASK_TAGS); preferencesPropagator.addPropagatorListener(listeners[1], PHPCoreConstants.TASK_PRIORITIES); preferencesPropagator.addPropagatorListener(listeners[2], PHPCoreConstants.TASK_CASE_SENSITIVE); projectToPropagatorListeners.put(project, listeners); } // Uninstall propagator listeners for the given project. private void uninstallPropagatorListeners(IProject project) { IPreferencesPropagatorListener[] listeners = (IPreferencesPropagatorListener[]) projectToPropagatorListeners .get(project); if (listeners != null) { preferencesPropagator.removePropagatorListener(listeners[0], PHPCoreConstants.TASK_TAGS); preferencesPropagator.removePropagatorListener(listeners[1], PHPCoreConstants.TASK_PRIORITIES); preferencesPropagator.removePropagatorListener(listeners[2], PHPCoreConstants.TASK_CASE_SENSITIVE); } projectToPropagatorListeners.remove(project); } /** * Install this task-tags provider. */ protected synchronized void install() { if (isInstalled) { return; } preferencesSupport = new PreferencesSupport(PHPCorePlugin.ID); projectToTaskTagListener = new HashMap<IProject, ITaskTagsListener>(); projectToPropagatorListeners = new HashMap<IProject, IPreferencesPropagatorListener[]>(); preferencesPropagator = PreferencePropagatorFactory.getPreferencePropagator(NODES_QUALIFIER); isInstalled = true; } /** * Uninstall this task-tags provider. */ protected synchronized void uninstall() { if (!isInstalled) { return; } // Uninstall the propagator listeners Set<IProject> keys = projectToPropagatorListeners.keySet(); IProject[] projects = new IProject[keys.size()]; keys.toArray(projects); for (IProject element : projects) { uninstallPropagatorListeners(element); } preferencesSupport = null; preferencesPropagator = null; projectToTaskTagListener = null; projectToPropagatorListeners = null; isInstalled = false; } // Notify a taskTagsChanged to all the listeners. private void notifyTaskTagChange(TaskTagsEvent event) { ITaskTagsListener[] allListeners = new ITaskTagsListener[projectToTaskTagListener.size()]; projectToTaskTagListener.values().toArray(allListeners); for (ITaskTagsListener element : allListeners) { element.taskTagsChanged(event); } } // Notify a taskTagsChanged to all the listeners. private void notifyTaskPriorityChange(TaskTagsEvent event) { ITaskTagsListener[] allListeners = new ITaskTagsListener[projectToTaskTagListener.size()]; projectToTaskTagListener.values().toArray(allListeners); for (ITaskTagsListener element : allListeners) { element.taskPrioritiesChanged(event); } } // Notify a taskTagsChanged to all the listeners. private void notifyTaskCaseChange(TaskTagsEvent event) { ITaskTagsListener[] allListeners = new ITaskTagsListener[projectToTaskTagListener.size()]; projectToTaskTagListener.values().toArray(allListeners); for (ITaskTagsListener element : allListeners) { element.taskCaseChanged(event); } } /* * Returns the tags into the workspace tags list. * * @param tags * * @param priorities */ private static TaskTag[] getTagsAndPropertiesFrom(String tagString, String priorityString) { String[] tags = StringUtils.unpack(tagString); String[] priorities = StringUtils.unpack(priorityString); List<Integer> list = new ArrayList<Integer>(); for (String element : priorities) { Integer number = null; if (PHPCoreConstants.TASK_PRIORITY_HIGH.equals(element)) { number = Integer.valueOf(IMarker.PRIORITY_HIGH); } else if (PHPCoreConstants.TASK_PRIORITY_LOW.equals(element)) { number = Integer.valueOf(IMarker.PRIORITY_LOW); } else { number = Integer.valueOf(IMarker.PRIORITY_NORMAL); } list.add(number); } Integer[] allPriorities = new Integer[list.size()]; list.toArray(allPriorities); TaskTag[] taskTags = new TaskTag[Math.min(tags.length, priorities.length)]; for (int i = 0; i < taskTags.length; i++) { taskTags[i] = new TaskTag(tags[i], allPriorities[i].intValue()); } return taskTags; } // //////////////////////////////////////////////////////////////////////////////////////////// // ///////////////////// IPreferencesPropagatorListeners // //////////////////////// // //////////////////////////////////////////////////////////////////////////////////////////// private abstract class AbstractTasksListener implements IPreferencesPropagatorListener { private IProject project; public AbstractTasksListener(@NonNull IProject project) { this.project = project; } public @NonNull IProject getProject() { return project; } } // Listen to task-tags strings changes private class InnerTaskTagsListener extends AbstractTasksListener { public InnerTaskTagsListener(@NonNull IProject project) { super(project); } public void preferencesEventOccured(PreferencesPropagatorEvent event) { String tags = preferencesSupport.getProjectSpecificPreferencesValue(PHPCoreConstants.TASK_TAGS, null, getProject()); String priorities = preferencesSupport.getProjectSpecificPreferencesValue(PHPCoreConstants.TASK_PRIORITIES, null, getProject()); String caseSensitive = preferencesSupport .getProjectSpecificPreferencesValue(PHPCoreConstants.TASK_CASE_SENSITIVE, null, getProject()); String newValue = (String) event.getNewValue(); // if project settings are not fully updated (i.e. user newly // enabled project task tags settings), use workspace settings if (tags == null || priorities == null || caseSensitive == null || newValue == null) { tags = preferencesSupport.getWorkspacePreferencesValue(PHPCoreConstants.TASK_TAGS); priorities = preferencesSupport.getWorkspacePreferencesValue(PHPCoreConstants.TASK_PRIORITIES); caseSensitive = preferencesSupport.getWorkspacePreferencesValue(PHPCoreConstants.TASK_CASE_SENSITIVE); newValue = tags; } if (StringUtils.occurrencesOf(newValue, ',') == StringUtils.occurrencesOf(priorities, ',')) { TaskTag[] taskTags = getTagsAndPropertiesFrom(newValue, priorities); TaskTagsEvent taskEvent = new TaskTagsEvent(TaskTagsProvider.this, getProject(), taskTags, PHPCoreConstants.ENABLED.equals(caseSensitive)); notifyTaskTagChange(taskEvent); } } } // Listen to task-tags priorities changes private class InnerTaskPrioritiesListener extends AbstractTasksListener { public InnerTaskPrioritiesListener(@NonNull IProject project) { super(project); } public void preferencesEventOccured(PreferencesPropagatorEvent event) { String tags = preferencesSupport.getProjectSpecificPreferencesValue(PHPCoreConstants.TASK_TAGS, null, getProject()); String priorities = preferencesSupport.getProjectSpecificPreferencesValue(PHPCoreConstants.TASK_PRIORITIES, null, getProject()); String caseSensitive = preferencesSupport .getProjectSpecificPreferencesValue(PHPCoreConstants.TASK_CASE_SENSITIVE, null, getProject()); String newValue = (String) event.getNewValue(); // if project settings are not fully updated (i.e. user newly // enabled project task tags settings), use workspace settings if (tags == null || priorities == null || caseSensitive == null || newValue == null) { tags = preferencesSupport.getWorkspacePreferencesValue(PHPCoreConstants.TASK_TAGS); priorities = preferencesSupport.getWorkspacePreferencesValue(PHPCoreConstants.TASK_PRIORITIES); caseSensitive = preferencesSupport.getWorkspacePreferencesValue(PHPCoreConstants.TASK_CASE_SENSITIVE); newValue = priorities; } if (StringUtils.occurrencesOf(tags, ',') == StringUtils.occurrencesOf(newValue, ',')) { TaskTag[] taskTags = getTagsAndPropertiesFrom(tags, newValue); TaskTagsEvent taskEvent = new TaskTagsEvent(TaskTagsProvider.this, getProject(), taskTags, PHPCoreConstants.ENABLED.equals(caseSensitive)); notifyTaskPriorityChange(taskEvent); } } } // Listen to task-tags case sensitivity changes private class InnerTaskCaseListener extends AbstractTasksListener { public InnerTaskCaseListener(@NonNull IProject project) { super(project); } public void preferencesEventOccured(PreferencesPropagatorEvent event) { String tags = preferencesSupport.getProjectSpecificPreferencesValue(PHPCoreConstants.TASK_TAGS, null, getProject()); String priorities = preferencesSupport.getProjectSpecificPreferencesValue(PHPCoreConstants.TASK_PRIORITIES, null, getProject()); String caseSensitive = preferencesSupport .getProjectSpecificPreferencesValue(PHPCoreConstants.TASK_CASE_SENSITIVE, null, getProject()); String newValue = (String) event.getNewValue(); // if project settings are not fully updated (i.e. user newly // enabled project task tags settings), use workspace settings if (tags == null || priorities == null || caseSensitive == null || newValue == null) { tags = preferencesSupport.getWorkspacePreferencesValue(PHPCoreConstants.TASK_TAGS); priorities = preferencesSupport.getWorkspacePreferencesValue(PHPCoreConstants.TASK_PRIORITIES); caseSensitive = preferencesSupport.getWorkspacePreferencesValue(PHPCoreConstants.TASK_CASE_SENSITIVE); newValue = caseSensitive; } if (StringUtils.occurrencesOf(tags, ',') == StringUtils.occurrencesOf(priorities, ',')) { TaskTag[] taskTags = getTagsAndPropertiesFrom(tags, priorities); TaskTagsEvent taskEvent = new TaskTagsEvent(TaskTagsProvider.this, getProject(), taskTags, PHPCoreConstants.ENABLED.equals(newValue)); notifyTaskCaseChange(taskEvent); } } } }