/******************************************************************************* * Copyright (c) 2011, 2015 Wind River Systems, Inc. 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: * Wind River Systems - initial API and implementation *******************************************************************************/ package org.eclipse.tcf.te.ui.trees; import java.lang.reflect.Constructor; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.concurrent.atomic.AtomicReference; import org.eclipse.core.expressions.EvaluationContext; import org.eclipse.core.expressions.EvaluationResult; import org.eclipse.core.expressions.Expression; import org.eclipse.core.expressions.ExpressionConverter; import org.eclipse.core.expressions.IEvaluationContext; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.SafeRunner; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.util.LocalSelectionTransfer; import org.eclipse.jface.util.SafeRunnable; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.DragSourceListener; import org.eclipse.swt.dnd.DropTargetListener; import org.eclipse.swt.dnd.FileTransfer; import org.eclipse.swt.dnd.ImageTransfer; import org.eclipse.swt.dnd.TextTransfer; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.graphics.Image; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.handlers.IHandlerService; import org.osgi.framework.Bundle; /** * The implementation of the tree viewer extension which is used to parse * the column, filter and content contributions declared in this extension * for a specified tree viewer. */ public class TreeViewerExtension { // The extension point id constant. private static final String EXTENSION_POINT_ID = "org.eclipse.tcf.te.ui.viewers"; //$NON-NLS-1$ // The id of the tree viewer for which the extension is parsed. private String viewerId; /** * Create an instance and parse all tree viewer extensions to get the * column descriptors and filter descriptors for the specified viewer. * * @param viewerId The tree viewer's id. */ public TreeViewerExtension(String viewerId) { this.viewerId = viewerId; } /** * Parse the viewer extensions and return the descriptor of the tree viewer. * * @return The viewer descriptor. */ public ViewerDescriptor parseViewer() { Assert.isNotNull(viewerId); IExtensionRegistry registry = Platform.getExtensionRegistry(); IExtensionPoint extensionPoint = registry.getExtensionPoint(EXTENSION_POINT_ID); IConfigurationElement[] configurations = extensionPoint.getConfigurationElements(); for (IConfigurationElement configuration : configurations) { String name = configuration.getName(); if ("viewer".equals(name)) { //$NON-NLS-1$ String id = configuration.getAttribute("id"); //$NON-NLS-1$ if (viewerId.equals(id)) { return createViewerDescriptor(configuration); } } } return null; } /** * Create a viewer descriptor from the given configuration element. * * @param configuration The configuration element that defines the viewer. * @return The viewer descriptor. */ private ViewerDescriptor createViewerDescriptor(final IConfigurationElement configuration) { final ViewerDescriptor descriptor = new ViewerDescriptor(); IConfigurationElement[] children = configuration.getChildren("creation"); //$NON-NLS-1$ if (children != null && children.length > 0) { Assert.isTrue(children.length == 1); descriptor.setStyleConfig(children[0]); } children = configuration.getChildren("dragSupport"); //$NON-NLS-1$ if (children != null && children.length > 0) { Assert.isTrue(children.length == 1); descriptor.setDragConfig(children[0]); } children = configuration.getChildren("dropSupport"); //$NON-NLS-1$ if (children != null && children.length > 0) { Assert.isTrue(children.length == 1); descriptor.setDropConfig(children[0]); } SafeRunner.run(new SafeRunnable() { @Override public void handleException(Throwable e) { // Ignore exception } @Override public void run() throws Exception { ITreeContentProvider contentProvider = (ITreeContentProvider) configuration.createExecutableExtension("contentProvider"); //$NON-NLS-1$ descriptor.setContentProvider(contentProvider); } }); String value = configuration.getAttribute("persistent"); //$NON-NLS-1$ if (value != null) { descriptor.setPersistent(Boolean.valueOf(value).booleanValue()); } value = configuration.getAttribute("useLabelDecorator"); //$NON-NLS-1$ if (value != null) { descriptor.setUseLabelDecorator(Boolean.valueOf(value).booleanValue()); } value = configuration.getAttribute("autoExpandLevel"); //$NON-NLS-1$ if (value != null) { try { int level = Integer.parseInt(value); descriptor.setAutoExpandLevel(level); } catch (NumberFormatException nfe) { } } return descriptor; } /** * Parse the column declarations of this extension point and return the * column descriptors. * * @param input The input used to initialize the columns. * @return The column descriptors from this extension point. */ public ColumnDescriptor[] parseColumns(Object input) { Assert.isNotNull(viewerId); List<ColumnDescriptor> columns = Collections.synchronizedList(new ArrayList<ColumnDescriptor>()); IExtensionRegistry registry = Platform.getExtensionRegistry(); IExtensionPoint extensionPoint = registry.getExtensionPoint(EXTENSION_POINT_ID); IConfigurationElement[] configurations = extensionPoint.getConfigurationElements(); for (IConfigurationElement configuration : configurations) { String name = configuration.getName(); if ("columnContribution".equals(name)) { //$NON-NLS-1$ String aViewerId = configuration.getAttribute("viewerId"); //$NON-NLS-1$ if (viewerId.equals(aViewerId)) { IConfigurationElement[] children = configuration.getChildren("column"); //$NON-NLS-1$ if (children != null && children.length > 0) { for (IConfigurationElement child : children) { createColumnDescriptor(input, columns, child); } } } } } return columns.toArray(new ColumnDescriptor[columns.size()]); } /** * Parse the viewer filter declarations of this extension point and return the * filter descriptors. * * @param input the new input * @return The filter descriptors from this extension point. */ public FilterDescriptor[] parseFilters(Object input) { Assert.isNotNull(viewerId); List<FilterDescriptor> descriptors = Collections.synchronizedList(new ArrayList<FilterDescriptor>()); IExtensionRegistry registry = Platform.getExtensionRegistry(); IExtensionPoint extensionPoint = registry.getExtensionPoint(EXTENSION_POINT_ID); IConfigurationElement[] configurations = extensionPoint.getConfigurationElements(); for (IConfigurationElement configuration : configurations) { String name = configuration.getName(); if ("filterContribution".equals(name)) { //$NON-NLS-1$ String aViewerId = configuration.getAttribute("viewerId"); //$NON-NLS-1$ if (viewerId.equals(aViewerId)) { IConfigurationElement[] children = configuration.getChildren("filter"); //$NON-NLS-1$ if (children != null && children.length > 0) { for (IConfigurationElement child : children) { createFilterDescriptor(input, descriptors, child); } } } } } return descriptors.toArray(new FilterDescriptor[descriptors.size()]); } /** * Create an filter descriptor from the specified configuration element and * add it to the filter list. * * @param input the input of the viewer to initialize the descriptors. * @param descriptors The filter list to add the created descriptor to. * @param configuration The extension configuration element to create the descriptor from. */ private void createFilterDescriptor(Object input, List<FilterDescriptor> descriptors, final IConfigurationElement configuration) { if (isElementActivated(input, configuration)) { String id = configuration.getAttribute("id"); //$NON-NLS-1$ Assert.isNotNull(id); final FilterDescriptor descriptor = new FilterDescriptor(); descriptor.setId(id); descriptors.add(descriptor); SafeRunner.run(new SafeRunnable() { @Override public void handleException(Throwable e) { // Ignore exception } @Override public void run() throws Exception { initFilter(descriptor, configuration); } }); } } /** * Initialize the filter descriptor from the specified configuration element. * * @param descriptor The new descriptor to be initialized. * @param configuration The configuration element to initialize the filter. * @throws CoreException Thrown during parsing. */ void initFilter(FilterDescriptor descriptor, IConfigurationElement configuration) throws CoreException { String attribute = configuration.getAttribute("name"); //$NON-NLS-1$ Assert.isNotNull(attribute); descriptor.setName(attribute); attribute = configuration.getAttribute("description"); //$NON-NLS-1$ if (attribute != null) { descriptor.setDescription(attribute); } attribute = configuration.getAttribute("image"); //$NON-NLS-1$ if (attribute != null) { String symbolicName = configuration.getContributor().getName(); URL resource = Platform.getBundle(symbolicName).getResource(attribute); Image image = ImageDescriptor.createFromURL(resource).createImage(); descriptor.setImage(image); } attribute = configuration.getAttribute("enabled"); //$NON-NLS-1$ if (attribute != null) { descriptor.setEnabled(Boolean.valueOf(attribute).booleanValue()); } attribute = configuration.getAttribute("class"); //$NON-NLS-1$ Assert.isNotNull(attribute); ViewerFilter filter = (ViewerFilter) configuration.createExecutableExtension("class"); //$NON-NLS-1$ Assert.isNotNull(filter); descriptor.setFilter(filter); attribute = configuration.getAttribute("visibleInUI"); //$NON-NLS-1$ if(attribute != null) { descriptor.setVisible(Boolean.valueOf(attribute).booleanValue()); } } /** * Create a column descriptor from the specified configuration element and add it to * the column descriptor list. * * @param input the new input. * @param columns The column descriptor. * @param configuration The configuration element to read the descriptor from. */ private void createColumnDescriptor(Object input, final List<ColumnDescriptor> columns, final IConfigurationElement configuration) { if (isElementActivated(input, configuration)) { String id = configuration.getAttribute("id"); //$NON-NLS-1$ Assert.isNotNull(id); final ColumnDescriptor column = new ColumnDescriptor(id); columns.add(column); SafeRunner.run(new SafeRunnable() { @Override public void handleException(Throwable e) { // Ignore exception } @Override public void run() throws Exception { initColumn(column, configuration); column.setOrder(columns.size()); } }); } } /** * Parse the content contribution declarations of this extension point and return the * content descriptors. * * @param input the new input * @return The content descriptors from this extension point. */ public ContentDescriptor[] parseContents(Object input) { Assert.isNotNull(viewerId); List<ContentDescriptor> descriptors = Collections.synchronizedList(new ArrayList<ContentDescriptor>()); IExtensionRegistry registry = Platform.getExtensionRegistry(); IExtensionPoint extensionPoint = registry.getExtensionPoint(EXTENSION_POINT_ID); IConfigurationElement[] configurations = extensionPoint.getConfigurationElements(); for (IConfigurationElement configuration : configurations) { String name = configuration.getName(); if ("contentContribution".equals(name)) { //$NON-NLS-1$ String aViewerId = configuration.getAttribute("viewerId"); //$NON-NLS-1$ if (viewerId.equals(aViewerId)) { IConfigurationElement[] children = configuration.getChildren("content"); //$NON-NLS-1$ if (children != null && children.length > 0) { for (IConfigurationElement child : children) { createContentDescriptor(input, descriptors, child); } } } } } return descriptors.toArray(new ContentDescriptor[descriptors.size()]); } /** * Create an content descriptor from the specified configuration element and * add it to the content descriptor list. * * @param input the input of the viewer to initialize the descriptors. * @param descriptors The content descriptor list to add the created descriptor to. * @param configuration The extension configuration element to create the descriptor from. */ private void createContentDescriptor(Object input, List<ContentDescriptor> descriptors, final IConfigurationElement configuration) { Assert.isNotNull(descriptors); Assert.isNotNull(configuration); if (isElementActivated(input, configuration)) { String id = configuration.getAttribute("id"); //$NON-NLS-1$ Assert.isNotNull(id); final ContentDescriptor descriptor = new ContentDescriptor(id, configuration); descriptors.add(descriptor); } } /** * If the specified configuration element is activated under the current input. * * @param input The input object. * @param configuration The configuration element that defines the activation element. * @return true if it is activated. */ private boolean isElementActivated(Object input, final IConfigurationElement configuration) { IConfigurationElement[] children = configuration.getChildren("activation"); //$NON-NLS-1$ if(children == null || children.length == 0) return true; children = children[0].getChildren(); if(children == null || children.length == 0) return true; final IConfigurationElement config = children[0]; IEvaluationContext currentState = ((IHandlerService)PlatformUI.getWorkbench().getService(IHandlerService.class)).getCurrentState(); final EvaluationContext context = new EvaluationContext(currentState, input); context.addVariable("input", input); //$NON-NLS-1$ context.setAllowPluginActivation(true); final boolean[] result = new boolean[1]; SafeRunner.run(new SafeRunnable() { @Override public void handleException(Throwable e) { // Ignore exception } @Override public void run() throws Exception { Expression expression = ExpressionConverter.getDefault().perform(config); EvaluationResult evaluate = expression.evaluate(context); if (evaluate == EvaluationResult.TRUE) { result[0] = true; } } }); return result[0]; } /** * Initialize the column descriptor by reading the attributes from the configuration element. * * @param column The column descriptor to be initialized. * @param configuration The configuration element. * @throws CoreException Thrown during parsing. */ void initColumn(ColumnDescriptor column, IConfigurationElement configuration) throws CoreException { String name = configuration.getAttribute("name"); //$NON-NLS-1$ Assert.isNotNull(name); column.setName(name); column.setDescription(configuration.getAttribute("description")); //$NON-NLS-1$ String attribute = configuration.getAttribute("moveable"); //$NON-NLS-1$ if (attribute != null) { column.setMoveable(Boolean.valueOf(attribute).booleanValue()); } attribute = configuration.getAttribute("resizable"); //$NON-NLS-1$ if (attribute != null) { column.setResizable(Boolean.valueOf(attribute).booleanValue()); } attribute = configuration.getAttribute("visible"); //$NON-NLS-1$ if (attribute != null) { column.setVisible(Boolean.valueOf(attribute).booleanValue()); } attribute = configuration.getAttribute("style"); //$NON-NLS-1$ if (attribute != null) { column.setStyle(parseAlignment(attribute)); } attribute = configuration.getAttribute("alignment"); //$NON-NLS-1$ if (attribute != null) { column.setAlignment(parseAlignment(attribute)); } attribute = configuration.getAttribute("width"); //$NON-NLS-1$ if (attribute != null) { try { column.setWidth(Integer.parseInt(attribute)); } catch (NumberFormatException e) { } } attribute = configuration.getAttribute("image"); //$NON-NLS-1$ if (attribute != null) { String symbolicName = configuration.getContributor().getName(); URL resource = Platform.getBundle(symbolicName).getResource(attribute); Image image = ImageDescriptor.createFromURL(resource).createImage(); column.setImage(image); } attribute = configuration.getAttribute("labelProvider"); //$NON-NLS-1$ if (attribute != null) { ILabelProvider labelProvider = (ILabelProvider) configuration.createExecutableExtension("labelProvider"); //$NON-NLS-1$ if (labelProvider != null) { column.setLabelProvider(labelProvider); } } attribute = configuration.getAttribute("comparator"); //$NON-NLS-1$ if (attribute != null) { @SuppressWarnings("unchecked") Comparator<Object> comparator = (Comparator<Object>) configuration.createExecutableExtension("comparator"); //$NON-NLS-1$ if (comparator != null) { column.setComparator(comparator); } } } /** * Parse the alignment attribute from a string to integer value. * * @param attribute The attribute value. * @return The alignment/style value. */ private int parseAlignment(String attribute) { if ("SWT.LEFT".equals(attribute)) { //$NON-NLS-1$ return SWT.LEFT; } else if ("SWT.RIGHT".equals(attribute)) { //$NON-NLS-1$ return SWT.RIGHT; } else if ("SWT.CENTER".equals(attribute)) { //$NON-NLS-1$ return SWT.CENTER; } return SWT.NONE; } /** * Parse the style name from a string to integer value. * * @param attribute The attribute value. * @return The alignment/style value. */ private int parseStyleName(String name) { if ("SWT.NONE".equals(name)) { //$NON-NLS-1$ return SWT.NONE; } else if ("SWT.SINGLE".equals(name)) { //$NON-NLS-1$ return SWT.SINGLE; } else if ("SWT.MULTI".equals(name)) { //$NON-NLS-1$ return SWT.MULTI; } else if ("SWT.CHECK".equals(name)) { //$NON-NLS-1$ return SWT.CHECK; } else if ("SWT.FULL_SELECTION".equals(name)) { //$NON-NLS-1$ return SWT.FULL_SELECTION; } else if ("SWT.VIRTUAL".equals(name)) { //$NON-NLS-1$ return SWT.VIRTUAL; } else if ("SWT.NO_SCROLL".equals(name)) { //$NON-NLS-1$ return SWT.NO_SCROLL; } return SWT.NONE; } /** * Parse the DND operation style and return a operation. * * @param name The name of the DND operation. * @return an integer that represents the operation. */ private int parseDndOp(String name) { if("DND.DROP_COPY".equals(name)) { //$NON-NLS-1$ return DND.DROP_COPY; } else if("DND.DROP_MOVE".equals(name)) { //$NON-NLS-1$ return DND.DROP_MOVE; } else if("DND.DROP_LINK".equals(name)) { //$NON-NLS-1$ return DND.DROP_LINK; } return 0; } /** * Parse and calculate the style from the give configuration element. * * @param configuration The configuration element that defines the styles. * @return An integer that represents the defined styles. */ public int parseStyle(IConfigurationElement configuration) { IConfigurationElement[] children = configuration.getChildren(); int style = SWT.NONE; for(IConfigurationElement child : children) { String name = child.getAttribute("name"); //$NON-NLS-1$ style |= parseStyleName(name); } return style; } /** * Parse the DND operation including DROP_COPY, * DROP_MOVE, DROP_LINK * * @param configuration The configuration element in which the DND operation is defined. * @return The operations. */ public int parseDnd(IConfigurationElement configuration) { IConfigurationElement[] children = configuration.getChildren("operations"); //$NON-NLS-1$ Assert.isTrue(children != null && children.length == 1); children = children[0].getChildren(); int operations = 0; for(IConfigurationElement child : children) { String name = child.getAttribute("name"); //$NON-NLS-1$ operations |= parseDndOp(name); } return operations; } /** * Parse the transfer type from the give configuration element. * * @param configuration The configuration element. * @return An array of transfer object that represents the transfer types. */ public Transfer[] parseTransferTypes(IConfigurationElement configuration) { List<Transfer> transferTypes = new ArrayList<Transfer>(); IConfigurationElement[] children = configuration.getChildren("transferTypes"); //$NON-NLS-1$ Assert.isTrue(children != null && children.length == 1); children = children[0].getChildren(); for(IConfigurationElement child : children) { String name = child.getAttribute("name"); //$NON-NLS-1$ Transfer transfer = parseTransferType(name); if (transfer != null) transferTypes.add(transfer); } return transferTypes.toArray(new Transfer[transferTypes.size()]); } /** * Translate the transfer type from this element. * * @param name The attribute name. * @return The transfer instance. */ private Transfer parseTransferType(String name) { if("TextTransfer".equals(name)) { //$NON-NLS-1$ return TextTransfer.getInstance(); } if("ImageTransfer".equals(name)) { //$NON-NLS-1$ return ImageTransfer.getInstance(); } if("FileTransfer".equals(name)) { //$NON-NLS-1$ return FileTransfer.getInstance(); } if("LocalSelectionTransfer".equals(name)) { //$NON-NLS-1$ return LocalSelectionTransfer.getTransfer(); } return null; } /** * Parse a DragSourceListener and return its instance. * * @param viewer The tree viewer to create an element. * @param configuration The configuration that wraps the instance. * @return The drag source listener created. */ public DragSourceListener parseDragSourceListener(final TreeViewer viewer, final IConfigurationElement configuration) { final AtomicReference<DragSourceListener> reference = new AtomicReference<DragSourceListener>(); SafeRunner.run(new SafeRunnable(){ @Override public void handleException(Throwable e) { // Ignore exception } @Override public void run() throws Exception { reference.set((DragSourceListener) createExecutableExtension(DragSourceListener.class, viewer, configuration)); }}); return reference.get(); } /** * Create an executable instance from the given configuration element, with the tree viewer * as the constructor parameter. * * @param aInterface The interface of the element should implement. * @param viewer The tree viewer to be passed * @param configuration The configuration element. * @return The object created. * @throws Exception */ Object createExecutableExtension(Class<?> aInterface, TreeViewer viewer, IConfigurationElement configuration) throws Exception{ String classname = configuration.getAttribute("class"); //$NON-NLS-1$ Assert.isNotNull(classname); String contributorId = configuration.getContributor().getName(); Bundle bundle = Platform.getBundle(contributorId); Assert.isNotNull(bundle); Class<?> clazz = bundle.loadClass(classname); Assert.isTrue(aInterface.isAssignableFrom(clazz)); try { Constructor<?> constructor = clazz.getConstructor(TreeViewer.class); return constructor.newInstance(viewer); } catch (NoSuchMethodException e) { Constructor<?> constructor = clazz.getConstructor(); return constructor.newInstance(); } } /** * Parse a DropTargetListener and return its instance. * * @param viewer The tree viewer to create an element. * @param configuration The configuration that wraps the instance. * @return The drop target listener created. */ public DropTargetListener parseDropTargetListener(final TreeViewer viewer, final IConfigurationElement configuration) { final AtomicReference<DropTargetListener> reference = new AtomicReference<DropTargetListener>(); SafeRunner.run(new SafeRunnable(){ @Override public void handleException(Throwable e) { // Ignore exception } @Override public void run() throws Exception { reference.set((DropTargetListener) createExecutableExtension(DropTargetListener.class, viewer, configuration)); }}); return reference.get(); } }