001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.part;
011:
012: import java.io.ByteArrayInputStream;
013: import java.io.ByteArrayOutputStream;
014: import java.io.DataInputStream;
015: import java.io.DataOutputStream;
016: import java.io.IOException;
017: import java.io.StringReader;
018: import java.io.StringWriter;
019:
020: import org.eclipse.core.runtime.IAdaptable;
021: import org.eclipse.swt.dnd.ByteArrayTransfer;
022: import org.eclipse.swt.dnd.TransferData;
023: import org.eclipse.ui.IEditorInput;
024: import org.eclipse.ui.IElementFactory;
025: import org.eclipse.ui.IPersistableElement;
026: import org.eclipse.ui.PlatformUI;
027: import org.eclipse.ui.WorkbenchException;
028: import org.eclipse.ui.XMLMemento;
029:
030: /**
031: * The <code>EditorInputTransfer</code> class is used to transfer an
032: * <code>IEditorInput</code> and corresponding editorId from one part to another
033: * in a drag and drop operation. Only opening of internal editors is supported.
034: * <p>
035: * In every drag and drop operation there is a <code>DragSource</code> and a
036: * <code>DropTarget</code>. When a drag occurs a <code>Transfer</code> is used
037: * to marshall the drag data from the source into a byte array. If a drop
038: * occurs another <code>Transfer</code> is used to marshall the byte array into
039: * drop data for the target.
040: * </p>
041: * <p>
042: * This class can be used for a <code>Viewer</code> or an SWT component directly.
043: * A singleton is provided which may be serially reused (see <code>getInstance</code>).
044: * For an implementor of <code>IEditorInput</code> to be supported by
045: * <code>EditorInputTransfer</code>, it must provide a proper implementation of
046: * <code>IEditorInput</code>.<code>getPersistable</code>. For further details,
047: * consult the <code>org.eclipse.ui.elementFactories</code> extension point.
048: * </p>
049: * <p>
050: * The data for a transfer is represented by the <code>EditorInputData</code>
051: * class, and a convenience method <code>createEditorInputData</code> is
052: * provided. A <code>DragSource</code>.<code>dragSetData</code> implementation
053: * should set the data to an array of <code>EditorInputData</code>. In this
054: * way, the dragging of multiple editor inputs is supported.
055: * </p>
056: * <p>
057: * Below is an example of how to set the data for dragging a single editor
058: * input using a <code>EditorInputTransfer</code>.
059: * </p>
060: * <p>
061: * <pre>
062: * public void dragSetData(DragSourceEvent event) {
063: * if (EditorInputTransfer.getInstance().isSupportedType(event.dataType)) {
064: *
065: * EditorInputTransfer.EditorInputData data =
066: * EditorInputTransfer.
067: * createEditorInputData(EDITOR_ID, getEditorInput());
068: * event.data = new EditorInputTransfer.EditorInputData [] {data};
069: * }
070: * }
071: * </pre>
072: * </p>
073: *
074: * @see org.eclipse.jface.viewers.StructuredViewer
075: * @see org.eclipse.swt.dnd.DropTarget
076: * @see org.eclipse.swt.dnd.DragSource
077: * @see org.eclipse.ui.IEditorInput
078: * @see org.eclipse.ui.IPersistableElement
079: * @see org.eclipse.ui.IElementFactory
080: */
081: public class EditorInputTransfer extends ByteArrayTransfer {
082:
083: /**
084: * Singleton instance.
085: */
086: private static final EditorInputTransfer instance = new EditorInputTransfer();
087:
088: // Create a unique ID to make sure that different Eclipse
089: // applications use different "types" of <code>EditorInputTransfer</code>
090: private static final String TYPE_NAME = "editor-input-transfer-format:" + System.currentTimeMillis() + ":" + instance.hashCode(); //$NON-NLS-2$//$NON-NLS-1$
091:
092: private static final int TYPEID = registerType(TYPE_NAME);
093:
094: public static class EditorInputData {
095:
096: public String editorId;
097:
098: public IEditorInput input;
099:
100: private EditorInputData(String editorId, IEditorInput input) {
101: this .editorId = editorId;
102: this .input = input;
103: }
104: }
105:
106: /**
107: * Creates a new transfer object.
108: */
109: private EditorInputTransfer() {
110: }
111:
112: /**
113: * Returns the singleton instance.
114: *
115: * @return the singleton instance
116: */
117: public static EditorInputTransfer getInstance() {
118: return instance;
119: }
120:
121: /* (non-Javadoc)
122: * Method declared on Transfer.
123: */
124: protected int[] getTypeIds() {
125: return new int[] { TYPEID };
126: }
127:
128: /* (non-Javadoc)
129: * Returns the type names.
130: *
131: * @return the list of type names
132: */
133: protected String[] getTypeNames() {
134: return new String[] { TYPE_NAME };
135: }
136:
137: /* (non-Javadoc)
138: * Method declared on Transfer.
139: */
140: public void javaToNative(Object data, TransferData transferData) {
141:
142: if (!(data instanceof EditorInputData[])) {
143: return;
144: }
145:
146: EditorInputData[] editorInputs = (EditorInputData[]) data;
147: /**
148: * The editor input serialization format is:
149: * (int) number of editor inputs
150: * Then, the following for each editor input:
151: * (String) editorId
152: * (String) factoryId
153: * (String) data used to recreate the IEditorInput
154: */
155:
156: int editorInputCount = editorInputs.length;
157:
158: try {
159: ByteArrayOutputStream out = new ByteArrayOutputStream();
160: DataOutputStream dataOut = new DataOutputStream(out);
161:
162: //write the number of resources
163: dataOut.writeInt(editorInputCount);
164:
165: //write each resource
166: for (int i = 0; i < editorInputs.length; i++) {
167: writeEditorInput(dataOut, editorInputs[i]);
168: }
169:
170: //cleanup
171: dataOut.close();
172: out.close();
173: byte[] bytes = out.toByteArray();
174: super .javaToNative(bytes, transferData);
175: } catch (IOException e) {
176: }
177: }
178:
179: /* (non-Javadoc)
180: * Method declared on Transfer.
181: */
182: public Object nativeToJava(TransferData transferData) {
183:
184: byte[] bytes = (byte[]) super .nativeToJava(transferData);
185: if (bytes == null) {
186: return null;
187: }
188: DataInputStream in = new DataInputStream(
189: new ByteArrayInputStream(bytes));
190: try {
191: int count = in.readInt();
192: EditorInputData[] results = new EditorInputData[count];
193: for (int i = 0; i < count; i++) {
194: results[i] = readEditorInput(in);
195: }
196: return results;
197: } catch (IOException e) {
198: return null;
199: } catch (WorkbenchException e) {
200: return null;
201: }
202:
203: }
204:
205: /**
206: * Method readEditorInput.
207: * @param in
208: * @return EditorInputData
209: */
210: private EditorInputData readEditorInput(DataInputStream dataIn)
211: throws IOException, WorkbenchException {
212:
213: String editorId = dataIn.readUTF();
214: String factoryId = dataIn.readUTF();
215: String xmlString = dataIn.readUTF();
216:
217: if (xmlString == null || xmlString.length() == 0) {
218: return null;
219: }
220:
221: StringReader reader = new StringReader(xmlString);
222:
223: // Restore the editor input
224: XMLMemento memento = XMLMemento.createReadRoot(reader);
225:
226: IElementFactory factory = PlatformUI.getWorkbench()
227: .getElementFactory(factoryId);
228:
229: if (factory != null) {
230: IAdaptable adaptable = factory.createElement(memento);
231: if (adaptable != null
232: && (adaptable instanceof IEditorInput)) {
233: return new EditorInputData(editorId,
234: (IEditorInput) adaptable);
235: }
236: }
237:
238: return null;
239: }
240:
241: /**
242: * Method writeEditorInput.
243: * @param dataOut
244: * @param editorInputData
245: */
246: private void writeEditorInput(DataOutputStream dataOut,
247: EditorInputData editorInputData) throws IOException {
248: //write the id of the editor
249: dataOut.writeUTF(editorInputData.editorId);
250:
251: //write the information needed to recreate the editor input
252: if (editorInputData.input != null) {
253: // Capture the editor information
254: XMLMemento memento = XMLMemento
255: .createWriteRoot("IEditorInput");//$NON-NLS-1$
256:
257: IPersistableElement element = editorInputData.input
258: .getPersistable();
259: if (element != null) {
260: //get the IEditorInput to save its state
261: element.saveState(memento);
262:
263: //convert memento to String
264: StringWriter writer = new StringWriter();
265: memento.save(writer);
266: writer.close();
267:
268: //write the factor ID and state information
269: dataOut.writeUTF(element.getFactoryId());
270: dataOut.writeUTF(writer.toString());
271: }
272: }
273: }
274:
275: public static EditorInputData createEditorInputData(
276: String editorId, IEditorInput input) {
277: return new EditorInputData(editorId, input);
278: }
279:
280: }
|