Index: org/openide/text/CallbackTransferable.java =================================================================== RCS file: org/openide/text/CallbackTransferable.java diff -N org/openide/text/CallbackTransferable.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ org/openide/text/CallbackTransferable.java 25 Jul 2005 15:24:25 -0000 @@ -0,0 +1,93 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2005 Sun + * Microsystems, Inc. All Rights Reserved. + */ +package org.openide.text; + +import java.awt.Component; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.io.IOException; + +/** + * CallbackTransferable with fake DataFlavor. Drag and drop initiator sometimes needs + * to be notified about a target component, where the drop operation was performed. + * Initiator should implement this abstract class and use the required fake DataFlavor. + * Component that will support drop operation of the CallbackTransferable should call handleTransfer + * method. For details please refer {@link QuietEditorPane}. + * CallbackTransferable can also support delegating on DragSource original Transferable. + * In this case it works as compound Transferable of this fake Transferable and + * the original transferable (e.g. containing the dragged nodes from the explorer). + * + * @author Martin Roskanin + */ +public abstract class CallbackTransferable implements Transferable { + + /** + * Fake DataFlavor used for communication between DragSource and DragTarget. + * This DataFlavor should be used for case where target component is instance + * of JTextComponent. + */ + public static final DataFlavor FAKE_JTEXTCOMPONENT_FLAVOR = + new DataFlavor("text/fake-flavor", "Fake JTextComponent Flavor"); //NOI18N + + private transient Transferable delegator; + + public CallbackTransferable(){ + this(null); + } + + /** + * @param originalTransferable original DragSource Transferable on + * which this transferable will delegate. + */ + public CallbackTransferable(Transferable originalTransferable){ + if (originalTransferable != null){ + this.delegator = originalTransferable; + } else { + // assigning empty StringSelection. Needed for appropriate calling + // of QuietEditorPane.DelegatingTransferHandler.importData() + this.delegator = new StringSelection(""); //NOI18N + } + } + + /** + * A method called from the drop target that support the fake DataFlavor. + * @param targetComponent a Component where drop operation occured. + */ + public abstract boolean handleTransfer(Component targetComponent); + + public final boolean isDataFlavorSupported(DataFlavor flavor) { + if (FAKE_JTEXTCOMPONENT_FLAVOR == flavor) { + return true; + } + return delegator.isDataFlavorSupported(flavor); + } + + public final Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { + if (flavor == FAKE_JTEXTCOMPONENT_FLAVOR) { + return this; + } + return delegator.getTransferData(flavor); + } + + public final DataFlavor[] getTransferDataFlavors() { + DataFlavor delegatorFlavor[] = delegator.getTransferDataFlavors(); + int delegatorFlavorLength = delegatorFlavor.length; + DataFlavor newArray[] = new DataFlavor[delegatorFlavorLength + 1]; + System.arraycopy(delegatorFlavor, 0, newArray, 0, delegatorFlavorLength); + newArray[delegatorFlavorLength] = FAKE_JTEXTCOMPONENT_FLAVOR; + return newArray; + } + +} Index: org/openide/text/QuietEditorPane.java =================================================================== RCS file: /cvs/openide/text/src/org/openide/text/QuietEditorPane.java,v retrieving revision 1.1 diff -u -r1.1 QuietEditorPane.java --- org/openide/text/QuietEditorPane.java 21 Apr 2005 20:16:02 -0000 1.1 +++ org/openide/text/QuietEditorPane.java 25 Jul 2005 15:24:26 -0000 @@ -12,7 +12,16 @@ */ package org.openide.text; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.DropTarget; +import java.awt.event.InputEvent; +import javax.swing.Icon; +import javax.swing.JComponent; import javax.swing.JEditorPane; +import javax.swing.TransferHandler; +import javax.swing.plaf.UIResource; import javax.swing.text.*; @@ -32,7 +41,22 @@ /** is firing of events enabled? */ int working = FIRE; // [Mila] firing since begining, otherwise doesn't work well - + + + public void setDocument(Document doc) { + super.setDocument(doc); + + // Setting DelegatingTransferHandler, where CallbackTransferable will + // be handled in importData method. + // For more details, please refer issue #53439 + if (doc != null){ + TransferHandler thn = getTransferHandler(); + DelegatingTransferHandler dth = new DelegatingTransferHandler(thn); + setTransferHandler(dth); + } + } + + public void setWorking(int x) { working = x; } @@ -88,4 +112,86 @@ super.repaint(); } } + + /** + * Delegating TransferHandler. + * The main purpose is hooking on importData method where CallbackTransferable + * is handled. For more details, please refer issue #53439 + */ + private class DelegatingTransferHandler extends TransferHandler{ + + TransferHandler delegator; + + public DelegatingTransferHandler(TransferHandler delegator){ + this.delegator = delegator; + } + + public void exportAsDrag(JComponent comp, InputEvent e, int action) { + delegator.exportAsDrag(comp, e, action); + } + + public void exportToClipboard(JComponent comp, Clipboard clip, int action) { + delegator.exportToClipboard(comp, clip, action); + } + + public boolean importData(JComponent comp, Transferable t) { + try { + if (t.isDataFlavorSupported(CallbackTransferable.FAKE_JTEXTCOMPONENT_FLAVOR)){ + Object obj = t.getTransferData(CallbackTransferable.FAKE_JTEXTCOMPONENT_FLAVOR); + if (obj instanceof CallbackTransferable){ + return ((CallbackTransferable)obj).handleTransfer(comp); + } + } + } catch (Exception exc){ + exc.printStackTrace(); + } + return delegator.importData(comp, t); + } + + public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) { + return delegator.canImport(comp, transferFlavors); + } + + public int getSourceActions(JComponent c) { + return delegator.getSourceActions(c); + } + + public Icon getVisualRepresentation(Transferable t) { + return delegator.getVisualRepresentation(t); + } + + protected void exportDone(JComponent source, Transferable data, int action) { + try { + java.lang.reflect.Method method = delegator.getClass().getDeclaredMethod( + "exportDone", // NOI18N + new Class[] {javax.swing.JComponent.class, Transferable.class, int.class}); + method.setAccessible(true); + method.invoke(delegator, new Object[] {source, data, new Integer(action)}); + } catch (NoSuchMethodException ex) { + ex.printStackTrace(); + } catch (IllegalAccessException ex) { + ex.printStackTrace(); + } catch (java.lang.reflect.InvocationTargetException ex) { + ex.printStackTrace(); + } + } + + protected Transferable createTransferable(JComponent comp) { + try { + java.lang.reflect.Method method = delegator.getClass().getDeclaredMethod( + "createTransferable", // NOI18N + new Class[] {javax.swing.JComponent.class}); + method.setAccessible(true); + return (Transferable)method.invoke(delegator, new Object[] {comp}); + } catch (NoSuchMethodException ex) { + ex.printStackTrace(); + } catch (IllegalAccessException ex) { + ex.printStackTrace(); + } catch (java.lang.reflect.InvocationTargetException ex) { + ex.printStackTrace(); + } + return null; + } + } + } Index: arch-openide-editor.xml =================================================================== RCS file: /cvs/openide/arch/arch-openide-editor.xml,v retrieving revision 1.22 diff -c -r1.22 arch-openide-editor.xml *** arch-openide-editor.xml 1 Jun 2005 12:57:14 -0000 1.22 --- arch-openide-editor.xml 20 Jul 2005 08:25:26 -0000 *************** *** 422,427 **** --- 422,432 ---- Yes, it calls protected method MultiDataObject.getCookieSet(). The class which calls this is deprecated, but it is still in use by clients. +

+ Another reflection is used in QuietEditorPane, where DelegatingTransferHandler delegates + also on two protected methods of TransferHandler: createTransferable and + exportDone. This delegation is needed because of drag and drop feature described + in issue #53439