Bug 500892 - API to create/remove content-types in user-space
Change-Id: I925cdee45d97d7d657e0d25c80eb69c43e9c9d71
Signed-off-by: Mickael Istria <mistria@redhat.com>
diff --git a/bundles/org.eclipse.core.contenttype/META-INF/MANIFEST.MF b/bundles/org.eclipse.core.contenttype/META-INF/MANIFEST.MF
index 74b6163..65c5da8 100644
--- a/bundles/org.eclipse.core.contenttype/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.core.contenttype/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.core.contenttype; singleton:=true
-Bundle-Version: 3.5.100.qualifier
+Bundle-Version: 3.6.0.qualifier
Bundle-Vendor: %providerName
Bundle-Localization: plugin
Require-Bundle: org.eclipse.equinox.preferences;bundle-version="[3.2.0,4.0.0)",
diff --git a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentType.java b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentType.java
index 98057c3..23adf17 100644
--- a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentType.java
+++ b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentType.java
@@ -10,7 +10,6 @@
*******************************************************************************/
package org.eclipse.core.internal.content;
-import org.eclipse.core.runtime.QualifiedName;
import java.io.*;
import java.util.*;
import org.eclipse.core.internal.runtime.RuntimeLog;
@@ -52,6 +51,10 @@
public final static String PREF_DEFAULT_CHARSET = "charset"; //$NON-NLS-1$
public final static String PREF_FILE_EXTENSIONS = "file-extensions"; //$NON-NLS-1$
public final static String PREF_FILE_NAMES = "file-names"; //$NON-NLS-1$
+ /**
+ * @since 3.6
+ */
+ public static final String PREF_USER_DEFINED = "userDefined"; //$NON-NLS-1$
final static byte PRIORITY_HIGH = 1;
final static byte PRIORITY_LOW = -1;
final static byte PRIORITY_NORMAL = 0;
@@ -73,6 +76,7 @@
String id;
private ContentTypeManager manager;
private String name;
+ private boolean userDefined;
private byte priority;
private ContentType target;
private String userCharset;
@@ -609,4 +613,9 @@
this.baseType = baseType;
}
+ @Override
+ public boolean isUserDefined() {
+ return this.userDefined;
+ }
+
}
diff --git a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeBuilder.java b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeBuilder.java
index f4793fa..3b455c3 100644
--- a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeBuilder.java
+++ b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeBuilder.java
@@ -10,15 +10,12 @@
*******************************************************************************/
package org.eclipse.core.internal.content;
-import org.eclipse.core.runtime.QualifiedName;
-
import java.util.*;
import org.eclipse.core.internal.runtime.RuntimeLog;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.content.IContentDescription;
import org.eclipse.core.runtime.content.IContentType;
-import org.eclipse.core.runtime.preferences.IEclipsePreferences;
-import org.eclipse.core.runtime.preferences.IPreferenceNodeVisitor;
+import org.eclipse.core.runtime.preferences.*;
import org.eclipse.osgi.util.NLS;
import org.osgi.service.prefs.BackingStoreException;
@@ -85,7 +82,7 @@
/**
* Builds all content types found in the extension registry.
*/
- public void buildCatalog() {
+ public void buildCatalog(IScopeContext context) {
IConfigurationElement[] allContentTypeCEs = getConfigurationElements();
for (int i = 0; i < allContentTypeCEs.length; i++)
if (allContentTypeCEs[i].getName().equals("content-type")) //$NON-NLS-1$
diff --git a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeCatalog.java b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeCatalog.java
index 1153d7b..26aa2f4 100644
--- a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeCatalog.java
+++ b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeCatalog.java
@@ -10,10 +10,6 @@
*******************************************************************************/
package org.eclipse.core.internal.content;
-import java.util.Iterator;
-
-import java.util.Set;
-import org.eclipse.core.runtime.content.IContentType;
import java.io.*;
import java.util.*;
import org.eclipse.core.runtime.*;
@@ -607,4 +603,12 @@
}
return destination;
}
+
+ void removeContentType(IContentType contentType) throws CoreException {
+ if (contentType.getSettings(getManager().getContext()).isUserDefined()) {
+ throw new IllegalArgumentException("content type must be user-defined."); //$NON-NLS-1$
+ }
+ contentTypes.remove(contentType.getId());
+ }
+
}
diff --git a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeHandler.java b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeHandler.java
index dcf3926..aa9e5cf 100644
--- a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeHandler.java
+++ b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeHandler.java
@@ -202,4 +202,13 @@
return id;
}
+ @Override
+ public boolean isUserDefined() {
+ ContentType target = getTarget();
+ if (target != null) {
+ return target.isUserDefined();
+ }
+ return false;
+ }
+
}
diff --git a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeManager.java b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeManager.java
index 8f67515..fee8a47 100644
--- a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeManager.java
+++ b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeManager.java
@@ -13,9 +13,14 @@
import java.io.InputStream;
import java.io.Reader;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.content.*;
import org.eclipse.core.runtime.preferences.*;
+import org.eclipse.osgi.util.NLS;
+import org.osgi.service.prefs.BackingStoreException;
public class ContentTypeManager extends ContentTypeMatcher implements IContentTypeManager {
private static ContentTypeManager instance;
@@ -140,7 +145,7 @@
// build catalog by parsing the extension registry
ContentTypeBuilder builder = createBuilder(newCatalog);
try {
- builder.buildCatalog();
+ builder.buildCatalog(getContext());
// only remember catalog if building it was successful
catalog = newCatalog;
} catch (InvalidRegistryObjectException e) {
@@ -213,4 +218,60 @@
// this is the platform content type manager, no specificities
return description;
}
+
+ @Override
+ public void removeContentType(IContentType contentType) throws CoreException {
+ if (contentType.getSettings(getContext()).isUserDefined()) {
+ throw new IllegalArgumentException("content type must be user-defined."); //$NON-NLS-1$
+ }
+ if (!contentType.isUserDefined()) {
+ throw new IllegalArgumentException("Can only delete content-types defined by users."); //$NON-NLS-1$
+ }
+ getCatalog().removeContentType(contentType);
+ // remove preferences for this content type
+ String currentUserDefined = getContext().getNode(ContentType.PREF_USER_DEFINED)
+ .get(ContentType.PREF_USER_DEFINED, "");//$NON-NLS-1$
+ List<String> userDefinedIds = Arrays.asList(currentUserDefined.split(",")); //$NON-NLS-1$
+ userDefinedIds.remove(contentType.getId());
+ getContext().getNode(ContentType.PREF_USER_DEFINED).put(ContentType.PREF_USER_DEFINED,
+ userDefinedIds.stream().collect(Collectors.joining(","))); //$NON-NLS-1$
+ try {
+ getContext().getNode(ContentType.PREF_USER_DEFINED).flush();
+ } catch (BackingStoreException bse) {
+ String message = NLS.bind(ContentMessages.content_errorSavingSettings, contentType.getId());
+ IStatus status = new Status(IStatus.ERROR, ContentMessages.OWNER_NAME, 0, message, bse);
+ throw new CoreException(status);
+ }
+ }
+
+ @Override
+ public IContentType addContentType(String id, String name, IContentType baseType) throws CoreException {
+ if (id == null) {
+ throw new IllegalArgumentException("content-type 'id' mustn't be null");//$NON-NLS-1$
+ }
+ if (id.contains(",")) { //$NON-NLS-1$
+ throw new IllegalAccessError("Content-Type id mustn't contain ','"); //$NON-NLS-1$
+ }
+ if (getContentType(id) != null) {
+ throw new IllegalArgumentException("content-type '" + id + "' already exists.");//$NON-NLS-1$ //$NON-NLS-2$
+ }
+ ContentType contentType = ContentType.createContentType(getCatalog(), id, name, (byte) 0, new String[0],
+ new String[0], baseType.getId(), null, null, null);
+ getCatalog().addContentType(contentType);
+ // add preferences for this content type
+ String currentUserDefined = getContext().getNode(ContentType.PREF_USER_DEFINED)
+ .get(ContentType.PREF_USER_DEFINED, "");//$NON-NLS-1$
+ if (currentUserDefined.length() > 0) {
+ currentUserDefined += ",";//$NON-NLS-1$
+ }
+ getContext().getNode(ContentType.PREF_USER_DEFINED).put(ContentType.PREF_USER_DEFINED, currentUserDefined + id);
+ try {
+ getContext().getNode(ContentType.PREF_USER_DEFINED).flush();
+ } catch (BackingStoreException bse) {
+ String message = NLS.bind(ContentMessages.content_errorSavingSettings, id);
+ IStatus status = new Status(IStatus.ERROR, ContentMessages.OWNER_NAME, 0, message, bse);
+ throw new CoreException(status);
+ }
+ return contentType;
+ }
}
diff --git a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeSettings.java b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeSettings.java
index 71387ee..60512f4 100644
--- a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeSettings.java
+++ b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeSettings.java
@@ -10,6 +10,7 @@
*******************************************************************************/
package org.eclipse.core.internal.content;
+import java.util.Arrays;
import java.util.List;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.content.IContentDescription;
@@ -161,4 +162,12 @@
}
}
+ @Override
+ public boolean isUserDefined() {
+ return Arrays.asList(
+ context.getNode(ContentType.PREF_USER_DEFINED).get(ContentType.PREF_USER_DEFINED, "") //$NON-NLS-1$
+ .split(",")) //$NON-NLS-1$
+ .contains(contentType.getId());
+ }
+
}
diff --git a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/runtime/content/IContentTypeManager.java b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/runtime/content/IContentTypeManager.java
index 1c9fb05..6bf307e 100644
--- a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/runtime/content/IContentTypeManager.java
+++ b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/runtime/content/IContentTypeManager.java
@@ -11,6 +11,7 @@
package org.eclipse.core.runtime.content;
import java.util.EventObject;
+import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.preferences.IScopeContext;
/**
@@ -22,6 +23,7 @@
*
* @see org.eclipse.core.runtime.content.IContentTypeMatcher
* @since 3.0
+ * @noimplement This interface is not intended to be implemented by clients.
*/
public interface IContentTypeManager extends IContentTypeMatcher {
@@ -215,4 +217,32 @@
* @see IContentTypeManager.IContentTypeChangeListener
*/
public void removeContentTypeChangeListener(IContentTypeChangeListener listener);
+
+ /**
+ * Removes the content-type from internal registry.
+ *
+ * @param id
+ * the non-null content-type id
+ * @param name
+ * the non-null user readable name
+ * @param baseType
+ * parent base type. May be null.
+ * @return the newly created and registered content-type
+ * @throws IllegalArgumentException
+ * if one of the non-null arguments is null, or id is already
+ * used by another content-type
+ *
+ * TODO move to a IContentTypeManagerExtension interface
+ */
+ public IContentType addContentType(String id, String name, IContentType baseType) throws CoreException;
+
+ /**
+ * Remove a content-type from underlying registry.
+ *
+ * @param contentType
+ * the content-type to remove.
+ *
+ * TODO move to a IContentTypeManagerExtension interface
+ */
+ public void removeContentType(IContentType contentType) throws CoreException;
}
diff --git a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/runtime/content/IContentTypeSettings.java b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/runtime/content/IContentTypeSettings.java
index 17f9035..25ee261 100644
--- a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/runtime/content/IContentTypeSettings.java
+++ b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/runtime/content/IContentTypeSettings.java
@@ -22,6 +22,7 @@
* @see IContentType
* @see IContentType#getSettings(IScopeContext)
* @since 3.1
+ * @noimplement This interface is not intended to be implemented by clients.
*/
public interface IContentTypeSettings {
/**
@@ -115,4 +116,10 @@
* </ul>
*/
public void setDefaultCharset(String userCharset) throws CoreException;
+
+ /**
+ * @return whether the content-type was defined by user
+ * @since 3.6
+ */
+ public boolean isUserDefined();
}