1 /******************************************************************************* 2 * Copyright (c) 2017 Red Hat Inc. and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * - Mickael Istria (Red Hat Inc.) 13 *******************************************************************************/ 14 package org.eclipse.ui.internal.genericeditor; 15 16 import org.eclipse.core.expressions.ElementHandler; 17 import org.eclipse.core.expressions.EvaluationContext; 18 import org.eclipse.core.expressions.EvaluationResult; 19 import org.eclipse.core.expressions.Expression; 20 import org.eclipse.core.expressions.ExpressionConverter; 21 import org.eclipse.core.runtime.CoreException; 22 import org.eclipse.core.runtime.IConfigurationElement; 23 import org.eclipse.core.runtime.IStatus; 24 import org.eclipse.core.runtime.Platform; 25 import org.eclipse.core.runtime.Status; 26 import org.eclipse.core.runtime.content.IContentType; 27 import org.eclipse.jface.text.source.ISourceViewer; 28 import org.eclipse.ui.texteditor.ITextEditor; 29 30 /** 31 * This class wraps and proxies an instance of T provided through extensions and loads it lazily when it can contribute to the editor, then delegates all operations to actual instance. 32 * 33 * @param <T> 34 * the actual type to proxy, typically the one defined on the extension point. 35 */ 36 public class GenericContentTypeRelatedExtension<T> { 37 private static final String ID_ATTRIBUTE = "id"; //$NON-NLS-1$ 38 private static final String CLASS_ATTRIBUTE = "class"; //$NON-NLS-1$ 39 static final String CONTENT_TYPE_ATTRIBUTE = "contentType"; //$NON-NLS-1$ 40 private static final String ENABLED_WHEN_ATTRIBUTE = "enabledWhen"; //$NON-NLS-1$ 41 42 public final IConfigurationElement extension; 43 public final IContentType targetContentType; 44 public final Expression enabledWhen; 45 GenericContentTypeRelatedExtension(IConfigurationElement element)46 public GenericContentTypeRelatedExtension(IConfigurationElement element) throws Exception { 47 this.extension = element; 48 this.targetContentType = Platform.getContentTypeManager().getContentType(element.getAttribute(CONTENT_TYPE_ATTRIBUTE)); 49 this.enabledWhen = buildEnabledWhen(element); 50 } 51 createDelegate()52 @SuppressWarnings("unchecked") public T createDelegate() { 53 try { 54 return (T) extension.createExecutableExtension(CLASS_ATTRIBUTE); 55 } catch (CoreException e) { 56 GenericEditorPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, GenericEditorPlugin.BUNDLE_ID, e.getMessage(), e)); 57 } 58 return null; 59 } 60 61 /** 62 * Returns the expression {@link Expression} declared in the <code>enabledWhen</code> element. 63 * 64 * @param configElement 65 * the configuration element 66 * @return the expression {@link Expression} declared in the enabledWhen element. 67 * @throws CoreException 68 * when enabledWhen expression is not valid. 69 */ buildEnabledWhen(IConfigurationElement configElement)70 private static Expression buildEnabledWhen(IConfigurationElement configElement) throws CoreException { 71 final IConfigurationElement[] children = configElement.getChildren(ENABLED_WHEN_ATTRIBUTE); 72 if (children.length > 0) { 73 IConfigurationElement[] subChildren = children[0].getChildren(); 74 if (subChildren.length != 1) { 75 throw new CoreException(new Status(IStatus.ERROR, GenericEditorPlugin.BUNDLE_ID, "One <enabledWhen> element is accepted. Disabling " //$NON-NLS-1$ 76 + configElement.getAttribute(ID_ATTRIBUTE))); 77 } 78 final ElementHandler elementHandler = ElementHandler.getDefault(); 79 final ExpressionConverter converter = ExpressionConverter.getDefault(); 80 return elementHandler.create(converter, subChildren[0]); 81 } 82 return null; 83 } 84 85 /** 86 * Returns true if the given viewer, editor matches the enabledWhen expression and false otherwise. 87 * 88 * @param viewer 89 * the viewer 90 * @param editor 91 * the editor 92 * @return true if the given viewer, editor matches the enabledWhen expression and false otherwise. 93 */ matches(ISourceViewer viewer, ITextEditor editor)94 public boolean matches(ISourceViewer viewer, ITextEditor editor) { 95 if (enabledWhen == null) { 96 return true; 97 } 98 EvaluationContext context = new EvaluationContext(null, editor != null ? editor : viewer); 99 context.setAllowPluginActivation(true); 100 context.addVariable("viewer", viewer); //$NON-NLS-1$ 101 if (viewer.getDocument() != null) { 102 context.addVariable("document", viewer.getDocument()); //$NON-NLS-1$ 103 } 104 if (editor != null) { 105 context.addVariable("editor", editor); //$NON-NLS-1$ 106 context.addVariable("editorInput", editor.getEditorInput()); //$NON-NLS-1$ 107 } 108 try { 109 return enabledWhen.evaluate(context) == EvaluationResult.TRUE; 110 } catch (CoreException e) { 111 GenericEditorPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, GenericEditorPlugin.BUNDLE_ID, "Error while 'enabledWhen' evaluation", e)); //$NON-NLS-1$ 112 return false; 113 } 114 } 115 } 116