Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 8042b044c2e9e5f0f9bb68e41f2a4481dbbc377a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/*******************************************************************************
 * Copyright (c) 2008 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
 *******************************************************************************/
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.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.ICDescriptor;
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>();
		ICDescriptor pd= CCorePlugin.getDefault().getCProjectDescription(project, true);
		Element e= pd.getProjectData(ATTRVAL_STORAGEID);
		if(e.hasChildNodes()) {
			NodeList commentOwners= e.getElementsByTagName(ELEMENT_DOC_COMMENT_OWNER);
			for(int i=0; i<commentOwners.getLength(); i++) {
				Element node= (Element) commentOwners.item(i);
				Node commentOwnerIDNode= node.getAttributes().getNamedItem(ATTRKEY_DCO_ID);

				if(commentOwnerIDNode != null) {
					String commentOwnerID= commentOwnerIDNode.getNodeValue();

					NodeList paths= node.getElementsByTagName(ELEMENT_PATH);
					for(int j=0; j<paths.getLength(); j++) {
						Node path= paths.item(i);
						Node pathValue= path.getAttributes().getNamedItem(ATTRKEY_PATH_VALUE);
						if(pathValue != null) {
							result.put(Path.fromPortableString(pathValue.getNodeValue()), commentOwnerID);
						}
					}
				}
			}
		}
		return result;
	}

	/**
	 * Write the map to the .cproject file
	 */
	public void save() throws CoreException {
		ICDescriptor pd= CCorePlugin.getDefault().getCProjectDescription(fProject, true);

		// remove current associations
		Element data= pd.getProjectData(ATTRVAL_STORAGEID);
		NodeList nl= data.getChildNodes();
		for(int i=0; i<nl.getLength(); i++) {
			Node node= nl.item(i);
			if(node.getNodeType()== Node.ELEMENT_NODE) {
				data.removeChild(node);
			}
		}

		// invert and persist associations
		for(Iterator i= fMap.values().iterator(); i.hasNext();) {
			String cid= (String) i.next();
			Element commentNode= data.getOwnerDocument().createElement(ELEMENT_DOC_COMMENT_OWNER);
			commentNode.setAttribute(ATTRKEY_DCO_ID, cid);
			for(Iterator j= fMap.keySet().iterator(); j.hasNext(); ) {
				IPath path= (IPath) j.next();
				String ccid= fMap.get(path);
				if(cid.equals(ccid)) {
					Element pathNode= data.getOwnerDocument().createElement(ELEMENT_PATH);
					pathNode.setAttribute(ATTRKEY_PATH_VALUE, path.toPortableString());
					commentNode.appendChild(pathNode);
				}
			}
			data.appendChild(commentNode);
		}
		pd.saveProjectData();
	}
}

Back to the top