/*******************************************************************************
* Copyright (c) 2008, 2011 Symbian Software Systems 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:
* Andrew Ferguson (Symbian) - Initial implementation
* IBM Corporation
* Johan Ekberg - Bug 285932
*******************************************************************************/
package org.eclipse.cdt.internal.ui.text.doctools;
import com.ibm.icu.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.preferences.DefaultScope;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.osgi.service.prefs.Preferences;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.ui.text.doctools.IDocCommentOwner;
import org.eclipse.cdt.ui.text.doctools.IDocCommentOwnershipListener;
import org.eclipse.cdt.ui.text.doctools.IDocCommentViewerConfiguration;
/**
* This class manages which IDocCommentOwner's are available in the run-time, and how they map to
* resources in projects.
* @since 5.0
*/
public class DocCommentOwnerManager {
/** Constants for attributes/elements from the DocCommentOwner extension point */
private static final String ELEMENT_OWNER = "owner"; //$NON-NLS-1$
private static final String ATTRKEY_OWNER_ID = "id"; //$NON-NLS-1$
private static final String ATTRKEY_OWNER_NAME = "name"; //$NON-NLS-1$
private static final String ATTRKEY_OWNER_SINGLELINE = "singleline"; //$NON-NLS-1$
private static final String ATTRKEY_OWNER_MULTILINE = "multiline"; //$NON-NLS-1$
private static final String QUALIFIER= CCorePlugin.PLUGIN_ID;
private static final String WORKSPACE_DOC_TOOL_NODE= "doctool"; //$NON-NLS-1$
private static final String PREFKEY_WORKSPACE_DEFAULT= "workspace.default"; //$NON-NLS-1$
private static DocCommentOwnerManager singleton;
public static DocCommentOwnerManager getInstance() {
return singleton == null ? singleton= new DocCommentOwnerManager() : singleton;
}
private Map<String, IDocCommentOwner> fOwners;
private IDocCommentOwner fWorkspaceOwner;
private Map<IProject, ProjectMap> prj2map= new HashMap<IProject, ProjectMap>();
private static List<IDocCommentOwnershipListener> fListeners;
private DocCommentOwnerManager() {
fOwners= getCommentOwnerExtensions();
fListeners= new ArrayList<IDocCommentOwnershipListener>();
Preferences defaultPrefs = DefaultScope.INSTANCE.getNode(QUALIFIER).node(WORKSPACE_DOC_TOOL_NODE);
Preferences prefs= InstanceScope.INSTANCE.getNode(QUALIFIER).node(WORKSPACE_DOC_TOOL_NODE);
String id= prefs.get(PREFKEY_WORKSPACE_DEFAULT, defaultPrefs.get(PREFKEY_WORKSPACE_DEFAULT,
NullDocCommentOwner.INSTANCE.getID()));
fWorkspaceOwner= getOwner(id);
if (fWorkspaceOwner == null) {
// this could occur if a plug-in is no longer available
fWorkspaceOwner= NullDocCommentOwner.INSTANCE;
}
}
/**
* @param project a non-null project
* @return whether the specified project defines any documentation owner association
*/
public boolean projectDefinesOwnership(IProject project) {
return !getProjectMap(project).isEmpty();
}
/**
* @param newOwner the non-null doc-comment owner
*/
public void setWorkspaceCommentOwner(IDocCommentOwner newOwner) {
if (newOwner == null)
throw new IllegalArgumentException();
if (!fWorkspaceOwner.getID().equals(newOwner.getID())) {
IDocCommentOwner oldOwner= fWorkspaceOwner;
fWorkspaceOwner= newOwner;
Preferences prefs= InstanceScope.INSTANCE.getNode(QUALIFIER).node(WORKSPACE_DOC_TOOL_NODE);
prefs.put(PREFKEY_WORKSPACE_DEFAULT, newOwner.getID());
fireWorkspaceOwnershipChanged(oldOwner, fWorkspaceOwner);
}
}
/**
* @return the doc comment owner associated with the workspace. If non
* is set, the {@link NullDocCommentOwner} is returned.
*/
public IDocCommentOwner getWorkspaceCommentOwner() {
return fWorkspaceOwner;
}
/**
*
* @param resource May be null.
* @return a non-null IDocCommentOwner. If the resource was null, the {@link NullDocCommentOwner} is returned.
*/
public IDocCommentOwner getCommentOwner(IResource resource) {
if (resource==null)
return NullDocCommentOwner.INSTANCE;
if (ResourcesPlugin.getWorkspace().getRoot().equals(resource))
return getWorkspaceCommentOwner();
ProjectMap pm= getProjectMap(resource);
String ownerID= pm.getOwnerID(resource);
IDocCommentOwner result= getOwner(ownerID);
return result == null ? fWorkspaceOwner : result;
}
/**
* @param id
* @return the {@link IDocCommentOwner} with the specified id, or null
*/
public IDocCommentOwner getOwner(String id) {
if (NullDocCommentOwner.INSTANCE.getID().equals(id)) {
return NullDocCommentOwner.INSTANCE;
}
return fOwners.get(id);
}
/**
* @param resource a non-null resource to map a comment owner to
* @param newOwner the new owner to assign, or null to inherit the parent's mapping
* @param removeSubMappings if the resource is an {@link IContainer}, then remove any mappings
* children have. <em>This is currently unimplemented.</em>
*/
/*
* Note - this implementation currently ignores removeSubMappings.
*/
public void setCommentOwner(IResource resource, IDocCommentOwner newOwner, boolean removeSubMappings) {
Assert.isNotNull(resource);
if (ResourcesPlugin.getWorkspace().getRoot().equals(resource)) {
setWorkspaceCommentOwner(newOwner);
return;
}
ProjectMap pm= getProjectMap(resource);
IDocCommentOwner oldOwner= getCommentOwner(resource);
pm.setCommentOwner(resource, newOwner);
IDocCommentOwner newLogicalOwner= getCommentOwner(resource);
if (!newLogicalOwner.getID().equals(oldOwner.getID())) {
fireOwnershipChanged(resource, removeSubMappings, oldOwner, newLogicalOwner);
}
}
/**
* @return any comment owners registered against the extension point. This does not include
* the null comment processor.
*/
public IDocCommentOwner[] getRegisteredOwners() {
return fOwners.values().toArray(new IDocCommentOwner[fOwners.values().size()]);
}
/**
* @param listener registers a listener for doc-comment ownership events
*/
public void addListener(IDocCommentOwnershipListener listener) {
if (!fListeners.contains(listener)) {
fListeners.add(listener);
}
}
/**
* @param listener removes a listener from those registered for doc-comment ownership events
*/
public void removeListener(IDocCommentOwnershipListener listener) {
fListeners.remove(listener);
}
/*
* Utilities
*/
/**
* @param resource a non-null resource
* @return the cached (or newly obtained) ProjectMap for the resources
* associated project.
*/
private ProjectMap getProjectMap(IResource resource) {
Assert.isNotNull(resource);
IProject project= resource.getProject();
if (!prj2map.containsKey(project)) {
prj2map.put(project, new ProjectMap(project));
}
return prj2map.get(project);
}
/**
* @return a map of ID to {@link IDocCommentOwner} for comment owners registered
* via the DocCommentOwner extension point
*/
private static Map<String, IDocCommentOwner> getCommentOwnerExtensions() {
Map<String, IDocCommentOwner> result= new HashMap<String, IDocCommentOwner>();
IExtensionRegistry registry = Platform.getExtensionRegistry();
IExtensionPoint indexProviders = registry.getExtensionPoint(CUIPlugin.ID_COMMENT_OWNER);
IExtension[] extensions = indexProviders.getExtensions();
for (IExtension extension : extensions) {
try {
IConfigurationElement[] ce = extension.getConfigurationElements();
for (IConfigurationElement element : ce) {
if (element.getName().equals(ELEMENT_OWNER)) {
IDocCommentViewerConfiguration multi = (IDocCommentViewerConfiguration) element.createExecutableExtension(ATTRKEY_OWNER_MULTILINE);
IDocCommentViewerConfiguration single = (IDocCommentViewerConfiguration) element.createExecutableExtension(ATTRKEY_OWNER_SINGLELINE);
String id= element.getAttribute(ATTRKEY_OWNER_ID);
String name= element.getAttribute(ATTRKEY_OWNER_NAME);
if (result.put(id, new DocCommentOwner(id, name, multi, single))!=null) {
String msg= MessageFormat.format(Messages.DocCommentOwnerManager_DuplicateMapping0, new Object[] {id});
CUIPlugin.log(new Status(IStatus.WARNING, CUIPlugin.PLUGIN_ID, msg));
}
}
}
} catch(CoreException ce) {
CUIPlugin.log(ce);
}
}
return result;
}
private void fireOwnershipChanged(IResource resource, boolean submappingsRemoved, IDocCommentOwner oldOwner, IDocCommentOwner newOwner) {
for (IDocCommentOwnershipListener docCommentOwnershipListener : fListeners) {
docCommentOwnershipListener.ownershipChanged(resource, submappingsRemoved, oldOwner, newOwner);
}
}
private void fireWorkspaceOwnershipChanged(IDocCommentOwner oldOwner, IDocCommentOwner newOwner) {
for (IDocCommentOwnershipListener element : fListeners) {
element.workspaceOwnershipChanged(oldOwner, newOwner);
}
}
}