blob: 6012c74d21f0dcfefae346c4000a44c4d4324c24 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2006 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
*******************************************************************************/
package org.eclipse.ui.part;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.swt.dnd.ByteArrayTransfer;
import org.eclipse.swt.dnd.TransferData;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IElementFactory;
import org.eclipse.ui.IPersistableElement;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.WorkbenchException;
import org.eclipse.ui.XMLMemento;
/**
* The <code>EditorInputTransfer</code> class is used to transfer an
* <code>IEditorInput</code> and corresponding editorId from one part to another
* in a drag and drop operation. Only opening of internal editors is supported.
* <p>
* In every drag and drop operation there is a <code>DragSource</code> and a
* <code>DropTarget</code>. When a drag occurs a <code>Transfer</code> is used
* to marshall the drag data from the source into a byte array. If a drop
* occurs another <code>Transfer</code> is used to marshall the byte array into
* drop data for the target.
* </p>
* <p>
* This class can be used for a <code>Viewer</code> or an SWT component directly.
* A singleton is provided which may be serially reused (see <code>getInstance</code>).
* For an implementor of <code>IEditorInput</code> to be supported by
* <code>EditorInputTransfer</code>, it must provide a proper implementation of
* <code>IEditorInput</code>.<code>getPersistable</code>. For further details,
* consult the <code>org.eclipse.ui.elementFactories</code> extension point.
* </p>
* <p>
* The data for a transfer is represented by the <code>EditorInputData</code>
* class, and a convenience method <code>createEditorInputData</code> is
* provided. A <code>DragSource</code>.<code>dragSetData</code> implementation
* should set the data to an array of <code>EditorInputData</code>. In this
* way, the dragging of multiple editor inputs is supported.
* </p>
* <p>
* Below is an example of how to set the data for dragging a single editor
* input using a <code>EditorInputTransfer</code>.
* </p>
* <p>
* <pre>
* public void dragSetData(DragSourceEvent event) {
* if (EditorInputTransfer.getInstance().isSupportedType(event.dataType)) {
*
* EditorInputTransfer.EditorInputData data =
* EditorInputTransfer.
* createEditorInputData(EDITOR_ID, getEditorInput());
* event.data = new EditorInputTransfer.EditorInputData [] {data};
* }
* }
* </pre>
* </p>
*
* @see org.eclipse.jface.viewers.StructuredViewer
* @see org.eclipse.swt.dnd.DropTarget
* @see org.eclipse.swt.dnd.DragSource
* @see org.eclipse.ui.IEditorInput
* @see org.eclipse.ui.IPersistableElement
* @see org.eclipse.ui.IElementFactory
* @since 1.3
*/
public class EditorInputTransfer extends ByteArrayTransfer {
/**
* Singleton instance.
*/
private static final EditorInputTransfer instance = new EditorInputTransfer();
// Create a unique ID to make sure that different Eclipse
// applications use different "types" of <code>EditorInputTransfer</code>
private static final String TYPE_NAME = "editor-input-transfer-format:" + System.currentTimeMillis() + ":" + instance.hashCode(); //$NON-NLS-2$//$NON-NLS-1$
private static final int TYPEID = registerType(TYPE_NAME);
public static class EditorInputData {
public String editorId;
public IEditorInput input;
private EditorInputData(String editorId, IEditorInput input) {
this.editorId = editorId;
this.input = input;
}
}
/**
* Creates a new transfer object.
*/
private EditorInputTransfer() {
}
/**
* Returns the singleton instance.
*
* @return the singleton instance
*/
public static EditorInputTransfer getInstance() {
return instance;
}
/* (non-Javadoc)
* Method declared on Transfer.
*/
protected int[] getTypeIds() {
return new int[] { TYPEID };
}
/* (non-Javadoc)
* Returns the type names.
*
* @return the list of type names
*/
protected String[] getTypeNames() {
return new String[] { TYPE_NAME };
}
/* (non-Javadoc)
* Method declared on Transfer.
*/
public void javaToNative(Object data, TransferData transferData) {
if (!(data instanceof EditorInputData[])) {
return;
}
EditorInputData[] editorInputs = (EditorInputData[]) data;
/**
* The editor input serialization format is:
* (int) number of editor inputs
* Then, the following for each editor input:
* (String) editorId
* (String) factoryId
* (String) data used to recreate the IEditorInput
*/
int editorInputCount = editorInputs.length;
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
DataOutputStream dataOut = new DataOutputStream(out);
//write the number of resources
dataOut.writeInt(editorInputCount);
//write each resource
for (int i = 0; i < editorInputs.length; i++) {
writeEditorInput(dataOut, editorInputs[i]);
}
//cleanup
dataOut.close();
out.close();
byte[] bytes = out.toByteArray();
super.javaToNative(bytes, transferData);
} catch (IOException e) {
}
}
/* (non-Javadoc)
* Method declared on Transfer.
*/
public Object nativeToJava(TransferData transferData) {
byte[] bytes = (byte[]) super.nativeToJava(transferData);
if (bytes == null) {
return null;
}
DataInputStream in = new DataInputStream(
new ByteArrayInputStream(bytes));
try {
int count = in.readInt();
EditorInputData[] results = new EditorInputData[count];
for (int i = 0; i < count; i++) {
results[i] = readEditorInput(in);
}
return results;
} catch (IOException e) {
return null;
} catch (WorkbenchException e) {
return null;
}
}
/**
* Method readEditorInput.
* @param in
* @return EditorInputData
*/
private EditorInputData readEditorInput(DataInputStream dataIn)
throws IOException, WorkbenchException {
String editorId = dataIn.readUTF();
String factoryId = dataIn.readUTF();
String xmlString = dataIn.readUTF();
if (xmlString == null || xmlString.length() == 0) {
return null;
}
StringReader reader = new StringReader(xmlString);
// Restore the editor input
XMLMemento memento = XMLMemento.createReadRoot(reader);
IElementFactory factory = PlatformUI.getWorkbench().getElementFactory(
factoryId);
if (factory != null) {
IAdaptable adaptable = factory.createElement(memento);
if (adaptable != null && (adaptable instanceof IEditorInput)) {
return new EditorInputData(editorId, (IEditorInput) adaptable);
}
}
return null;
}
/**
* Method writeEditorInput.
* @param dataOut
* @param editorInputData
*/
private void writeEditorInput(DataOutputStream dataOut,
EditorInputData editorInputData) throws IOException {
//write the id of the editor
dataOut.writeUTF(editorInputData.editorId);
//write the information needed to recreate the editor input
if (editorInputData.input != null) {
// Capture the editor information
XMLMemento memento = XMLMemento.createWriteRoot("IEditorInput");//$NON-NLS-1$
IPersistableElement element = editorInputData.input
.getPersistable();
if (element != null) {
//get the IEditorInput to save its state
element.saveState(memento);
//convert memento to String
StringWriter writer = new StringWriter();
memento.save(writer);
writer.close();
//write the factor ID and state information
dataOut.writeUTF(element.getFactoryId());
dataOut.writeUTF(writer.toString());
}
}
}
public static EditorInputData createEditorInputData(String editorId,
IEditorInput input) {
return new EditorInputData(editorId, input);
}
}