blob: 1d7d64a3eb3c2a3d813bc5a85dbf145b2101c795 [file] [log] [blame]
/*******************************************************************************
* 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;
}
}