/*******************************************************************************
* 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
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.ui.text.doctools;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
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.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.cdt.core.settings.model.ICStorageElement;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.ui.text.doctools.IDocCommentOwner;
/**
* A ProjectMap is an internal abstraction which
* <ul>
* <li>Maintains mappings from project relative paths to comment-owner ID's
* <li>Manages persistence of these mappings to the .cproject file.
* </ul>
* for a particular {@link IProject}
*
* @since 5.0
*/
class ProjectMap {
/** .cproject xml element/attribute names **/
private static final String ATTRVAL_STORAGEID= "org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"; //$NON-NLS-1$
private static final String ELEMENT_DOC_COMMENT_OWNER = "doc-comment-owner"; //$NON-NLS-1$
private static final String ATTRKEY_DCO_ID = "id"; //$NON-NLS-1$
private static final String ELEMENT_PATH = "path"; //$NON-NLS-1$
private static final String ATTRKEY_PATH_VALUE = "value"; //$NON-NLS-1$
private IProject fProject;
private Map<IPath, String> fMap;
/**
* Loads the project map
* @param project
*/
public ProjectMap(IProject project) {
try {
fMap= load(project);
} catch(CoreException ce) {
CUIPlugin.log(ce);
fMap= new HashMap<IPath, String>();
}
fProject= project;
}
/**
* Returns the id of the doc comment owner mapped to the resource specified, or null
* if no owner is mapped within this project. Ownership is inherited from parents and
* may be overridden.
* @param resource
* @return possibly null
*/
public String getOwnerID(IResource resource) {
String id= null;
if (resource != null) {
for (IPath p= resource.getProjectRelativePath(); ; p= p.removeLastSegments(1)) {
if (fMap.containsKey(p)) {
id= fMap.get(p);
break;
}
if (p.isEmpty())
break;
}
}
return id;
}
/**
* Creates a new (or updates the existing) mapping associating the specified
* {@link IDocCommentOwner} with the specified {@link IResource}
* @param resource the non-null resource to create an association for
* @param owner the owner to associate the resource with, or <code>null</code> to ensure there
* is no association.
*/
public void setCommentOwner(IResource resource, IDocCommentOwner owner) {
Assert.isNotNull(resource);
if (ResourcesPlugin.getWorkspace().getRoot().equals(resource))
throw new IllegalStateException();
if (owner != null) {
fMap.put(resource.getProjectRelativePath(), owner.getID());
} else {
fMap.remove(resource.getProjectRelativePath());
}
try {
save();
} catch(CoreException ce) {
CUIPlugin.log(ce);
}
}
public boolean isEmpty() {
return fMap.isEmpty();
}
private static Map<IPath, String> load(IProject project) throws CoreException {
Map<IPath, String> result= new HashMap<IPath, String>();
ICProjectDescription pd= CCorePlugin.getDefault().getProjectDescription(project, false);
if (pd != null) {
ICStorageElement element = pd.getStorage(ATTRVAL_STORAGEID, false);
if (element != null) {
for (ICStorageElement node : element.getChildrenByName(ELEMENT_DOC_COMMENT_OWNER)) {
String commentOwnerID = node.getAttribute(ATTRKEY_DCO_ID);
if (commentOwnerID != null) {
for (ICStorageElement path : node.getChildrenByName(ELEMENT_PATH)) {
String pathValue= path.getAttribute(ATTRKEY_PATH_VALUE);
if(pathValue != null) {
result.put(Path.fromPortableString(pathValue), commentOwnerID);
}
}
}
}
}
}
return result;
}
/**
* Write the map to the .cproject file
*/
public void save() throws CoreException {
ICProjectDescription pd= CCorePlugin.getDefault().getProjectDescription(fProject, true);
// remove current associations
ICStorageElement data = pd.getStorage(ATTRVAL_STORAGEID, true);
for (ICStorageElement child : data.getChildren())
data.removeChild(child);
// invert and persist associations
for (Iterator<String> i= fMap.values().iterator(); i.hasNext();) {
String cid= i.next();
ICStorageElement commentNode = data.createChild(ELEMENT_DOC_COMMENT_OWNER);
commentNode.setAttribute(ATTRKEY_DCO_ID, cid);
for (Iterator<IPath> j= fMap.keySet().iterator(); j.hasNext(); ) {
IPath path= j.next();
String ccid= fMap.get(path);
if(cid.equals(ccid)) {
ICStorageElement pathNode = commentNode.createChild(ELEMENT_PATH);
pathNode.setAttribute(ATTRKEY_PATH_VALUE, path.toPortableString());
}
}
}
CCorePlugin.getDefault().setProjectDescription(fProject, pd);
}
}