Index: src/org/eclipse/core/internal/content/ContentType.java =================================================================== RCS file: /home/eclipse/org.eclipse.core.runtime/src/org/eclipse/core/internal/content/ContentType.java,v retrieving revision 1.61 diff -u -r1.61 ContentType.java --- src/org/eclipse/core/internal/content/ContentType.java 29 Apr 2005 00:22:23 -0000 1.61 +++ src/org/eclipse/core/internal/content/ContentType.java 9 May 2005 03:10:07 -0000 @@ -16,6 +16,7 @@ import org.eclipse.core.runtime.*; import org.eclipse.core.runtime.content.*; import org.eclipse.core.runtime.preferences.IScopeContext; +import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.osgi.util.NLS; import org.osgi.service.prefs.BackingStoreException; import org.osgi.service.prefs.Preferences; @@ -104,7 +105,7 @@ return new FileSpec(fileSpec, type); } - private static String getPreferenceKey(int flags) { + static String getPreferenceKey(int flags) { if ((flags & FILE_EXTENSION_SPEC) != 0) return PREF_FILE_EXTENSIONS; if ((flags & FILE_NAME_SPEC) != 0) @@ -341,9 +342,10 @@ return priority; } - public IContentTypeSettings getSettings(IScopeContext context) throws CoreException { - //TODO should honor context - return this; + public IContentTypeSettings getSettings(IScopeContext context) { + if (context == null || context.getName().equals(InstanceScope.SCOPE)) + return this; + return new ContentTypeSettings(id, context); } /* @@ -361,6 +363,17 @@ return builtInAssociations; } + boolean hasFileSpec(IScopeContext context, String text, int typeMask) { + if (context.equals(manager.getContext()) || (typeMask & IGNORE_USER_DEFINED) != 0) + return hasFileSpec(text, typeMask); + String[] fileSpecs = ContentTypeSettings.getFileSpecs(context, id, typeMask); + for (int i = 0; i < fileSpecs.length; i++) + if (text.equalsIgnoreCase(fileSpecs[i])) + return true; + // no user defined association... try built-in + return hasFileSpec(text, typeMask | IGNORE_PRE_DEFINED); + } + /** * @param text the file spec string * @param typeMask FILE_NAME_SPEC or FILE_EXTENSION_SPEC @@ -385,7 +398,6 @@ * Adds a user-defined or pre-defined file spec. */ boolean internalAddFileSpec(String fileSpec, int typeMask) { - // XXX shouldn't this be done *after* we check for aliasing? if (hasFileSpec(fileSpec, typeMask)) return false; if (fileSpecs == null) Index: src/org/eclipse/core/internal/content/ContentTypeCatalog.java =================================================================== RCS file: /home/eclipse/org.eclipse.core.runtime/src/org/eclipse/core/internal/content/ContentTypeCatalog.java,v retrieving revision 1.12 diff -u -r1.12 ContentTypeCatalog.java --- src/org/eclipse/core/internal/content/ContentTypeCatalog.java 29 Apr 2005 00:22:23 -0000 1.12 +++ src/org/eclipse/core/internal/content/ContentTypeCatalog.java 9 May 2005 03:10:07 -0000 @@ -15,6 +15,8 @@ import org.eclipse.core.internal.runtime.Policy; import org.eclipse.core.runtime.*; import org.eclipse.core.runtime.content.*; +import org.eclipse.core.runtime.content.IContentTypeManager.ISelectionPolicy; +import org.eclipse.core.runtime.preferences.IScopeContext; public final class ContentTypeCatalog { private static final IContentType[] NO_CONTENT_TYPES = new IContentType[0]; @@ -26,10 +28,10 @@ private Map fileNames = new HashMap(); - private ContentTypeManager manager; - private int generation; + private ContentTypeManager manager; + /** * A sorting policy where the more generic content type wins. Lexicographical comparison is done * as a last resort when all other criteria fail. @@ -195,38 +197,6 @@ return valid; } - /** - * Processes all content types in source, adding those matching the given file spec to the - * destination collection. - */ - private Set selectMatchingByName(Collection source, final Collection existing, final String fileSpecText, final int fileSpecType) { - if (source == null || source.isEmpty()) - return Collections.EMPTY_SET; - final Set destination = new HashSet(5); - // process all content types in the given collection - for (Iterator i = source.iterator(); i.hasNext();) { - final ContentType root = (ContentType) i.next(); - // From a given content type, check if it matches, and - // include any children that match as well. - internalAccept(new ContentTypeVisitor() { - public int visit(ContentType type) { - if (type != root && type.hasBuiltInAssociations()) - // this content type has built-in associations - visit it later as root - return RETURN; - if (type == root && !type.hasFileSpec(fileSpecText, fileSpecType)) - // it is the root and does not match the file name - do not add it nor look into its children - return RETURN; - // either the content type is the root and matches the file name or - // is a sub content type and does not have built-in files specs - if (!existing.contains(type)) - destination.add(type); - return CONTINUE; - } - }, root); - } - return destination; - } - void dissociate(ContentType contentType, String text, int type) { Map fileSpecMap = ((type & IContentType.FILE_NAME_SPEC) != 0) ? fileNames : fileExtensions; String mappingKey = FileSpec.getMappingKeyFor(text); @@ -279,18 +249,20 @@ return true; } - IContentType[] findContentTypesFor(InputStream contents, String fileName, IContentTypeManager.ISelectionPolicy policy) throws IOException { + IContentType[] findContentTypesFor(ContentTypeMatcher matcher, InputStream contents, String fileName) throws IOException { final ILazySource buffer = ContentTypeManager.readBuffer(contents); - IContentType[] selected = internalFindContentTypesFor(buffer, fileName); + IContentType[] selected = internalFindContentTypesFor(matcher, buffer, fileName); // give the policy a chance to change the results + ISelectionPolicy policy = matcher.getPolicy(); if (policy != null) selected = applyPolicy(policy, selected, fileName != null, true); return selected; } - IContentType[] findContentTypesFor(final String fileName, IContentTypeManager.ISelectionPolicy policy) { - IContentType[] selected = concat(internalFindContentTypesFor(fileName, policyConstantGeneralIsBetter)); + IContentType[] findContentTypesFor(ContentTypeMatcher matcher, final String fileName) { + IContentType[] selected = concat(internalFindContentTypesFor(matcher, fileName, policyConstantGeneralIsBetter)); // give the policy a chance to change the results + ISelectionPolicy policy = matcher.getPolicy(); if (policy != null) selected = applyPolicy(policy, selected, true, false); return selected; @@ -326,11 +298,12 @@ return (type != null && type.isValid() && !type.isAlias()) ? type : null; } - private IContentDescription getDescriptionFor(ILazySource contents, String fileName, QualifiedName[] options, IContentTypeManager.ISelectionPolicy policy) throws IOException { - IContentType[] selected = internalFindContentTypesFor(contents, fileName); + private IContentDescription getDescriptionFor(ContentTypeMatcher matcher, ILazySource contents, String fileName, QualifiedName[] options) throws IOException { + IContentType[] selected = internalFindContentTypesFor(matcher, contents, fileName); if (selected.length == 0) return null; // give the policy a chance to change the results + ISelectionPolicy policy = matcher.getPolicy(); if (policy != null) { selected = applyPolicy(policy, selected, fileName != null, true); if (selected.length == 0) @@ -339,22 +312,22 @@ return ((ContentType) selected[0]).internalGetDescriptionFor(contents, options); } - public IContentDescription getDescriptionFor(InputStream contents, String fileName, QualifiedName[] options, IContentTypeManager.ISelectionPolicy policy) throws IOException { - return getDescriptionFor(ContentTypeManager.readBuffer(contents), fileName, options, policy); - } - - public IContentDescription getDescriptionFor(Reader contents, String fileName, QualifiedName[] options, IContentTypeManager.ISelectionPolicy policy) throws IOException { - return getDescriptionFor(ContentTypeManager.readBuffer(contents), fileName, options, policy); + public IContentDescription getDescriptionFor(ContentTypeMatcher matcher, InputStream contents, String fileName, QualifiedName[] options) throws IOException { + return getDescriptionFor(matcher, ContentTypeManager.readBuffer(contents), fileName, options); } - public ContentTypeManager getManager() { - return manager; + public IContentDescription getDescriptionFor(ContentTypeMatcher matcher, Reader contents, String fileName, QualifiedName[] options) throws IOException { + return getDescriptionFor(matcher, ContentTypeManager.readBuffer(contents), fileName, options); } public int getGeneration() { return generation; } + public ContentTypeManager getManager() { + return manager; + } + public boolean internalAccept(ContentTypeVisitor visitor, ContentType root) { if (!root.isValid() || root.isAlias()) return true; @@ -396,7 +369,7 @@ return result; } - private IContentType[] internalFindContentTypesFor(ILazySource buffer, String fileName) throws IOException { + private IContentType[] internalFindContentTypesFor(ContentTypeMatcher matcher, ILazySource buffer, String fileName) throws IOException { final IContentType[][] subset; final Comparator validPolicy; Comparator indeterminatePolicy; @@ -406,7 +379,7 @@ indeterminatePolicy = policyConstantGeneralIsBetter; validPolicy = policyConstantSpecificIsBetter; } else { - subset = internalFindContentTypesFor(fileName, policyLexicographical); + subset = internalFindContentTypesFor(matcher, fileName, policyLexicographical); indeterminatePolicy = policyGeneralIsBetter; validPolicy = policySpecificIsBetter; } @@ -419,15 +392,30 @@ * @return all matching content types in the preferred order * @see IContentTypeManager#findContentTypesFor(String) */ - public IContentType[][] internalFindContentTypesFor(final String fileName, Comparator sortingPolicy) { + public IContentType[][] internalFindContentTypesFor(ContentTypeMatcher matcher, final String fileName, Comparator sortingPolicy) { + IScopeContext context = matcher.getContext(); IContentType[][] result = {NO_CONTENT_TYPES, NO_CONTENT_TYPES}; - final Set allByFileName = (Set) fileNames.get(FileSpec.getMappingKeyFor(fileName)); - Set selectedByName = selectMatchingByName(allByFileName, Collections.EMPTY_SET, fileName, IContentType.FILE_NAME_SPEC); + + final Set allByFileName; + + if (context.equals(manager.getContext())) + allByFileName = getDirectlyAssociated(fileName, IContentTypeSettings.FILE_NAME_SPEC); + else { + allByFileName = new HashSet(getDirectlyAssociated(fileName, IContentTypeSettings.FILE_NAME_SPEC | IContentType.IGNORE_USER_DEFINED)); + allByFileName.addAll(matcher.getDirectlyAssociated(this, fileName, IContentTypeSettings.FILE_NAME_SPEC)); + } + Set selectedByName = selectMatchingByName(context, allByFileName, Collections.EMPTY_SET, fileName, IContentType.FILE_NAME_SPEC); result[0] = (IContentType[]) selectedByName.toArray(new IContentType[selectedByName.size()]); final String fileExtension = ContentTypeManager.getFileExtension(fileName); if (fileExtension != null) { - final Set allByFileExtension = (Set) fileExtensions.get(FileSpec.getMappingKeyFor(fileExtension)); - Set selectedByExtension = selectMatchingByName(allByFileExtension, selectedByName, fileExtension, IContentType.FILE_EXTENSION_SPEC); + final Set allByFileExtension; + if (context.equals(manager.getContext())) + allByFileExtension = getDirectlyAssociated(fileExtension, IContentTypeSettings.FILE_EXTENSION_SPEC); + else { + allByFileExtension = new HashSet(getDirectlyAssociated(fileExtension, IContentTypeSettings.FILE_EXTENSION_SPEC | IContentType.IGNORE_USER_DEFINED)); + allByFileExtension.addAll(matcher.getDirectlyAssociated(this, fileExtension, IContentTypeSettings.FILE_EXTENSION_SPEC)); + } + Set selectedByExtension = selectMatchingByName(context, allByFileExtension, selectedByName, fileExtension, IContentType.FILE_EXTENSION_SPEC); if (!selectedByExtension.isEmpty()) result[1] = (IContentType[]) selectedByExtension.toArray(new IContentType[selectedByExtension.size()]); } @@ -438,6 +426,24 @@ return result; } + public Set getDirectlyAssociated(String text, int typeMask) { + Map associations = (typeMask & IContentTypeSettings.FILE_NAME_SPEC) != 0 ? fileNames : fileExtensions; + Set result = null; + if ((typeMask & (IContentType.IGNORE_PRE_DEFINED | IContentType.IGNORE_PRE_DEFINED)) == 0) + result = (Set) associations.get(FileSpec.getMappingKeyFor(text)); + else { + // only those specs satisfying the the type mask should be included + result = (Set) associations.get(FileSpec.getMappingKeyFor(text)); + if (result != null) + for (Iterator i = result.iterator(); i.hasNext();) { + ContentType contentType = (ContentType) i.next(); + if (!contentType.hasFileSpec(text, typeMask)) + i.remove(); + } + } + return result == null ? Collections.EMPTY_SET : result; + } + ContentType internalGetContentType(String contentTypeIdentifier) { return (ContentType) contentTypes.get(contentTypeIdentifier); } @@ -474,4 +480,36 @@ Policy.debug("Invalid: " + type); //$NON-NLS-1$ } } + + /** + * Processes all content types in source, adding those matching the given file spec to the + * destination collection. + */ + private Set selectMatchingByName(final IScopeContext context, Collection source, final Collection existing, final String fileSpecText, final int fileSpecType) { + if (source == null || source.isEmpty()) + return Collections.EMPTY_SET; + final Set destination = new HashSet(5); + // process all content types in the given collection + for (Iterator i = source.iterator(); i.hasNext();) { + final ContentType root = (ContentType) i.next(); + // From a given content type, check if it matches, and + // include any children that match as well. + internalAccept(new ContentTypeVisitor() { + public int visit(ContentType type) { + if (type != root && type.hasBuiltInAssociations()) + // this content type has built-in associations - visit it later as root + return RETURN; + if (type == root && !type.hasFileSpec(context, fileSpecText, fileSpecType)) + // it is the root and does not match the file name - do not add it nor look into its children + return RETURN; + // either the content type is the root and matches the file name or + // is a sub content type and does not have built-in files specs + if (!existing.contains(type)) + destination.add(type); + return CONTINUE; + } + }, root); + } + return destination; + } } Index: src/org/eclipse/core/internal/content/ContentTypeManager.java =================================================================== RCS file: /home/eclipse/org.eclipse.core.runtime/src/org/eclipse/core/internal/content/ContentTypeManager.java,v retrieving revision 1.50 diff -u -r1.50 ContentTypeManager.java --- src/org/eclipse/core/internal/content/ContentTypeManager.java 29 Apr 2005 00:22:23 -0000 1.50 +++ src/org/eclipse/core/internal/content/ContentTypeManager.java 9 May 2005 03:10:07 -0000 @@ -92,7 +92,7 @@ } public ContentTypeManager() { - super(null); + super(null, new InstanceScope()); } protected ContentTypeBuilder createBuilder(ContentTypeCatalog newCatalog) { @@ -135,12 +135,15 @@ } public IContentTypeMatcher getMatcher(final ISelectionPolicy customPolicy, final IScopeContext context) { - //TODO should honor context parameter - return new ContentTypeMatcher(customPolicy); + return new ContentTypeMatcher(customPolicy, context == null ? getContext() : context); } IEclipsePreferences getPreferences() { - return new InstanceScope().getNode(CONTENT_TYPE_PREF_NODE); + return getPreferences(getContext()); + } + + IEclipsePreferences getPreferences(IScopeContext context) { + return context.getNode(CONTENT_TYPE_PREF_NODE); } public void registryChanged(IRegistryChangeEvent event) { Index: src/org/eclipse/core/internal/content/ContentTypeMatcher.java =================================================================== RCS file: /home/eclipse/org.eclipse.core.runtime/src/org/eclipse/core/internal/content/ContentTypeMatcher.java,v retrieving revision 1.3 diff -u -r1.3 ContentTypeMatcher.java --- src/org/eclipse/core/internal/content/ContentTypeMatcher.java 29 Apr 2005 00:22:23 -0000 1.3 +++ src/org/eclipse/core/internal/content/ContentTypeMatcher.java 9 May 2005 03:10:07 -0000 @@ -11,18 +11,25 @@ package org.eclipse.core.internal.content; import java.io.*; +import java.util.*; +import org.eclipse.core.internal.runtime.Messages; import org.eclipse.core.runtime.QualifiedName; import org.eclipse.core.runtime.content.*; +import org.eclipse.core.runtime.preferences.*; +import org.osgi.service.prefs.BackingStoreException; /** * @since 3.1 */ -class ContentTypeMatcher implements IContentTypeMatcher { +public class ContentTypeMatcher implements IContentTypeMatcher { + private IScopeContext context; private IContentTypeManager.ISelectionPolicy policy; + private Map defaultDescriptions = new HashMap(); - public ContentTypeMatcher(IContentTypeManager.ISelectionPolicy policy) { + public ContentTypeMatcher(IContentTypeManager.ISelectionPolicy policy, IScopeContext context) { this.policy = policy; + this.context = InstanceScope.SCOPE.equals(context) ? null : context; } /** @@ -30,7 +37,7 @@ */ public IContentType findContentTypeFor(InputStream contents, String fileName) throws IOException { ContentTypeCatalog currentCatalog = getCatalog(); - IContentType[] all = currentCatalog.findContentTypesFor(contents, fileName, policy); + IContentType[] all = currentCatalog.findContentTypesFor(this, contents, fileName); return all.length > 0 ? new ContentTypeHandler((ContentType) all[0], currentCatalog.getGeneration()) : null; } @@ -40,7 +47,7 @@ public IContentType findContentTypeFor(String fileName) { // basic implementation just gets all content types ContentTypeCatalog currentCatalog = getCatalog(); - IContentType[] associated = currentCatalog.findContentTypesFor(fileName, policy); + IContentType[] associated = currentCatalog.findContentTypesFor(this, fileName); return associated.length == 0 ? null : new ContentTypeHandler((ContentType) associated[0], currentCatalog.getGeneration()); } @@ -49,7 +56,7 @@ */ public IContentType[] findContentTypesFor(InputStream contents, String fileName) throws IOException { ContentTypeCatalog currentCatalog = getCatalog(); - IContentType[] types = currentCatalog.findContentTypesFor(contents, fileName, policy); + IContentType[] types = currentCatalog.findContentTypesFor(this, contents, fileName); IContentType[] result = new IContentType[types.length]; int generation = currentCatalog.getGeneration(); for (int i = 0; i < result.length; i++) @@ -62,7 +69,7 @@ */ public IContentType[] findContentTypesFor(String fileName) { ContentTypeCatalog currentCatalog = getCatalog(); - IContentType[] types = currentCatalog.findContentTypesFor(fileName, policy); + IContentType[] types = currentCatalog.findContentTypesFor(this, fileName); IContentType[] result = new IContentType[types.length]; int generation = currentCatalog.getGeneration(); for (int i = 0; i < result.length; i++) @@ -78,14 +85,50 @@ * @see IContentTypeMatcher */ public IContentDescription getDescriptionFor(InputStream contents, String fileName, QualifiedName[] options) throws IOException { - return getCatalog().getDescriptionFor(contents, fileName, options, policy); + return getCatalog().getDescriptionFor(this, contents, fileName, options); } /** * @see IContentTypeMatcher */ public IContentDescription getDescriptionFor(Reader contents, String fileName, QualifiedName[] options) throws IOException { - return getCatalog().getDescriptionFor(contents, fileName, options, policy); + return getCatalog().getDescriptionFor(this, contents, fileName, options); } + public IScopeContext getContext() { + return context; + } + + public IContentTypeManager.ISelectionPolicy getPolicy() { + return policy; + } + + /** + * Enumerates all content types whose settings satisfy the given file spec type mask. + */ + public Collection getDirectlyAssociated(final ContentTypeCatalog catalog, final String fileSpec, final int typeMask) { + final IEclipsePreferences root = context.getNode(ContentTypeManager.CONTENT_TYPE_PREF_NODE); + final Set result = new HashSet(3); + try { + root.accept(new IPreferenceNodeVisitor() { + public boolean visit(IEclipsePreferences node) { + if (node == root) + return true; + String[] fileSpecs = ContentTypeSettings.getFileSpecs(node, typeMask); + for (int i = 0; i < fileSpecs.length; i++) + if (fileSpecs[i].equalsIgnoreCase(fileSpec)) { + ContentType associated = catalog.getContentType(node.name()); + if (associated != null) + result.add(associated); + break; + } + return false; + } + + }); + } catch (BackingStoreException bse) { + ContentType.log(Messages.content_errorLoadingSettings, bse); + } + return result == null ? Collections.EMPTY_SET : result; + } } Index: src/org/eclipse/core/internal/content/Util.java =================================================================== RCS file: /home/eclipse/org.eclipse.core.runtime/src/org/eclipse/core/internal/content/Util.java,v retrieving revision 1.4 diff -u -r1.4 Util.java --- src/org/eclipse/core/internal/content/Util.java 4 Mar 2005 22:16:14 -0000 1.4 +++ src/org/eclipse/core/internal/content/Util.java 9 May 2005 03:10:07 -0000 @@ -10,8 +10,7 @@ *******************************************************************************/ package org.eclipse.core.internal.content; -import java.util.ArrayList; -import java.util.StringTokenizer; +import java.util.*; public class Util { public static String[] parseItems(String string) { @@ -53,6 +52,46 @@ return (String[]) items.toArray(new String[items.size()]); } + public static List parseItemsIntoList(String string) { + return parseItemsIntoList(string, ","); //$NON-NLS-1$ + } + + public static List parseItemsIntoList(String string, String separator) { + List items = new ArrayList(5); + if (string == null) + return items; + StringTokenizer tokenizer = new StringTokenizer(string, separator, true); //$NON-NLS-1$ + if (!tokenizer.hasMoreTokens()) { + items.add(string.trim()); + return items; + } + String first = tokenizer.nextToken().trim(); + boolean wasSeparator = false; + if (first.equals(separator)) { + // leading separator + first = ""; //$NON-NLS-1$ + wasSeparator = true; + } + items.add(first); + if (!tokenizer.hasMoreTokens()) + return items; + String current; + do { + current = tokenizer.nextToken().trim(); + boolean isSeparator = current.equals(separator); + if (isSeparator) { + if (wasSeparator) + items.add(""); //$NON-NLS-1$ + } else + items.add(current); + wasSeparator = isSeparator; + } while (tokenizer.hasMoreTokens()); + if (wasSeparator) + // trailing separator + items.add(""); //$NON-NLS-1$ + return items; + } + public static String toListString(Object[] list) { return toListString(list, ","); //$NON-NLS-1$ } Index: src/org/eclipse/core/internal/content/ContentTypeSettings.java =================================================================== RCS file: src/org/eclipse/core/internal/content/ContentTypeSettings.java diff -N src/org/eclipse/core/internal/content/ContentTypeSettings.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/core/internal/content/ContentTypeSettings.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2005 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 + *******************************************************************************/ +package org.eclipse.core.internal.content; + +import java.util.List; +import org.eclipse.core.runtime.content.IContentTypeSettings; +import org.eclipse.core.runtime.preferences.IScopeContext; +import org.osgi.service.prefs.Preferences; + +public class ContentTypeSettings implements IContentTypeSettings { + + private IScopeContext context; + private String id; + + public ContentTypeSettings(String id, IScopeContext context) { + this.context = context; + this.id = id; + } + + /* + * @see IContentTypeSettings + */ + public void addFileSpec(String fileSpec, int type) { + addFileSpec(context, id, fileSpec, type); + } + + static void addFileSpec(IScopeContext context, String contentTypeId, String fileSpec, int type) { + Preferences contentTypeNode = ContentTypeManager.getInstance().getPreferences(context).node(contentTypeId); + String key = ContentType.getPreferenceKey(type); + List existingValues = Util.parseItemsIntoList(contentTypeNode.get(key, null)); + for (int i = 0; i < existingValues.size(); i++) + if (((String) existingValues.get(i)).equalsIgnoreCase(fileSpec)) + // don't do anything if already exists + return; + existingValues.add(fileSpec); + // set new preference value + String newValue = Util.toListString(existingValues.toArray()); + contentTypeNode.put(key, newValue); + } + + public String getDefaultCharset() { + Preferences contentTypeNode = ContentTypeManager.getInstance().getPreferences(context).node(id); + return contentTypeNode.get(ContentType.PREF_DEFAULT_CHARSET, null); + } + + static String[] getFileSpecs(IScopeContext context, String contentTypeId, int type) { + Preferences contentTypeNode = ContentTypeManager.getInstance().getPreferences(context).node(contentTypeId); + return getFileSpecs(contentTypeNode, type); + } + + static String[] getFileSpecs(Preferences contentTypeNode, int type) { + String key = ContentType.getPreferenceKey(type); + String existing = contentTypeNode.get(key, null); + return Util.parseItems(existing); + } + + public String[] getFileSpecs(int type) { + return getFileSpecs(context, id, type); + } + + public String getId() { + return id; + } + + public void removeFileSpec(String fileSpec, int type) { + removeFileSpec(context, id, fileSpec, type); + } + + static void removeFileSpec(IScopeContext context, String contentTypeId, String fileSpec, int type) { + Preferences contentTypeNode = ContentTypeManager.getInstance().getPreferences(context).node(contentTypeId); + String key = ContentType.getPreferenceKey(type); + String existing = contentTypeNode.get(key, null); + if (existing == null) + // content type has no settings - nothing to do + return; + List existingValues = Util.parseItemsIntoList(contentTypeNode.get(key, null)); + int index = -1; + for (int i = 0; index >= 0 && i < existingValues.size(); i++) + if (((String) existingValues.get(i)).equalsIgnoreCase(fileSpec)) + index = i; + if (index == -1) + // did not find the file spec to be removed - nothing to do + return; + existingValues.remove(index); + // set new preference value + String newValue = Util.toListString(existingValues.toArray()); + contentTypeNode.put(key, newValue); + } + + public void setDefaultCharset(String userCharset) { + Preferences contentTypeNode = ContentTypeManager.getInstance().getPreferences(context).node(id); + if (userCharset == null) + contentTypeNode.remove(ContentType.PREF_DEFAULT_CHARSET); + else + contentTypeNode.put(ContentType.PREF_DEFAULT_CHARSET, userCharset); + } + +}