diff options
author | Lakshminarayana Nekkanti | 2019-07-02 09:19:43 +0000 |
---|---|---|
committer | Mickael Istria | 2019-07-18 14:05:07 +0000 |
commit | 5dacb5c72fb91737feedb5f20ff741a078707c61 (patch) | |
tree | e7373d1ac7cc0c46e03ce39a36d8bb1cf29a69be | |
parent | 47770c4052845dd93da22a50c254eece94b04c45 (diff) | |
download | eclipse.platform.text-5dacb5c72fb91737feedb5f20ff741a078707c61.tar.gz eclipse.platform.text-5dacb5c72fb91737feedb5f20ff741a078707c61.tar.xz eclipse.platform.text-5dacb5c72fb91737feedb5f20ff741a078707c61.zip |
Bug 513034 - [generic editor] Provide a way for generic editor to use
different icon based on content-type
Change-Id: I669c1a8df2918cdecea5e12d71059e34cb2f1c3f
Signed-off-by: Lakshminarayana Nekkanti <narayana.nekkanti@gmail.com>
13 files changed, 397 insertions, 4 deletions
diff --git a/org.eclipse.ui.genericeditor.tests/build.properties b/org.eclipse.ui.genericeditor.tests/build.properties index ed380ef0273..552c2424f7c 100644 --- a/org.eclipse.ui.genericeditor.tests/build.properties +++ b/org.eclipse.ui.genericeditor.tests/build.properties @@ -17,7 +17,8 @@ bin.includes = plugin.properties,\ about.html,\ .,\ META-INF/,\ - plugin.xml + plugin.xml,\ + icons/ src.includes = about.html diff --git a/org.eclipse.ui.genericeditor.tests/icons/newfile_wiz.png b/org.eclipse.ui.genericeditor.tests/icons/newfile_wiz.png Binary files differnew file mode 100644 index 00000000000..cb428d360f0 --- /dev/null +++ b/org.eclipse.ui.genericeditor.tests/icons/newfile_wiz.png diff --git a/org.eclipse.ui.genericeditor.tests/icons/newfolder_wiz.png b/org.eclipse.ui.genericeditor.tests/icons/newfolder_wiz.png Binary files differnew file mode 100644 index 00000000000..6fddda8953f --- /dev/null +++ b/org.eclipse.ui.genericeditor.tests/icons/newfolder_wiz.png diff --git a/org.eclipse.ui.genericeditor.tests/plugin.xml b/org.eclipse.ui.genericeditor.tests/plugin.xml index e107937b3a6..5d45eb65a30 100644 --- a/org.eclipse.ui.genericeditor.tests/plugin.xml +++ b/org.eclipse.ui.genericeditor.tests/plugin.xml @@ -263,4 +263,16 @@ type="org.eclipse.ui.internal.genericeditor.ExtensionBasedTextEditor"> </propertyTester> </extension> + <extension + point="org.eclipse.ui.genericeditor.icons"> + <icon + contentTypeId="org.eclipse.ui.genericeditor.tests.content-type" + icon="icons/newfile_wiz.png"/> + <icon + contentTypeId="org.eclipse.ui.genericeditor.tests.specialized-content-type" + icon="icons/newfolder_wiz.png"/> + <icon + contentTypeId="org.eclipse.ui.genericeditor.tests.sub-specialized-content-type" + icon="platform:/plugin/org.eclipse.ui.ide/icons/full/etool16/newprj_wiz.png"/> + </extension> </plugin> diff --git a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/GenericEditorTestSuite.java b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/GenericEditorTestSuite.java index 02581867800..366a17bd2cc 100644 --- a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/GenericEditorTestSuite.java +++ b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/GenericEditorTestSuite.java @@ -28,7 +28,8 @@ import org.junit.runners.Suite.SuiteClasses; FoldingTest.class, AutoEditTest.class, ReconcilerTest.class, - HighlightTest.class + HighlightTest.class, + IconsTest.class }) public class GenericEditorTestSuite { // see @SuiteClasses diff --git a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/IconsTest.java b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/IconsTest.java new file mode 100644 index 00000000000..647ab781520 --- /dev/null +++ b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/IconsTest.java @@ -0,0 +1,105 @@ +/******************************************************************************** + * Copyright (c) 2019 Lakshminarayana Nekkanti(narayana.nekkanti@gmail.com) + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 3 + * + * Contributor + * Lakshminarayana Nekkanti - initial API and implementation + ********************************************************************************/ +package org.eclipse.ui.genericeditor.tests; + +import static org.junit.Assert.assertEquals; + +import java.io.ByteArrayInputStream; +import java.lang.reflect.Field; + +import org.junit.Test; + +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.content.IContentType; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ResourcesPlugin; + +import org.eclipse.jface.resource.ImageDescriptor; + +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.internal.genericeditor.ExtensionBasedTextEditor; +import org.eclipse.ui.internal.genericeditor.GenericEditorPlugin; +import org.eclipse.ui.part.FileEditorInput; +import org.eclipse.ui.tests.harness.util.UITestCase; + +public class IconsTest extends AbstratGenericEditorTest { + + private ExtensionBasedTextEditor genericEditor; + + private IFile testFile; + + private IProject testProject; + + @Test + public void testEditorIconParentSet() throws Exception { + testProject= ResourcesPlugin.getWorkspace().getRoot().getProject(getClass().getName() + System.currentTimeMillis()); + testProject.create(null); + testProject.open(null); + + testFile= testProject.getFile("foobar.txt"); + testFile.create(new ByteArrayInputStream("Testing file".getBytes()), true, null); + + genericEditor= (ExtensionBasedTextEditor) PlatformUI.getWorkbench().getActiveWorkbenchWindow() + .getActivePage().openEditor(new FileEditorInput(testFile), "org.eclipse.ui.genericeditor.GenericEditor"); + + Field field= genericEditor.getClass().getDeclaredField("contentTypeImageDescripter"); + field.setAccessible(true);// Workaround to access descriptor + + ImageDescriptor descriptor= GenericEditorPlugin.getDefault().getContentTypeImagesRegistry() + .getImageDescriptor(new IContentType[] { Platform.getContentTypeManager().getContentType("org.eclipse.ui.genericeditor.tests.content-type"), + }); + assertEquals(field.get(genericEditor), descriptor); + } + + @Test + public void testEditorIconChildSet() throws Exception { + testProject= ResourcesPlugin.getWorkspace().getRoot().getProject(getClass().getName() + System.currentTimeMillis()); + testProject.create(null); + testProject.open(null); + + testFile= testProject.getFile("foo.txt"); + testFile.create(new ByteArrayInputStream("Testing file".getBytes()), true, null); + + genericEditor= (ExtensionBasedTextEditor) PlatformUI.getWorkbench().getActiveWorkbenchWindow() + .getActivePage().openEditor(new FileEditorInput(testFile), "org.eclipse.ui.genericeditor.GenericEditor"); + + Field field= genericEditor.getClass().getDeclaredField("contentTypeImageDescripter"); + field.setAccessible(true);// Workaround to access descriptor + + ImageDescriptor descriptor= GenericEditorPlugin.getDefault().getContentTypeImagesRegistry() + .getImageDescriptor(new IContentType[] { Platform.getContentTypeManager().getContentType("org.eclipse.ui.genericeditor.tests.sub-specialized-content-type"), + }); + assertEquals(field.get(genericEditor), descriptor); + } + + @Override + public void tearDown() throws Exception { + if (genericEditor != null) { + genericEditor.close(false); + genericEditor= null; + UITestCase.processEvents(); + } + if (testFile != null) { + testFile.delete(true, new NullProgressMonitor()); + testFile= null; + } + if (testProject != null) { + testProject.delete(true, new NullProgressMonitor()); + testProject= null; + } + super.tearDown(); + } +} diff --git a/org.eclipse.ui.genericeditor/plugin.properties b/org.eclipse.ui.genericeditor/plugin.properties index f3a9ac9dfea..ca08078a7a7 100644 --- a/org.eclipse.ui.genericeditor/plugin.properties +++ b/org.eclipse.ui.genericeditor/plugin.properties @@ -24,6 +24,7 @@ ExtPoint.highlightReconcilers=Highlight Reconcilers ExtPoint.foldingReconcilers=Folding Reconcilers ExtPoint.characterPairMatchers=Character Pair Matcher Providers ExtPoint.hyperlinkDetectorTarget=Generic Text Editor +ExtPoint.iconProviders=Generic Editor Icon Providers openDeclarationCommand_name=Open Declaration context_name=in Generic Code Editor context_description=When editing in the Generic Code Editor diff --git a/org.eclipse.ui.genericeditor/plugin.xml b/org.eclipse.ui.genericeditor/plugin.xml index 416f17b867f..bb3ea5b8a90 100644 --- a/org.eclipse.ui.genericeditor/plugin.xml +++ b/org.eclipse.ui.genericeditor/plugin.xml @@ -23,7 +23,8 @@ <extension-point id="autoEditStrategies" name="%ExtPoint.autoEditStrategies" schema="schema/autoEditStrategies.exsd"/> <extension-point id="highlightReconcilers" name="%ExtPoint.highlightReconcilers" schema="schema/highlightReconcilers.exsd"/> <extension-point id="foldingReconcilers" name="%ExtPoint.foldingReconcilers" schema="schema/foldingReconcilers.exsd"/> - <extension-point id="characterPairMatchers" name="%ExtPoint.characterPairMatchers" schema="schema/characterPairMatchers.exsd"/> + <extension-point id="characterPairMatchers" name="%ExtPoint.characterPairMatchers" schema="schema/characterPairMatchers.exsd"/> + <extension-point id="icons" name="%ExtPoint.iconProviders" schema="schema/genericEditorIcons.exsd"/> <extension point="org.eclipse.ui.editors"> <editor diff --git a/org.eclipse.ui.genericeditor/schema/genericEditorIcons.exsd b/org.eclipse.ui.genericeditor/schema/genericEditorIcons.exsd new file mode 100644 index 00000000000..e0e4a4f3a65 --- /dev/null +++ b/org.eclipse.ui.genericeditor/schema/genericEditorIcons.exsd @@ -0,0 +1,130 @@ +<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.ui.genericeditor"
+ xmlns="http://www.w3.org/2001/XMLSchema">
+ <annotation>
+ <appinfo>
+ <meta.schema plugin="org.eclipse.ui.genericeditor" id="icons" name="GenericEditorIcons"/>
+ </appinfo>
+ <documentation>
+The icons extension point provides a way of linking different types of icons to a particular content type.
+ </documentation>
+ </annotation>
+ <element name="extension">
+ <annotation>
+ <appinfo>
+ <meta.element />
+ </appinfo>
+ </annotation>
+ <complexType>
+ <sequence>
+ <element ref="icon" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation></documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation></documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation></documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+ <element name="icon">
+ <annotation>
+ <appinfo>
+ <meta.element labelAttribute="contentTypeId"/>
+ </appinfo>
+ <documentation>
+ The icon to associate with a particular content type.
+ </documentation>
+ </annotation>
+ <complexType>
+ <attribute name="contentTypeId" type="string" use="required">
+ <annotation>
+ <documentation>
+ The identifier of the content type with which the icons should be associated.
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="identifier" basedOn="org.eclipse.core.contenttype.contentTypes/content-type/@id"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ <attribute name="icon" type="string" use="required">
+ <annotation>
+ <documentation>
+ The path to the icon which should be used.
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="resource"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+ <annotation>
+ <appinfo>
+ <meta.section type="since"/>
+ </appinfo>
+ <documentation>
+ 1.1.500
+ </documentation>
+ </annotation>
+ <annotation>
+ <appinfo>
+ <meta.section type="examples"/>
+ </appinfo>
+ <documentation>
+ <pre>
+ <extension
+ point="org.eclipse.ui.genericeditor.icons">
+ <icon
+ contentTypeId="org.eclipse.core.runtime.xml"
+ icon="icons/xml_content.png" />
+ </extension>
+</pre>
+<pre>
+ <extension
+ point="org.eclipse.ui.genericeditor.icons">
+ <icon
+ contentTypeId="org.eclipse.core.runtime.text"
+ icon="platform:/plugin/org.eclipse.ui.test/icons/text_content.png" />
+ </extension>
+</pre>
+ </documentation>
+ </annotation>
+ <annotation>
+ <appinfo>
+ <meta.section type="apiInfo"/>
+ </appinfo>
+ <documentation>
+ </documentation>
+ </annotation>
+ <annotation>
+ <appinfo>
+ <meta.section type="copyright"/>
+ </appinfo>
+ <documentation>
+ Copyright (c) 2019 Lakshminarayana Nekkanti(narayana.nekkanti@gmail.com)
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License 2.0 which is available at
+ http://www.eclipse.org/legal/epl-2.0.
+
+ SPDX-License-Identifier: EPL-2.0 3
+
+ Contributor
+ Lakshminarayana Nekkanti - initial API and implementation
+ </documentation>
+ </annotation>
+</schema>
diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ContentTypeImagesRegistry.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ContentTypeImagesRegistry.java new file mode 100644 index 00000000000..38e841a1bce --- /dev/null +++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ContentTypeImagesRegistry.java @@ -0,0 +1,95 @@ +/******************************************************************************** + * Copyright (c) 2019 Lakshminarayana Nekkanti(narayana.nekkanti@gmail.com) + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 3 + * + * Contributor + * Lakshminarayana Nekkanti - initial API and implementation + ********************************************************************************/ +package org.eclipse.ui.internal.genericeditor; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IRegistryChangeEvent; +import org.eclipse.core.runtime.IRegistryChangeListener; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.content.IContentType; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.ResourceLocator; + +public class ContentTypeImagesRegistry { + + private static final String EXTENSION_POINT_ID = GenericEditorPlugin.BUNDLE_ID + ".icons"; //$NON-NLS-1$ + private Map<IContentType, ImageDescriptor> extensions = new LinkedHashMap<>(); + private boolean outOfSync = true; + + public ContentTypeImagesRegistry() { + Platform.getExtensionRegistry().addRegistryChangeListener(new IRegistryChangeListener() { + @Override + public void registryChanged(IRegistryChangeEvent event) { + outOfSync = true; + } + }, EXTENSION_POINT_ID); + } + + public ImageDescriptor getImageDescriptor(IContentType[] contentTypes) { + if (this.outOfSync) { + sync(); + } + return Arrays.stream(contentTypes) + .sorted(Collections.reverseOrder(Comparator.comparingInt(ContentTypeSpecializationComparator::depth))) + .map(extensions::get).filter(Objects::nonNull).findFirst().orElse(null); + } + + private void sync() { + Set<IContentType> toRemoveContentTypes = new HashSet<IContentType>(this.extensions.keySet()); + for (IConfigurationElement extension : Platform.getExtensionRegistry() + .getConfigurationElementsFor(EXTENSION_POINT_ID)) { + try { + final String contentTypeId = extension.getAttribute("contentTypeId"); //$NON-NLS-1$ + if (contentTypeId == null || contentTypeId.isEmpty()) { + continue; + } + + final IContentType contentType = Platform.getContentTypeManager().getContentType(contentTypeId); + if (contentType == null) { + continue; + } + toRemoveContentTypes.remove(contentType); + if (!this.extensions.containsKey(contentType)) { + final String icon = extension.getAttribute("icon"); //$NON-NLS-1$ + if (icon == null || icon.isEmpty()) { + continue; + } + ImageDescriptor imageDescriptor = ResourceLocator + .imageDescriptorFromBundle(extension.getNamespaceIdentifier(), icon).orElse(null); + if (imageDescriptor != null) { + this.extensions.put(contentType, imageDescriptor); + } + } + } catch (Exception ex) { + GenericEditorPlugin.getDefault().getLog() + .log(new Status(IStatus.ERROR, GenericEditorPlugin.BUNDLE_ID, ex.getMessage(), ex)); + } + } + + for (IContentType toRemove : toRemoveContentTypes) { + this.extensions.remove(toRemove); + } + this.outOfSync = false; + } +} diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ContentTypeSpecializationComparator.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ContentTypeSpecializationComparator.java index 68c2e18f480..a381e9ff72c 100644 --- a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ContentTypeSpecializationComparator.java +++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ContentTypeSpecializationComparator.java @@ -29,7 +29,7 @@ public class ContentTypeSpecializationComparator<T> implements Comparator<Generi return depth(o2.targetContentType) - depth(o1.targetContentType); } - private static int depth(IContentType targetContentType) { + public static int depth(IContentType targetContentType) { int res = 0; IContentType current = targetContentType; while (current != null) { diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ExtensionBasedTextEditor.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ExtensionBasedTextEditor.java index f1f2c4bfbb1..d92078fd0fb 100644 --- a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ExtensionBasedTextEditor.java +++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ExtensionBasedTextEditor.java @@ -19,12 +19,15 @@ package org.eclipse.ui.internal.genericeditor; import java.util.List; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.content.IContentType; import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.text.source.ICharacterPairMatcher; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.source.IVerticalRuler; import org.eclipse.jface.text.source.projection.ProjectionSupport; import org.eclipse.jface.text.source.projection.ProjectionViewer; +import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.editors.text.EditorsUI; @@ -48,6 +51,8 @@ public class ExtensionBasedTextEditor extends TextEditor { private static final String ENCLOSING_BRACKETS = GenericEditorPreferenceConstants.EDITOR_ENCLOSING_BRACKETS; private ExtensionBasedTextViewerConfiguration configuration; + private Image contentTypeImage; + private ImageDescriptor contentTypeImageDescripter; /** * @@ -85,6 +90,7 @@ public class ExtensionBasedTextEditor extends TextEditor { new ProjectionSupport(viewer, getAnnotationAccess(), getSharedColors()).install(); viewer.doOperation(ProjectionViewer.TOGGLE); + computeImage(); } @Override protected void initializeEditor() { @@ -109,4 +115,34 @@ public class ExtensionBasedTextEditor extends TextEditor { support.setMatchingCharacterPainterPreferenceKeys(MATCHING_BRACKETS, MATCHING_BRACKETS_COLOR, HIGHLIGHT_BRACKET_AT_CARET_LOCATION, ENCLOSING_BRACKETS); } } + + @Override + public Image getTitleImage() { + return this.contentTypeImage != null ? this.contentTypeImage : super.getTitleImage(); + } + + private void computeImage() { + contentTypeImageDescripter = GenericEditorPlugin.getDefault().getContentTypeImagesRegistry() + .getImageDescriptor(getContentTypes()); + if (contentTypeImageDescripter != null) { + this.contentTypeImage = contentTypeImageDescripter.createImage(); + } + } + + private IContentType[] getContentTypes() { + ISourceViewer sourceViewer = getSourceViewer(); + if (sourceViewer != null) { + return configuration.getContentTypes(sourceViewer).toArray(new IContentType[] {}); + } + return new IContentType[] {}; + } + + @Override + public void dispose() { + if (this.contentTypeImage != null) { + this.contentTypeImage.dispose(); + this.contentTypeImage = null; + } + super.dispose(); + } } diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/GenericEditorPlugin.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/GenericEditorPlugin.java index 12fe25a7ff3..6a9bc7f9738 100644 --- a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/GenericEditorPlugin.java +++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/GenericEditorPlugin.java @@ -47,6 +47,7 @@ public class GenericEditorPlugin extends AbstractUIPlugin { private PresentationReconcilerRegistry presentationReconcilierRegistry; private AutoEditStrategyRegistry autoEditStrategyRegistry; private CharacterPairMatcherRegistry characterPairMatcherRegistry; + private ContentTypeImagesRegistry editorImagesRegistry; private IPropertyChangeListener themeListener; @@ -151,4 +152,14 @@ public class GenericEditorPlugin extends AbstractUIPlugin { } return this.characterPairMatcherRegistry; } + + /** + * @return the registry allowing to access contributed images + */ + public synchronized ContentTypeImagesRegistry getContentTypeImagesRegistry() { + if (this.editorImagesRegistry == null) { + this.editorImagesRegistry = new ContentTypeImagesRegistry(); + } + return this.editorImagesRegistry; + } } |