KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > resources > ProjectContentTypes


1 /*******************************************************************************
2  * Copyright (c) 2005 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.core.internal.resources;
12
13 import java.util.*;
14 import org.eclipse.core.internal.utils.Cache;
15 import org.eclipse.core.resources.IProject;
16 import org.eclipse.core.resources.ProjectScope;
17 import org.eclipse.core.runtime.*;
18 import org.eclipse.core.runtime.content.*;
19 import org.eclipse.core.runtime.content.IContentTypeManager.ISelectionPolicy;
20 import org.eclipse.core.runtime.preferences.*;
21 import org.osgi.service.prefs.BackingStoreException;
22 import org.osgi.service.prefs.Preferences;
23
24 /**
25  * Manages project-specific content type behavior.
26  *
27  * @see ContentDescriptionManager
28  * @see IContentTypeManager.ISelectionPolicy
29  * @since 3.1
30  */

31 public class ProjectContentTypes {
32
33     /**
34      * A project-aware content type selection policy.
35      * This class is also a dynamic scope context that will delegate to either
36      * project or instance scope depending on whether project specific settings were enabled
37      * for the project in question.
38      */

39     private class ProjectContentTypeSelectionPolicy implements ISelectionPolicy, IScopeContext {
40         // corresponding project
41
private Project project;
42         // cached project scope
43
private IScopeContext projectScope;
44
45         public ProjectContentTypeSelectionPolicy(Project project) {
46             this.project = project;
47             this.projectScope = new ProjectScope(project);
48         }
49
50         /* (non-Javadoc)
51          * @see java.lang.Object#equals(java.lang.Object)
52          */

53         public boolean equals(Object JavaDoc obj) {
54             if (this == obj)
55                 return true;
56             if (!(obj instanceof IScopeContext))
57                 return false;
58             IScopeContext other = (IScopeContext) obj;
59             if (!getName().equals(other.getName()))
60                 return false;
61             IPath location = getLocation();
62             return location == null ? other.getLocation() == null : location.equals(other.getLocation());
63         }
64
65         private IScopeContext getDelegate() {
66             if (!usesContentTypePreferences(project.getName()))
67                 return ProjectContentTypes.INSTANCE_SCOPE;
68             return projectScope;
69         }
70
71         public IPath getLocation() {
72             return getDelegate().getLocation();
73         }
74
75         public String JavaDoc getName() {
76             return getDelegate().getName();
77         }
78
79         public IEclipsePreferences getNode(String JavaDoc qualifier) {
80             return getDelegate().getNode(qualifier);
81         }
82
83         /* (non-Javadoc)
84          * @see java.lang.Object#hashCode()
85          */

86         public int hashCode() {
87             return getName().hashCode();
88         }
89
90         public IContentType[] select(IContentType[] candidates, boolean fileName, boolean content) {
91             return ProjectContentTypes.this.select(project, candidates, fileName, content);
92         }
93     }
94
95     private static final String JavaDoc CONTENT_TYPE_PREF_NODE = "content-types"; //$NON-NLS-1$
96

97     static final InstanceScope INSTANCE_SCOPE = new InstanceScope();
98
99     private static final String JavaDoc PREF_LOCAL_CONTENT_TYPE_SETTINGS = "enabled"; //$NON-NLS-1$
100
private static final Preferences PROJECT_SCOPE = Platform.getPreferencesService().getRootNode().node(ProjectScope.SCOPE);
101     private Cache contentTypesPerProject;
102     private Workspace workspace;
103
104     static boolean usesContentTypePreferences(String JavaDoc projectName) {
105         try {
106             // be careful looking up for our node so not to create any nodes as side effect
107
Preferences node = PROJECT_SCOPE;
108             //TODO once bug 90500 is fixed, should be simpler
109
// for now, take the long way
110
if (!node.nodeExists(projectName))
111                 return false;
112             node = node.node(projectName);
113             if (!node.nodeExists(Platform.PI_RUNTIME))
114                 return false;
115             node = node.node(Platform.PI_RUNTIME);
116             if (!node.nodeExists(CONTENT_TYPE_PREF_NODE))
117                 return false;
118             node = node.node(CONTENT_TYPE_PREF_NODE);
119             return node.getBoolean(PREF_LOCAL_CONTENT_TYPE_SETTINGS, false);
120         } catch (BackingStoreException e) {
121             // exception treated when retrieving the project preferences
122
}
123         return false;
124     }
125
126     public ProjectContentTypes(Workspace workspace) {
127         this.workspace = workspace;
128         // keep cache small
129
this.contentTypesPerProject = new Cache(5, 30, 0.4);
130     }
131
132     /**
133      * Collect content types associated to the natures configured for the given project.
134      */

135     private Set collectAssociatedContentTypes(Project project) {
136         String JavaDoc[] enabledNatures = workspace.getNatureManager().getEnabledNatures(project);
137         if (enabledNatures.length == 0)
138             return Collections.EMPTY_SET;
139         Set related = new HashSet(enabledNatures.length);
140         for (int i = 0; i < enabledNatures.length; i++) {
141             ProjectNatureDescriptor descriptor = (ProjectNatureDescriptor) workspace.getNatureDescriptor(enabledNatures[i]);
142             if (descriptor == null)
143                 // no descriptor found for the nature, skip it
144
continue;
145             String JavaDoc[] natureContentTypes = descriptor.getContentTypeIds();
146             for (int j = 0; j < natureContentTypes.length; j++)
147                 // collect associate content types
148
related.add(natureContentTypes[j]);
149         }
150         return related;
151     }
152
153     public void contentTypePreferencesChanged(IProject project) {
154         final ProjectInfo info = (ProjectInfo) ((Project) project).getResourceInfo(false, false);
155         if (info != null)
156             info.setMatcher(null);
157     }
158
159     /**
160      * Creates a content type matcher for the given project. Takes natures and user settings into account.
161      */

162     private IContentTypeMatcher createMatcher(Project project) {
163         ProjectContentTypeSelectionPolicy projectContentTypeSelectionPolicy = new ProjectContentTypeSelectionPolicy(project);
164         return Platform.getContentTypeManager().getMatcher(projectContentTypeSelectionPolicy, projectContentTypeSelectionPolicy);
165     }
166
167     private Set getAssociatedContentTypes(Project project) {
168         final ResourceInfo info = project.getResourceInfo(false, false);
169         if (info == null)
170             // the project has been deleted
171
return null;
172         final String JavaDoc projectName = project.getName();
173         synchronized (contentTypesPerProject) {
174             Cache.Entry entry = contentTypesPerProject.getEntry(projectName);
175             if (entry != null)
176                 // we have an entry...
177
if (entry.getTimestamp() == info.getContentId())
178                     // ...and it is not stale, so just return it
179
return (Set) entry.getCached();
180             // no cached information found, have to collect associated content types
181
Set result = collectAssociatedContentTypes(project);
182             if (entry == null)
183                 // there was no entry before - create one
184
entry = contentTypesPerProject.addEntry(projectName, result, info.getContentId());
185             else {
186                 // just update the existing entry
187
entry.setTimestamp(info.getContentId());
188                 entry.setCached(result);
189             }
190             return result;
191         }
192     }
193
194     public IContentTypeMatcher getMatcherFor(Project project) throws CoreException {
195         ProjectInfo info = (ProjectInfo) project.getResourceInfo(false, false);
196         //fail if project has been deleted concurrently
197
if (info == null)
198             project.checkAccessible(project.getFlags(info));
199         IContentTypeMatcher matcher = info.getMatcher();
200         if (matcher != null)
201             return matcher;
202         matcher = createMatcher(project);
203         info.setMatcher(matcher);
204         return matcher;
205     }
206
207     /**
208      * Implements project specific, nature-based selection policy. No content types are vetoed.
209      *
210      * The criteria for this policy is as follows:
211      * <ol>
212      * <li>associated content types should appear before non-associated content types</li>
213      * <li>otherwise, relative ordering should be preserved.</li>
214      * </ol>
215      *
216      * @see IContentTypeManager.ISelectionPolicy
217      */

218     final IContentType[] select(Project project, IContentType[] candidates, boolean fileName, boolean content) {
219         // since no vetoing is done here, don't go further if there is nothing to sort
220
if (candidates.length < 2)
221             return candidates;
222         final Set associated = getAssociatedContentTypes(project);
223         if (associated == null || associated.isEmpty())
224             // project has no content types associated
225
return candidates;
226         int associatedCount = 0;
227         for (int i = 0; i < candidates.length; i++)
228             // is it an associated content type?
229
if (associated.contains(candidates[i].getId())) {
230                 // need to move it to the right spot (unless all types visited so far are associated as well)
231
if (associatedCount < i) {
232                     final IContentType promoted = candidates[i];
233                     // move all non-associated content types before it one one position up...
234
for (int j = i; j > associatedCount; j--)
235                         candidates[j] = candidates[j - 1];
236                     // ...so there is an empty spot for the content type we are promoting
237
candidates[associatedCount] = promoted;
238                 }
239                 associatedCount++;
240             }
241         return candidates;
242     }
243 }
Popular Tags