| /******************************************************************************* |
| * Copyright (c) 2001, 2007 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 |
| * Jens Lukowski/Innoopract - initial renaming/restructuring |
| * |
| *******************************************************************************/ |
| package org.eclipse.wst.sse.ui.internal; |
| |
| |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.IExtensionRegistry; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.swt.custom.BusyIndicator; |
| import org.eclipse.swt.dnd.Transfer; |
| import org.eclipse.swt.dnd.TransferData; |
| import org.eclipse.wst.sse.ui.internal.extension.DropActionProxy; |
| import org.eclipse.wst.sse.ui.internal.extension.RegistryReader; |
| import org.osgi.framework.Bundle; |
| |
| |
| /** |
| * Builds drop target transfers, drag source transfers, and drop actions |
| */ |
| public class TransferBuilder extends RegistryReader { |
| |
| public static final String ATT_CLASS = "class"; //$NON-NLS-1$ |
| public static final String ATT_ID = "id"; //$NON-NLS-1$ |
| public static final String ATT_METHOD = "method"; //$NON-NLS-1$ |
| public static final String ATT_PRIORITY = "priority"; //$NON-NLS-1$ |
| public static final String ATT_SINGLETON = "singleton"; //$NON-NLS-1$ |
| public static final String ATT_TARGET_ID = "targetID"; //$NON-NLS-1$ |
| public static final String ATT_TRANSFER_ID = "transferID"; //$NON-NLS-1$ |
| |
| private final static boolean debugTime = "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.wst.sse.ui/transferbuilder/time")); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| public static final String PL_DRAG_SOURCE_TRANSFERS = "dragSourceTransfers"; //$NON-NLS-1$ |
| public static final String PL_DROP_TARGET_TRANSFERS = "dropTargetTransfers"; //$NON-NLS-1$ |
| |
| public static final String PLUGIN_ID = "org.eclipse.wst.sse.ui"; //$NON-NLS-1$ |
| |
| public static final String[] PRIORITIES = {"highest", "high", "mid", "low", "lowest"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ |
| |
| public static final String TAG_DRAG_SOURCE_CONTRIBUTION = "dragSourceContribution"; //$NON-NLS-1$ |
| public static final String TAG_DROP_ACTION = "dropAction"; //$NON-NLS-1$ |
| public static final String TAG_DROP_TARGET_CONTRIBUTION = "dropTargetContribution"; //$NON-NLS-1$ |
| |
| public static final String TAG_TRANSFER = "transfer"; //$NON-NLS-1$ |
| |
| public static final String TRUE = "true"; //$NON-NLS-1$ |
| |
| private boolean useProxy; |
| |
| class TransferProxyForDelayLoading extends Transfer { |
| private IConfigurationElement element; |
| private String classAttribute; |
| private Transfer proxy; |
| private Method getTypeIdsMethod, getTypeNamesMethod, javaToNativeMethod, nativeToJavaMethod; |
| |
| TransferProxyForDelayLoading() { |
| super(); |
| } |
| |
| TransferProxyForDelayLoading(IConfigurationElement elm, String clsAttr) { |
| super(); |
| this.element = elm; |
| this.classAttribute = clsAttr; |
| } |
| |
| private Transfer newInstance() { |
| if ((element != null) && (classAttribute != null)) { |
| Object o = createExtension(element, classAttribute); |
| if (o instanceof Transfer) { |
| element = null; |
| classAttribute = null; |
| return (Transfer)o; |
| } |
| } |
| return null; |
| } |
| |
| public TransferData[] getSupportedTypes() { |
| if (proxy == null) { |
| proxy = newInstance(); |
| } |
| if (proxy != null) { |
| return proxy.getSupportedTypes(); |
| } |
| return new TransferData[0]; |
| } |
| protected int[] getTypeIds() { |
| if (proxy == null) { |
| proxy = newInstance(); |
| } |
| if (proxy != null) { |
| if (getTypeIdsMethod == null) { |
| Class runtimeClass = proxy.getClass(); |
| NoSuchMethodException e = null; |
| while (runtimeClass != null) { |
| try { |
| getTypeIdsMethod = runtimeClass.getDeclaredMethod("getTypeIds", new Class[0]);//$NON-NLS-1$ |
| getTypeIdsMethod.setAccessible(true); |
| break; |
| } catch (NoSuchMethodException e1) { |
| e = e1; |
| runtimeClass = runtimeClass.getSuperclass(); |
| } catch (SecurityException e2) { |
| runtimeClass = runtimeClass.getSuperclass(); |
| } |
| } |
| if ((getTypeIdsMethod == null) && (e != null)) { |
| Logger.logException(e); |
| } |
| } |
| if (getTypeIdsMethod != null) { |
| try { |
| // changed Integer[] return type to int[] |
| int[] r = (int[])getTypeIdsMethod.invoke(proxy, new Object[0]); |
| if ((r != null) && (r.length > 0)) { |
| int[] ret = new int[r.length]; |
| for(int i = 0; i < r.length; i++) { |
| ret[i] = r[i]; |
| } |
| return ret; |
| } |
| } catch (IllegalAccessException e2) { |
| Logger.logException(e2); |
| } catch (InvocationTargetException e3) { |
| Logger.logException(e3); |
| } |
| } |
| } |
| return new int[0]; |
| } |
| protected String[] getTypeNames() { |
| if (proxy == null) { |
| proxy = newInstance(); |
| } |
| if (proxy != null) { |
| if (getTypeNamesMethod == null) { |
| Class runtimeClass = proxy.getClass(); |
| NoSuchMethodException e = null; |
| while (runtimeClass != null) { |
| try { |
| getTypeNamesMethod = runtimeClass.getDeclaredMethod("getTypeNames", new Class[0]);//$NON-NLS-1$ |
| getTypeNamesMethod.setAccessible(true); |
| break; |
| } catch (NoSuchMethodException e1) { |
| e = e1; |
| runtimeClass = runtimeClass.getSuperclass(); |
| } catch (SecurityException e2) { |
| runtimeClass = runtimeClass.getSuperclass(); |
| } |
| } |
| if ((getTypeNamesMethod == null) && (e != null)) { |
| Logger.logException(e); |
| } |
| } |
| if (getTypeNamesMethod != null) { |
| try { |
| return (String[])getTypeNamesMethod.invoke(proxy, new Object[0]); |
| } catch (IllegalAccessException e2) { |
| Logger.logException(e2); |
| } catch (InvocationTargetException e3) { |
| Logger.logException(e3); |
| } |
| } |
| } |
| return new String[0]; |
| } |
| public boolean isSupportedType(TransferData transferData) { |
| if (proxy == null) { |
| proxy = newInstance(); |
| } |
| if (proxy != null) { |
| return proxy.isSupportedType(transferData); |
| } |
| return false; |
| } |
| protected void javaToNative(Object object, TransferData transferData) { |
| if (proxy == null) { |
| proxy = newInstance(); |
| } |
| if (proxy != null) { |
| if (javaToNativeMethod == null) { |
| Class runtimeClass = proxy.getClass(); |
| NoSuchMethodException e = null; |
| while (runtimeClass != null) { |
| try { |
| javaToNativeMethod = runtimeClass.getDeclaredMethod("javaToNative", new Class[]{object.getClass(), transferData.getClass()});//$NON-NLS-1$ |
| javaToNativeMethod.setAccessible(true); |
| break; |
| } catch (NoSuchMethodException e1) { |
| e = e1; |
| runtimeClass = runtimeClass.getSuperclass(); |
| } catch (SecurityException e2) { |
| runtimeClass = runtimeClass.getSuperclass(); |
| } |
| } |
| if ((javaToNativeMethod == null) && (e != null)) { |
| Logger.logException(e); |
| } |
| } |
| if (javaToNativeMethod != null) { |
| try { |
| javaToNativeMethod.invoke(proxy, new Object[]{object, transferData}); |
| } catch (IllegalAccessException e2) { |
| Logger.logException(e2); |
| } catch (InvocationTargetException e3) { |
| Logger.logException(e3); |
| } |
| } |
| } |
| } |
| protected Object nativeToJava(TransferData transferData) { |
| if (proxy == null) { |
| proxy = newInstance(); |
| } |
| if (proxy != null) { |
| if (nativeToJavaMethod == null) { |
| Class runtimeClass = proxy.getClass(); |
| NoSuchMethodException e = null; |
| while (runtimeClass != null) { |
| try { |
| nativeToJavaMethod = runtimeClass.getDeclaredMethod("nativeToJava", new Class[]{transferData.getClass()});//$NON-NLS-1$ |
| nativeToJavaMethod.setAccessible(true); |
| break; |
| } catch (NoSuchMethodException e1) { |
| e = e1; |
| runtimeClass = runtimeClass.getSuperclass(); |
| } catch (SecurityException e2) { |
| runtimeClass = runtimeClass.getSuperclass(); |
| } |
| } |
| if ((nativeToJavaMethod == null) && (e != null)) { |
| Logger.logException(e); |
| } |
| } |
| if (nativeToJavaMethod != null) { |
| try { |
| return nativeToJavaMethod.invoke(proxy, new Object[]{transferData}); |
| } catch (IllegalAccessException e2) { |
| Logger.logException(e2); |
| } catch (InvocationTargetException e3) { |
| Logger.logException(e3); |
| } |
| } |
| } |
| return new Object(); |
| } |
| Transfer getTransferClass() { |
| if (proxy == null) { |
| proxy = newInstance(); |
| } |
| return proxy; |
| } |
| |
| public String toString() { |
| String clazz = element.getAttribute(classAttribute); |
| return clazz != null ? clazz : super.toString(); |
| } |
| } |
| /** |
| * @param element |
| * @param classAttribute |
| * @return Object |
| * @throws CoreException |
| */ |
| static Object createExecutableExtension(final IConfigurationElement element, final String classAttribute) throws CoreException { |
| |
| Object obj = null; |
| |
| String singleton = element.getAttribute(ATT_SINGLETON); |
| String method = element.getAttribute(ATT_METHOD); |
| if (TRUE.equalsIgnoreCase(singleton) && method != null) { |
| try { |
| String name = element.getAttribute(ATT_CLASS); |
| String pluginId = element.getDeclaringExtension().getNamespace(); |
| Class cls = Platform.getBundle(pluginId).loadClass(name); |
| Method mtd = cls.getMethod(method, new Class[]{}); |
| |
| obj = mtd.invoke(null, null); |
| } catch (ClassNotFoundException e) { |
| obj = null; |
| } catch (NoSuchMethodException e) { |
| obj = null; |
| } catch (IllegalAccessException e) { |
| obj = null; |
| } catch (InvocationTargetException e) { |
| obj = null; |
| } |
| } else { |
| obj = element.createExecutableExtension(classAttribute); |
| } |
| |
| return obj; |
| } |
| |
| /** |
| * Creates an extension. If the extension plugin has not been loaded a |
| * busy cursor will be activated during the duration of the load. |
| * |
| * @param element |
| * @param classAttribute |
| * @return Object |
| * @throws CoreException |
| */ |
| public static Object createExtension(final IConfigurationElement element, final String classAttribute) { |
| // If plugin has been loaded create extension. |
| // Otherwise, show busy cursor then create extension. |
| final Object[] result = new Object[1]; |
| String pluginId = element.getDeclaringExtension().getNamespace(); |
| Bundle bundle = Platform.getBundle(pluginId); |
| if (bundle.getState() == Bundle.ACTIVE) { |
| try { |
| return createExecutableExtension(element, classAttribute); |
| } catch (CoreException e) { |
| handleCreateExecutableException(result, e); |
| } |
| } else { |
| BusyIndicator.showWhile(null, new Runnable() { |
| public void run() { |
| try { |
| result[0] = createExecutableExtension(element, classAttribute); |
| } catch (Exception e) { |
| handleCreateExecutableException(result, e); |
| } |
| } |
| }); |
| } |
| return result[0]; |
| } |
| |
| /** |
| * @param result |
| * @param e |
| */ |
| protected static void handleCreateExecutableException(Object[] result, Throwable e) { |
| Logger.logException(e); |
| result[0] = null; |
| |
| } |
| |
| protected List cache; |
| protected String targetContributionTag; |
| |
| protected List targetIDs; |
| |
| /** |
| * @param element |
| * @return IDropAction |
| */ |
| protected IDropAction createDropAction(IConfigurationElement element) { |
| Object obj = null; |
| obj = createExtension(element, ATT_CLASS); |
| if (obj == null) |
| return null; |
| return (obj instanceof IDropAction) ? (IDropAction) DropActionProxy.newInstance(obj) : null; |
| } |
| |
| /** |
| * @param transferId |
| * @return IDropAction[] |
| */ |
| protected IDropAction[] createDropActions(String transferId) { |
| if (cache == null) |
| return new IDropAction[0]; |
| |
| final int num = cache.size(); |
| if (num == 0) |
| return new IDropAction[0]; |
| |
| IDropAction[] as = new IDropAction[num]; |
| int j = 0; |
| for (int p = 0; p < PRIORITIES.length; p++) { |
| for (int i = 0; i < num; i++) { |
| Object obj = cache.get(i); |
| if (!(obj instanceof IConfigurationElement)) |
| continue; |
| |
| IConfigurationElement element = (IConfigurationElement) obj; |
| if (!(TAG_DROP_ACTION.equals(element.getName())) || !(transferId.equals(element.getAttribute(ATT_TRANSFER_ID)))) |
| continue; |
| |
| if (PRIORITIES[p].equals(element.getAttribute(ATT_PRIORITY)) || (p == 2 && element.getAttribute(ATT_PRIORITY) == null)) { |
| IDropAction a = createDropAction(element); |
| if (a != null) { |
| as[j] = a; |
| j++; |
| } |
| } |
| } |
| } |
| |
| if (num == j) |
| return as; |
| |
| IDropAction[] as2 = new IDropAction[j]; |
| for (int i = 0; i < j; i++) { |
| as2[i] = as[i]; |
| } |
| |
| return as2; |
| } |
| |
| /** |
| * @param element |
| * @return Transfer |
| */ |
| protected Transfer createTransfer(IConfigurationElement element) { |
| Object obj = null; |
| if (useProxy) { |
| obj = new TransferProxyForDelayLoading(element, ATT_CLASS); |
| } else { |
| obj = createExtension(element, ATT_CLASS); |
| } |
| if (obj == null) |
| return null; |
| return (obj instanceof Transfer) ? (Transfer) obj : null; |
| } |
| |
| /** |
| * @return Transfer[] |
| */ |
| protected Transfer[] createTransfers() { |
| if (cache == null) |
| return new Transfer[0]; |
| |
| final int num = cache.size(); |
| if (num == 0) |
| return new Transfer[0]; |
| |
| Transfer[] ts = new Transfer[num]; |
| int j = 0; |
| for (int p = 0; p < PRIORITIES.length; p++) { |
| for (int i = 0; i < num; i++) { |
| Object obj = cache.get(i); |
| if (!(obj instanceof IConfigurationElement)) |
| continue; |
| |
| IConfigurationElement element = (IConfigurationElement) obj; |
| if (!TAG_TRANSFER.equals(element.getName())) |
| continue; |
| |
| if (PRIORITIES[p].equals(element.getAttribute(ATT_PRIORITY)) || (p == 2 && element.getAttribute(ATT_PRIORITY) == null)) { |
| Transfer t = createTransfer(element); |
| if (t != null) { |
| ts[j] = t; |
| j++; |
| } |
| } |
| } |
| } |
| |
| if (num == j) |
| return ts; |
| |
| Transfer[] ts2 = new Transfer[j]; |
| for (int i = 0; i < j; i++) { |
| ts2[i] = ts[i]; |
| } |
| |
| return ts2; |
| } |
| |
| /** |
| * @param editorId |
| * @return Transfer[] |
| */ |
| public Transfer[] getDragSourceTransfers(String editorId) { |
| return getDragSourceTransfers(new String[]{editorId}); |
| } |
| |
| /** |
| * @param editorIds |
| * @return Transfer[] |
| */ |
| public Transfer[] getDragSourceTransfers(String[] editorIds) { |
| long time0 = System.currentTimeMillis(); |
| readContributions(editorIds, TAG_DRAG_SOURCE_CONTRIBUTION, PL_DRAG_SOURCE_TRANSFERS); |
| Transfer[] transfers = createTransfers(); |
| if (debugTime) |
| System.out.println(getClass().getName() + "#getDragSourceTransfers(" + editorIds + "): " + transfers.length + " transfers created in " + (System.currentTimeMillis() - time0) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
| return transfers; |
| } |
| |
| /** |
| * @deprecated use getDropActions(String editorId, Transfer transfer) for the performance |
| * @param editorId |
| * @param className |
| * @return IDropAction[] |
| */ |
| public IDropAction[] getDropActions(String editorId, String transferClassName) { |
| return getDropActions(new String[]{editorId}, transferClassName); |
| } |
| |
| /** |
| * @param editorId |
| * @param class |
| * @return IDropAction[] |
| */ |
| public IDropAction[] getDropActions(String editorId, Transfer transfer) { |
| return getDropActions(new String[]{editorId}, transfer); |
| } |
| /** |
| * @deprecated use getDropActions(String[] editorIds, Transfer transfer) for the performance |
| * @param editorId |
| * @param className |
| * @return IDropAction[] |
| */ |
| public IDropAction[] getDropActions(String[] editorIds, String transferClassName) { |
| long time0 = System.currentTimeMillis(); |
| readContributions(editorIds, TAG_DROP_TARGET_CONTRIBUTION, PL_DROP_TARGET_TRANSFERS); |
| String transferId = getTransferIdOfClassName(transferClassName); |
| IDropAction[] actions = createDropActions(transferId); |
| if (debugTime) |
| System.out.println(getClass().getName() + "#getDropActions(" + editorIds + "): " + actions.length + " drop actions created in " + (System.currentTimeMillis() - time0) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
| return actions; |
| } |
| |
| /** |
| * @param editorId |
| * @param class |
| * @return IDropAction[] |
| */ |
| public IDropAction[] getDropActions(String[] editorIds, Transfer transfer) { |
| String transferClassName; |
| if (transfer instanceof TransferProxyForDelayLoading) { |
| transferClassName = ((TransferProxyForDelayLoading)transfer).getTransferClass().getClass().getName(); |
| } else { |
| transferClassName = transfer.getClass().getName(); |
| } |
| return getDropActions(editorIds, transferClassName); |
| } |
| /** |
| * @param editorId |
| * @return Transfer[] |
| */ |
| public Transfer[] getDropTargetTransfers(String editorId) { |
| return getDropTargetTransfers(new String[]{editorId}); |
| } |
| |
| /** |
| * @param editorIds |
| * @return Transfer[] |
| */ |
| public Transfer[] getDropTargetTransfers(String[] editorIds) { |
| long time0 = System.currentTimeMillis(); |
| readContributions(editorIds, TAG_DROP_TARGET_CONTRIBUTION, PL_DROP_TARGET_TRANSFERS); |
| Transfer[] transfers = createTransfers(); |
| if (debugTime) { |
| String idlist = ""; //$NON-NLS-1$ |
| if (editorIds.length > 0) { |
| for (int i = 0; i < editorIds.length; i++) { |
| idlist += editorIds[i]; |
| if (i < editorIds.length - 1) |
| idlist += ","; //$NON-NLS-1$ |
| } |
| } |
| System.out.println(getClass().getName() + "#getDropTargetTransfers(" + idlist + "): " + transfers.length + " transfers created in " + (System.currentTimeMillis() - time0) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
| } |
| return transfers; |
| } |
| |
| /** |
| * Returns the name of the part ID attribute that is expected in the |
| * target extension. |
| * |
| * @param element |
| * @return String |
| */ |
| protected String getTargetID(IConfigurationElement element) { |
| String value = element.getAttribute(ATT_TARGET_ID); |
| return value != null ? value : "???"; //$NON-NLS-1$ |
| } |
| |
| /** |
| * @param className |
| * @return String |
| */ |
| private String getTransferIdOfClassName(String className) { |
| String id = ""; //$NON-NLS-1$ |
| final int num = cache.size(); |
| if (className == null || cache == null || num == 0) |
| return id; |
| |
| for (int i = 0; i < num; i++) { |
| Object obj = cache.get(i); |
| if (obj instanceof IConfigurationElement) { |
| IConfigurationElement element = (IConfigurationElement) obj; |
| if (className.equals(element.getAttribute(ATT_CLASS))) { |
| id = element.getAttribute(ATT_ID); |
| break; |
| } |
| } |
| } |
| |
| return (id.length() != 0 ? id : className); |
| } |
| |
| /** |
| * Reads the contributions from the registry for the provided workbench |
| * part and the provided extension point ID. |
| * |
| * @param id |
| * @param tag |
| * @param extensionPoint |
| */ |
| protected void readContributions(String[] ids, String tag, String extensionPoint) { |
| cache = null; |
| targetIDs = Arrays.asList(ids); |
| targetContributionTag = tag; |
| IExtensionRegistry registry = Platform.getExtensionRegistry(); |
| readRegistry(registry, PLUGIN_ID, extensionPoint); |
| } |
| |
| protected boolean readElement(IConfigurationElement element) { |
| String tag = element.getName(); |
| if (tag.equals(targetContributionTag)) { |
| String id = getTargetID(element); |
| if (id == null || !targetIDs.contains(id)) { |
| // This is not of interest to us - don't go deeper |
| return true; |
| } |
| } else if (tag.equals(TAG_TRANSFER)) { |
| if (cache == null) |
| cache = new ArrayList(); |
| cache.add(element); |
| return true; // just cache the element - don't go into it |
| } else if (tag.equals(TAG_DROP_ACTION)) { |
| if (cache == null) |
| cache = new ArrayList(); |
| //cache.add(createActionDescriptor(element)); |
| cache.add(element); |
| return true; // just cache the action - don't go into |
| } else { |
| return false; |
| } |
| |
| readElementChildren(element); |
| return true; |
| } |
| /** |
| * @deprecated - use TransferBuilder(boolean useProxy) for the performance |
| */ |
| public TransferBuilder() { |
| this(false); |
| } |
| |
| public TransferBuilder(boolean useProxy) { |
| super(); |
| this.useProxy = useProxy; |
| } |
| } |