このドキュメントには次の節があります。
この仕様では、Java 2 プラットフォームのドラッグ&ドロップ機能の API を定義します。
この仕様で規定する主な要件は、次のとおりです。
java.awt.datatransfer.*
パッケージを活用して、MIME 標準ベースの拡張可能なデータ型システムに記述されている、データの転送を使用可能にする
この仕様は、上で言及した以前の研究から派生していますが、JavaBeansTM イベントモデルや軽量 (Swing) コンポーネントが出現し、クロスプラットフォームの統合と相互運用性の問題の理解が深まってきた結果、元の研究とはかなり異なった仕様が組み入れられています。
以降の節では、ドラッグ&ドロップ API について説明します。
ドラッグ&ドロップは、多くのグラフィカルユーザインタフェース (GUI) システムにみられる直接的な操作のジェスチャーで、GUI 内の表現要素に論理的に関連付けられた 2 つの構成要素間で情報を転送するための機構を提供します。通常、ドラッグ&ドロップは、ユーザが適切な入力デバイスを使用して行う物理的なジェスチャーによって生じます。ドラッグ&ドロップは、GUI の表現要素上でデータ転送の結果がわかるように、ナビゲーション中に、ユーザに継続的にフィードバックする機構と、続いて行われるデータのネゴシエーションおよび転送を容易にする機能を提供します。
一般的なドラッグ&ドロップ操作は、次のようにいくつかの状態に分けることができます (この順番どおり行われるわけではない)。
Transferable
(転送可能になりうる) データのドラッグ&ドロップを開始するために、GUI の表現要素 (Component
) に関連付けられた DragSource
(ドラッグソース) が作成される
Component
) に関連付けられ、Transferable
データ型を消費する可能性のある 1 つ以上の DropTarget
(ドロップターゲット) が作成または削除される
Component
に対してユーザが開始したドラッグジェスチャーの追跡および識別を行うために、DragGestureRecognizer
が DragSource
から取得され、Component
に関連付けられる
Component
に対してドラッグジェスチャーを行う。登録された DragGestureRecognizer
がそれを検出し、DragGestureListener
に通知する
注: このドキュメントでは、ドラッグ&ドロップ操作の開始要因が、ユーザによる物理的なジェスチャーであることを繰り返し言及していますが、これには、DragSource
が適切に実装されている場合の、プログラムによるドラッグ&ドロップ操作も含まれています。
DragGestureListener
からの指示によって、GUI Cursor
(カーソル) をアニメーション化したり、操作の対象となるアイテムの Image
(画像) を描画するなどして、DragSource
がユーザに代わってドラッグ&ドロップ操作を開始する
DropTarget
を持つ GUI の Component
を通過するとき、DragSource
は、通知を受けて Drag Over フィードバック効果を提供し、DropTarget
は、通知を受けてサポートされる操作および関係するデータ型に基づいて Drag Under フィードバック効果を提供する
ジェスチャー自体は、論理カーソルを GUI 階層を越えて動かし、GUI Component
のジオメトリと交差します。この結果、論理 Drag カーソルは Component
および関連する DropTarget
内に入り、それらを横切ってから出て行きます。
DragSource
オブジェクトは、通常の場合は、論理カーソルに関連付けられた GUI Cursor
をアニメーション化することによって、ユーザに「Drag Over」フィードバックを明示します。
DropTarget
オブジェクトは、通常の場合は、GUI Cursor
の下にある関連付けられた GUI Component
にアニメーションを描画することによって、ユーザに Drag Under フィードバックを明示します。
フィードバック効果の決定、およびデータ転送が行われる場合はその操作が最終的に成功したかどうかが、次のようにパラメータ化される:
DragSource
および DropTarget
でサポートされる転送の「操作」(コピー、移動または参照 (リンク)) による
DragSource
によって提供されるデータ型のセットと DropTarget
で認識できるデータ型セットとの共通部分による
DragSource
と DropTarget
の両方に、Transferable
オブジェクトを介して DragSource
に関連付けられた情報を含む通知が渡され、型ネゴシエーションおよび結果情報の転送が行われる
このドキュメントの以降の部分では、このモデルをサポートするために提案された API の変更の詳細について説明します。
ドラッグ&ドロップ操作を開始できるジェスチャーは、プラットフォーム、Component
、およびデバイスごとに異なります。このため、操作の依存性をカプセル化するための機構が必要です。この機構があれば、ドラッグ&ドロップ操作を開始するコンポーネントの作成が簡単になります。
DragGestureRecognizer
は、すべてのデバイス、プラットフォーム、および Component
固有のドラッグ&ドロップジェスチャーレコグナイザ用の抽象基底クラスで、次のように定義されています。
public abstract DragGestureRecognizer { protected DragGestureRecognizer( DragSource ds, Component c, int srcActions, DragGestureListener dgl ); public Component getComponent(); public void setComponent(Component c); public int getSourceActions(); public void setSourceActions(int actions); public java.awt.InputEvent getTriggerEvent(); public void resetRecognizer(); public void addDragGestureListener( DragGestureListener dgl ) throws TooManyListenerExceptions; public void removeDragGestureListener( DragGestureListener dgl ); protected abstract void registerListeners(); protected abstract void unregisterListeners(); protected void fireDragGestureRecognized( int dragAction ); protected void appendEvent(InputEvent awtie); }
DragGestureRecognizer
に適した特定の具象サブクラスは、DragSource
インスタンス、Toolkit
など、さまざまな方法で取得できます。具象実装サブクラスは、Class
参照を抽象 DragGestureRecognizer
スーパークラスに指定することによって、標準 API から取得できます。この実パラメータの具象サブクラスは、インスタンス化されて要求元に返されます。
DragGestureRecognizer
インスタンスが Component
および DragSource
に関連付けられると、そのインスタンスの特定の EventListener
セットがターゲット Component
とともに登録されて、その Component
に提供されたイベントのいくつかが監視され、開始ジェスチャーが検出されます。registerListeners
および unregisterListeners
を使用して、これらの監視 EventListener
の追加および削除を行うことができます。
指定された Component
または DragSource
が、その DragGestureRecognizer
に対して正しい状態にないか、その DragGestureRecognizer
と相互運用性がない場合は、DragGestureRecognizer
によって、IllegalStateException
または IllegalArgumentException
がスローされる可能性があります。
DragGestureRecognizer
の具象インスタンスによって、関連する Component
上でドラッグを開始するユーザジェスチャーが検出されたときは、DragGestureListener
イベントのユニキャストイベントソース上に登録されている DragGestureListener
に対して DragGestureEvent
が発生します。この DragGestureListener
によって、関連する DragSource
に対するドラッグ&ドロップ操作の開始が指示されます (適切な場合)。
実装は、マウスデバイスジェスチャーを認識するために (少なくとも) 抽象サブクラス MouseDragGestureRecognizer
を提供します。その他の入力デバイスまたは特定の Component クラスのセマンティクスをサポートするために、その他の抽象サブクラスがプラットフォームから提供されることもあります。この MouseDragGestureRecognizer
の具象スーパークラスでは、プラットフォームに依存するマウスベースのジェスチャーがカプセル化されます。この具象スーパークラスは、Toolkit
オブジェクトの createDragGestureRecognizer (Class adgrc、DragSource ds、Component c、int sa、DragGestureListener dgl)
メソッドを介して取得できます。この Toolkit
の API から、プラットフォームに依存する具象実装が提供されます。この実装には、プラットフォームに依存しない特定の抽象定義 (クラス) が継承されています。
MouseDragGestureRecognizer
抽象クラスは、次のように定義されています。
public abstract MouseDragGestureRecognizer extends DragGestureRecognizer implements MouseListener, MouseMotionListener { public MouseDragGestureRecognizer( DragSource ds, Component c, int sa, DragGestureListener dsl ); //... }
DragGestureListener
は、次のように定義されています。
public interface DragGestureListener extends EventListener { void dragGestureRecognized(DragGestureEvent dge); }
通常、dragGestureRecognized()
メソッドは単に、DragGestureEvent
の簡易 API startDrag
を使って、関連する DragSource
上でドラッグ&ドロップ操作を開始します。
開始ジェスチャーに影響する各 Component
(クラスまたはインスタンス) の動作は、通常、この DragGestureListener
メソッドに実装されるか、適切または可能な場合は DragGestureRecognizer
サブクラスに実装されます。
DragGestureEvent
は、次のように定義されています。
publc class DragGestureEvent extends EventObject { public DragGestureEvent(DragGestureRecognizer dgr, int dragAction, java.util.List events ); public DragGestureRecognizer getSourceAsDragGestureRecognizer(); public Component getComponent(); public DragSource getDragSource(); public java.util.Iterator iterator(); public Object[] toArray(); public Object[] toArray(Object[] array); public int getDragAction(); public startDrag(Cursor dragCursor, Transferable t, DragSourceListener dsl ); public startDrag(Cursor dragCursor, Image dragImage, Point imageOffset, Transferable t, DragSourceListener dsl ); //... }
DragGestureEvent
によって、直前に認識されたジェスチャーの特性に関する情報がすべてカプセル化されます。次の情報がカプセル化されます。
DragGestureRecognizer
Component
DragSource
InputEvent
オブジェクトのリスト
DragSource
(ドラッグ元) は、ドラッグ&ドロップ操作を開始する構成要素です。
DragSource
および関連付けられた定数のインタフェースは、次のように定義されています。
DnDConstants
クラスは、転送対象に適用される可能性のある操作を定義しています。
public final class java.awt.dnd.DnDConstants { public static int ACTION_NONE = 0x0; public static int ACTION_COPY = 0x1; public static int ACTION_MOVE = 0x2; public static int ACTION_COPY_OR_MOVE= ACTION_COPY | ACTION_MOVE; public static int ACTION_REFERENCE = 0x40000000; } public class java.awt.dnd.DragSource { public static Cursor DefaultCopyDrop; public static Cursor DefaultMoveDrop; public static Cursor DefaultLinkDrop; public static Cursor DefaultCopyNoDrop; public static Cursor DefaultMoveNoDrop; public static Cursor DefaultLinkNoDrop; public static DragSource getDefaultDragSource(); public static boolean isDragImageSupported(); public void startDrag(DragGestureEvent trigger, Cursor dragCursor, Image dragImage, Point dragImageOffset, Transferable transferable, DragSourceListener dsl, FlavorMap fm) throws InvalidDnDOperationException; protected DragSourceContext createDragSourceContext( DragSourceContextPeer dscp, DragGestureEvent trigger, Cursor dragCursor, Image dragImage, Point dragImageOffset, Transferable transferable, DragSourceListener dsl ); public FlavorMap getFlavorMap(); public DragGestureRecongizer createDragGestureRecognizer( Class abstractRecognizerClass, Component c, int srcActions, DragGestureListener dgl ); public DragGestureRecongizer createDefaultDragGestureRecognizer( Component c, int srcActions, DragGestureListener dgl ); //... }
DragSource
は、数多くの状況で使用される可能性があります。
TextField
等の、ドラッグイニシエータオブジェクトになり得るクラスにつき 1 つのインスタンス(実装に依存)
Component
のインスタンスにつき 1 つ。または、GUI の Component
のインスタンスに関連付けられたアプリケーション固有のオブジェクトにつき 1 つ(実装に依存)
制御オブジェクトは、ドラッグ操作を処理するために、ユーザのジェスチャーの前に DragSource
のインスタンスを取得して、関連する Component
を有効にします。インスタンスを取得したら、DragGestureRecognizer
を取得して、DragSource
を Component
に関連付ける必要があります。
ユーザのジェスチャーの最初の解釈、およびそれに続くドラッグ操作の開始は、Component
の実装によって行われます。通常これは、DragGestureRecognizer
によって実装されます。
ジェスチャーが発生すると、ユーザによる操作ジェスチャーを処理し、ドラッグ&ドロッププロトコルの通知を配布するために、DragSource
の startDrag
メソッドが呼び出されます。DragSource
では、どの時点でも複数のドラッグ&ドロップ操作をカレントにすることはできません。現在の操作が完了するまでは、startDrag
要求を追加しようとすると、IllegalDnDOperationException
がスローされて拒否されます。
ドラッグ操作を開始するために、startDrag
メソッドの呼び出し元は、次のパラメータを提供します。
DragGestureEvent
Cursor
(ユーザに対して No Drop の視覚的なフィードバックを提供する Cursor
)
Image
(省略可能)
この機能をサポート可能なプラットフォーム上では、ドラッグイメージを操作に関連付けて、より忠実に Drag Over をフィードバックできます。このイメージは、通常は、ドラッグされる 1 つまたは複数のオブジェクトの小さな「アイコン」の表示で、背後のシステムは、Cursor アニメーションの動きを追跡しながらこのイメージを読み込みます。イメージは、Cursor アニメーションと同時に動きますが、通常は、Cursor
アニメーションとは別のものです。
この機能が利用できない箇所、または背後のシステムが描画するのに適切でない種類のイメージの場合、このパラメータは無視され、結果的に Cursor
の「Drag Over」アニメーションだけになるので、アプリケーションは、この機能に依存しません。特定のプラットフォーム上にこの機能が存在するかどうかは、static メソッド isDragImageSupported
を呼び出すことによってテストできます。
Image
が渡された場合には Point
(Component
の座標空間内) は、ドラッグ「Cursor」の「ホットスポット」の座標に対する相対位置で Image
の起点が指定される。Component
の座標空間内において、最初のジェスチャーの時点で、その「ホットスポット」に対する相対位置に、Image
の「Drag Over」アニメーションを適切に配置して開始するためにある
DataFlavor
(データの型) を記述した、Transferable
のインスタンス
Transferable
のインスタンスは、ドラッグ操作の開始時に DragSource
に関連付けられ、ドラッグ&ドロップのオペランドまたは対象である、オブジェクトまたはデータを表しています。これは、ドラッグ操作のあと、DropTarget
に関連付けられた Component
上でドロップが成功した結果として、DragSource
から DropTarget
に渡される情報です。
コンテナオブジェクトを作成し、転送の対象にして Transferable
を実装することによって、同じ種類または異なる種類のオブジェクトの複数コレクションをドラッグ&ドロップ操作の対象にすることも可能です。ただし、ターゲットとなるどのネイティブプラットフォームシステムでも、このようなコレクションを記述および転送する機構は標準ではサポートされていません。そのため、透過的かつプラットフォーム移植性の高い方法では、このような転送を実装することはできません。
DragSourceListener
のインスタンス
前述したように、startDrag
メソッドの主な役割は、ユーザのためにドラッグを開始することです。このためには、startDrag
メソッドは、操作そのものを追跡するための DragSourceContext
のインスタンスを作成する必要があります。さらに重要なことは、このメソッドは、基本的なプラットフォーム実装内で、操作をそのものを開始しなければならないことです。これを行うために、DragSource
は、まず基本的なシステムから (通常は java.awt.Toolkit.createDragSourceContextPeer
メソッドの呼び出しにより) DragSourceContextPeer
を取得してから、新しく作成された DragSourceContextPeer
(基本的なシステムの機能に対してプラットフォームに依存しないインタフェースを提供する) を DragSourceContext
に関連付ける必要があります。startDrag
メソッドは、createDragSourceContext
メソッドを呼び出して、適切な DragSourceContext
のインスタンスを生成し、DragSourceContextPeer
を関連付けます。
ドラッグ&ドロップシステムが、何らかの理由でドラッグ操作を開始できない場合は、startDrag
メソッドは、java.awt.dnd.InvalidDnDOperationException
をスローしてその状態を示します。一般的に、この例外は、基本的なプラットフォームシステムがドラッグを開始する状態にない場合か、または指定されたパラメータが無効な場合にスローされます。
ドラッグ操作中には、ソースがドラッグ操作の開始時に公開した操作のセットは、変更できないことに注意してください。つまり、ドラッグ操作中は、DragSource
に関する操作が一定である必要があります。
getFlavorMap
メソッドは、Transferable
によって公開された DataFlavors
を、基盤のドラッグ&ドロッププラットフォームのデータ型名にマップするために、基本的なシステムによる FlavorMap
オブジェクトの取得に使われます (FlavorMap
の詳細は、以降を参照)。
「private」 FlavorMap
は、DragSource
の startDrag()
メソッドに渡すことができます。null も渡すことができますが、この場合は、DragSource
クラスまたはインスタンスの「デフォルト」の FlavorMap
が使用されます。
DragSource
の startDrag
メソッドが正常に呼び出された結果、DragSourceContext
クラスのインスタンスが作成されます。このインスタンスは、DragSource
のために操作の状態を追跡し、状態の変化を DragSourceListener
に通知する役割を果たします。
DragSourceContext
クラスは、次のように定義されています。
public class DragSourceContext implements DragSourceListener { public DragSourceContext( DragSourceContextPeer dscp, DragGestureEvent trigger, Cursor dragCursor, Image dragImage, Point dragOffset, Transferable transferable, DragSourceListener dsl ); public DragSource getDragSource(); public Component getComponent(); public DragGestureEvent getTrigger(); public Image getDragImage(); public Point getDragImageOffset(); public void transferablesFlavorsChanged(); public int getSourceActions(); public Cursor getCursor(); pbulic void setCursor(Cursor Cursor) throws InvalidDnDOperationException; public void addDragSourceListener(DragSourceListener dsl) throws TooManyListenersException; public void removeDragSourceListener(DragSourceListener dsl); protected updateCurrentCursor(int dropOperation, int targetActions, int status ); // values for status parameter above. protected static final int DEFAULT = 0; protected static final int ENTER = 1; protected static final int OVER = 2; protected static final int CHANGED = 3; //... }
DragSourceContext
自体が DragSourceListener
を実装することに注目してください。これにより、DragSource
によって作成されたプラットフォームのピアである DragSourceContextPeer
のインスタンスは、DragSourceContext
に進行中の操作状態の変化について通知できるようになります。したがって DragSourceContext
は、プラットフォームと、操作のイニシエータによって提供された DragSourceListener
の間に割り込むことができるようになります。
転送元、またはドラッグ&ドロップ操作のイニシエータに関してプラットフォームが公開する状態の変化の詳細は、次のとおりです。
ドラッグ&ドロップ操作中のイニシエータに関する状態の変化の通知は、上に示したように、DragSourceContextPeer
から適切な DragSourceContext
に配布されます。DragSourceContext
は通知を、ユニキャスト JavaBeans に準拠した EventListener
サブインタフェースを介して、startDrag
で DragSource
に登録された DragSourceListener
を実装する任意のオブジェクトに委譲します。
DragSourceListener
の主な役目は、ドラッグ&ドロップ操作中にユーザ操作の進行を監視して、Drag-Over 効果をユーザにフィードバックすることです。一般的に、フィードバックは、Drag Cursor を変更することで行われます。
各ドラッグ操作には、次の 2 種類の論理カーソル (ドラッグカーソル) の状態が関連付けられています。
Cursor
。有効な DropTarget
上にドラッグしているときに表示されるカーソル
Cursor
。それ以外の物の上にドラッグしているときに表示されるカーソル (ドラッグ開始時のカーソルの初期状態)
Cursor
の状態は、DragSourceContext
の setCursor
メソッドを呼び出すことによって変更できます。
DragSourceListener
インタフェースは、次のように定義されます。
public interface java.awt.dnd.DragSourceListener extends java.util.EventListener { void dragEnter (DragSourceDragEvent dsde); void dragOver (DragSourceDragEvent dsde); void dropActionChanged (DragSourceDragEvent dsde); void dragExit (DragSourceEvent dse); void dragDropEnd (DragSourceDropEvent dsde); }
ドラッグ操作が進行するに従って、DragSourceListener
の dragEnter
、dragOver
、および dragExit
メソッドが呼び出されます。これは、DropTarget
が関連付けられている GUI Component
のジオメトリに交差するように、論理 「Drag」 カーソルの位置をユーザがナビゲートした結果です (DropTarget
のプロトコルの相互作用に関する詳細は次を参照)。
DragSourceListener
の dragEnter
メソッドは、次の条件が満たされたときに呼び出されます。
Component
の可視ジオメトリに最初に交わった
Component
に、アクティブな DropTarget
が関連付けられている
DropTarget
に登録された DropTargetListener
の dragEnter
メソッドが呼び出され、正常に処理を返します。
登録された DropTargetListener
が、DropTargetDragEvent
の acceptDrag
メソッドを呼び出して、転送元が実行する可能性のあるドロップ動作、および利用可能なデータ型 (DataFlavors
) を調べた上で、ドラッグを受け入れます。
DragSourceListener
の dragOver
メソッドは、次の条件が満たされたときに呼び出されます。
DragSourceListener
の dragExit
メソッドは、次の条件のうちの 1 つが満たされたときに呼び出されます。
dragEnter
の呼び出しに関連付けられた Component
の可視ジオメトリと、もはや交差していない
または
Component
(これが直前の dragEnter
の呼び出しにつながった) に、アクティブな DropTarget
(または DropTargetListener
) が関連付けられていない
または
dragEnter
または dragOver
が最後に呼び出されてから、現在の DropTarget
の DropTargetListener
が rejectDrag
を呼び出した
DragSourceListener
の dropActionChanged()
メソッドは、ドラッグ操作を実行するためにユーザが使用している、マウスボタンやキーボードのキーなどの入力デバイスの状態が変わったときに呼び出されます。
dragDropEnd()
メソッドは、操作が完了したことを示すために呼び出されます。DragSourceDropEvent
の getDropSuccess
メソッドは、終了状態を確認するために使用されます。getDropAction
メソッドは、DropTarget
が DropTargetDropEvent
の acceptDrop
パラメータを介してドロップ操作に適用するために選択した操作を返します。
このメソッドが完了すると、現在の DragSourceContext
および関連付けられたリソースが無効になります。
DragSourceEvent
クラスは、DragSource
に属するすべてのイベントのルート Event
クラスで、次のように定義されています。
public class java.awt.dnd.DragSourceEvent extends java.util.EventObject { public DragSourceEvent(DragSourceContext dsc); public DragSourceContext getDragSourceContext(); //... };
このイベントのインスタンスは、DragSourceListener
の dragExit
メソッドに渡されます。
DragSourceDragEvent
クラスは、次のように定義されています。
public class java.awt.dnd.DragSourceDragEvent extends DragSourceEvent { public int getTargetActions(); public int getUserAction(); public int getGestureModifiers(); public int getGestureModifiersEx(); public int getDropAction(); }
このクラスのインスタンスは、DragSourceListener
の dragEnter
、dragOver
、および dragGestureChanged
の各メソッドに渡されます。
getDragSourceContext
メソッドは、現在のドラッグ&ドロップ操作に関連付けられた DragSourceContext
を返します。
getUserAction
メソッドは、ユーザジェスチャーによって現在選択されているアクションを返します。
The getTargetActions
メソッドは、ドロップアクションがドラッグソースによってサポートされている場合には、現在のドロップターゲットにより選択されているドロップアクションを返し、ドロップアクションがドラッグソースによりサポートされていない場合には DnDConstants.ACTION_NONE
を返します。
これら 2 つの結果とドラッグソースによりサポートされる一連のドロップアクションの論理的な相互作用が、ドロップによる実際の効果を定義し、getDropAction
を介して返されます。
getGestureModifiers
メソッドは、入力デバイスの修飾子の現在の状態を返します。通常、入力デバイスの修飾子は、ユーザのジェスチャーに関連付けられたマウスボタンおよびキーボードのキーです。
getGestureModifiersEx
メソッドは、ユーザのジェスチャーに関連付けられた入力デバイスの拡張修飾子の現在の状態を返します。
DragSourceDropEvent
クラスは、次のように定義されています。
public public class java.awt.dnd.DragSourceDropEvent extends java.util.EventObject { public DragSourceDropEvent(DragSourceContext dsc); public DragSourceDropEvent(DragSourceContext dsc, int action, boolean success); public boolean getDropSuccess(); public int getDropAction(); }
このクラスのインスタンスは、DragSourceListener
の dragDropEnd
メソッドに渡されます。このイベントはドラッグ&ドロップ操作の終了状態を DragSource
のためにカプセル化します。
ドロップが発生して、ドロップに関係した DropTarget
が DropTargetContext
の dropComplete
メソッドを介してデータ転送の成功または失敗を示し、イニシエータは getDropSuccess
メソッドを介してこの状態を取得できます。ドロップ先である DropTarget
がドラッグの対象に対して実行する操作は、(DropTarget
の acceptDrop
メソッドにより渡された) getDropAction
メソッドを介して返されます。
ユーザが DropTarget
の外部でジェスチャーを終了するか、DropTarget
が rejectDrop
を呼び出した場合など、何らかの理由でドロップが発生する前にドラッグ操作が中止された場合は、getDropSuccess
メソッドは false を返します。そうでない場合は true を返します。
java.awt.Component
クラスには、DropTarget
との関連付けおよび関連付け解除を可能にするために、2 つのメソッドが追加されました。特に次の点が重要です。
public class java.awt.Component /* ... */ { //... public synchronized void setDropTarget(DropTarget dt); public synchronized DropTarget getDropTarget(DropTarget df); //... }
DropTarget
を Component
に関連付けるには、DropTarget.setCompononent
または Component.setDropTarget
のどちらのメソッドを呼び出すこともできます。このため、相互再帰呼び出しを防ぐために、両方のメソッドの実装に準拠する必要があります。
DropTarget
と Component
の関連付けを解除するには、DropTarget.setCompononent(null)
または Component.setDropTarget(null)
のどちらのメソッドを呼び出すこともできます。
DropTarget
と Component
の両方の設定メソッドの仕様に準拠する実装は、互いの状況を適切に管理するように実装する必要があります。
DropTarget
の実パラメータが Component
の、このクラスまたはインスタンスとともに使うことが不適切な場合は、setDropTarget
メソッドは、IllegalArgumentException
をスローします。また、Component
が DropTarget
の外部設定をサポートしていない場合などには、このメソッドは UnsupportedOperationException
をスローします。
DropTarget
は、操作の受け側または送り先の役割に関連する、ドラッグ&ドロッププロトコルのプラットフォーム固有の処理をすべてカプセル化します。
一般に、単一の DropTarget
インスタンスを、java.awt.Component
の任意のインスタンスに関連付けることができます。このような関係を確立すると、関連付けられた Component
の可視ジオメトリに論理カーソルの座標が交差したときに、ドラッグ&ドロップ操作の受け取りが可能であるとして、このジオメトリがクライアントのデスクトップにエクスポートされます。
DropTarget
クラスは、次のように定義されています。
public class java.awt.dnd.DropTarget implements DropTargetListener, Serializable { public DropTarget(Component c, int actions, DropTargetListener dsl, boolean isActive, FlavorMap fm ); public DropTarget(); public DropTarget(Component c); public DropTarget(Component c, DropTargetListener dsl); public Component getComponent(); public void setComponent(Component c); public DropTargetContext getDropTargetContext(); public void addDropTargetListener(DropTargetListener dte) throws TooManyListenersException; public void removeDropTargetListener(DropTargetListener dte); public void setActive(boolean active); public boolean isActive(); public FlavorMap getFlavorMap(); public void setFlavorMap(FlavorMap fm); public void setDefaultActions(int actions); public int getDefaultActions(); protected DropTargetContext createDropTargetContext(); public void addNotify(ComponentPeer cp); public void removeNotify(ComponentPeer cp); // ... }
Component
の実パラメータが DropTarget
の、このクラスまたはインスタンスとともに使うことが不適切な場合は、setComponent
メソッドは、IllegalArgumentException
をスローします。また、このメソッドは、Component
で、DropTarget
の外部設定を許可しないように指定されてる場合には、UnsupportedOperationException
をスローします。
addDropTargetListener
および removeDropTargetListener
メソッドを使って、ユニキャスト DropTargetListener
を変更できます。
setActive
および isActive
メソッドを使って、DropTarget
をアクティブまたは非アクティブにすることができ、さらに DropTarget
の現在の状態を知ることができます。
getFlavorMap
メソッドは、プラットフォームに依存した型名と、それに対応するプラットフォームに依存しない DataFlavors
との間のマッピングを行う目的で、この DropTarget
に関連付けられた FlavorMap
を取得するために使います。
setFlavorMap
メソッドは、新しい FlavorMap
を DropTarget
に割り当てます。パラメータに null が指定された場合は、「デフォルト」の FlavorMap
を DropTarget
にインストールします。
createDropTargetContext
メソッドは、ドラッグ操作で最初に DropTarget
に関連付けられた Component
を検出したときに、背後のプラットフォームに依存したピアに、新しい DropTargetContext
のインスタンスを提供するためだけに呼び出されます。現在 DropTarget
に関連付けられている DropTargetContext
がない場合は、getDropTargetContext
の呼び出しに許可されている副作用によって、新しい DropTargetContext
のインスタンスが生成されます。
addNotify
および removeNotify
メソッドは、Component
の ComponentPeer
への関連付け (および関連付けの解除) を DropTarget
に通知するためだけに、Component
から呼び出されます。
DropTarget
自体が DropTargetListener
を実装することに注目してください。これにより、プラットフォームによって作成されたプラットフォームのピアである DropTargetContextPeer
のインスタンスは、DropTarget
に進行中の操作状態の変化について通知できるようになり、したがって DropTarget
は、プラットフォームと DropTarget
に登録されている DropTargetListener
の間に割り込むことができるようになります。
進行中のドラッグ&ドロップ操作に関連付けられた論理カーソルが、DropTarget
に関連付けられた Component
の可視ジオメトリと最初に交差すると、DropTarget
に関連付けられた DropTargetContext
がインタフェースになります。このインタフェースを介して、DropTargetListener
から受け側のプロトコルの状態を制御したりアクセスしたりできます。
DropTarget
の DropTargetContext
が存在しない場合は、DropTarget
の getDropTargetContext
メソッドが呼び出されたときに、副作用として DropTarget
の createDropTargetContext
メソッドによって DropTargetContext
が作成されます。
DropTargetContext
インタフェースは、次のように定義されます。
public class DropTargetContext { public DropTarget getDropTarget(); public Component getComponent(); public void dropComplete(boolean success) throws InvalidDnDOperationException; public void acceptDrag(int dropAction); public void rejectDrag(); public void acceptDrop(int dropAction); public void rejectDrop(); public void addNotify(DropTargetContextPeer dtcp); public void removeNotify(); protected Transferable createTransferableProxy(Transferable t, boolean isLocal ); protected void setTargetActions(int actions); protected int getTargetActions(); protected DataFlavor[] getCurrentDataFlavors(); protected List getCurrentDataFlavorsAsList(); protected boolean isDataFlavorSupported(DataFlavor df); protected Transferable getTransferable(); // ... }
アクセスおよび制御を行うメソッドは、ほとんどが protected メソッドです。これらのメソッドの状態に public アクセスするときは、通常、要求を DropTargetContext
に委譲する特定の DropTargetEvent
サブクラスの呼び出しにより行います。
getDropTarget()
メソッドは、この DropTargetContext
を作成した DropTarget
を返します。
getComponent
メソッドは、この DropTargetContext
を作成した DropTarget
に関連付けられた Component
を返します。
acceptDrag
メソッドは、DropTargetDragEvent
の類似のメソッドから委譲されていて、DropTargetListener
のメソッド dragEnter()
、dragOver
、または dropActionChanged
から呼び出されます。acceptDrag
の呼び出しは、受け側では指定された操作を含むドロップの受け取りの準備ができていることを意味します。通常は、現在ユーザが選択しているアクションが操作として指定されます。
rejectDrag
メソッドは、DropTargetDragEvent
の類似のメソッドから委譲されていて、DropTargetListener
のメソッド dragEnter
、dragOver
、または dropActionChanged
から呼び出されます。rejectDrag
の呼び出しは、現在ユーザが選択しているアクションを受け取れないことを意味します。
acceptDrop
メソッドは、DropTargetDropEvent
の類似のメソッドから委譲されていて、DropTargetListener
の drop
メソッドから呼び出されます。acceptDrop
の呼び出しは、受け側では指定された操作を含むドロップの受け取りの準備ができていることを意味します。通常は、現在ユーザが選択しているアクションが操作として指定されます。
rejectDrop
メソッドは、DropTargetDropEvent
の類似のメソッドから委譲されていて、DropTargetListener
の drop
メソッドから呼び出されます。rejectDrop
の呼び出しは、受け側では現在ユーザが選択しているアクションを含むドロップの受け取りが不可能であることを意味します。このメソッドにより、ドラッグ&ドロップ操作が終了し、データは転送されません。
dropComplete
メソッドは、DropTargetListener
がドラッグ&ドロップ操作の対象を含む転送を完了したこと、および操作が完了したことを、転送元の DragSource
に通知します。転送の成功 (または失敗) および指定された操作のそれ以降の適用が、実際のパラメータの値によって通知されます。
getDataFlavors
メソッドは、DragSource
で利用できる DataFlavors
の配列を返します。
getTransferable
メソッドは、Transferable
を返し、getTransferData
メソッドを介したデータ転送を可能にします。返される Transferable
は、必ずしも DragSource
が登録したものではなく、プロキシの可能性もあります (JVM 間の転送ではプロキシ)。最初に acceptDrop
を呼び出さずに getTransferable
を呼び出すことは不正です。
addNotify
および removeNotify
メソッドは、基本的なプラットフォームの DropTargetContextPeer
によって排他的に呼び出され、DropTargetContext
およびそれと関連付けられた DropTarget
で発生または終了したドラッグ&ドロップ操作を DropTargetContext
に通知します。
createTransferableProxy
メソッドにより、DropTargetContext
の実装で、DropTargetListener
と呼び出し元から提供された Transferable
との間に Transferable
を挿入できるようになります。一般に、呼び出し元は基本的なプラットフォームの DropTargetContextPeer
です。
適切な Drag-under フィードバックセマンティクスの提供、およびその後のドロップの処理は、DropTarget
に関連付けられた DropTargetListener
を使って可能になります。
DropTargetListener
は、転送元によって提案された動作、利用可能なデータ型、およびデータ自体を検査することによって、ドロップが可能かどうかに関する適切な Drag-under フィードバックおよび DragSource
への応答を決定します。
特定の DropTargetListener
インスタンスは、addDropTargetListener
メソッドを介して DropTarget
に関連付けられ、removeDropTargetListener
メソッドを介して削除されます。
public interface java.awt.dnd.DropTargetListener extends java.util.EventListener { void dragEnter (DropTargetDragEvent dtde); void dragOver (DropTargetDragEvent dtde); void dropActionChanged (DropTargetDragEvent dtde); void dragExit (DropTargetDragEvent dtde); void drop (DropTargetDropEvent dtde); }
DropTargetListener
の dragEnter
メソッドは、論理 Drag カーソルのホットスポットが、DropTarget
に関連付けられた Component
のジオメトリの可視部分と交差したときに呼び出されます。この通知を受け取ると、DropTargetListener
は、DragSource
から提供される操作または動作、あるいはデータ型 (DataFlavors
) およびデータ自体を調べて、適切な動作および Drag-under フィードバックを決定し、acceptDrag
または rejectDrag
を呼びます。
DropTargetListener
の dragOver
メソッドは、動いている論理 Drag カーソルのホットスポットが、DropTarget
に関連付けられた Component
のジオメトリの可視部分と交差し続けている間に呼び出されます。この通知を受け取ると、DropTargetListener
は、DragSource
から提供される動作、およびデータ型あるいはデータ自身を調べて、適切な動作および Drag-under フィードバックを決定し、acceptDrag
または rejectDrag
を呼び出します。
DropTargetListener
の dragExit
メソッドは、論理 Drag カーソルのホットスポットが、DropTarget
に関連付けられた Component
のジオメトリの可視部分と交差しなくなったとき、または drop
による通知が行われる直前に呼び出されます。この通知を受け取ると、DropTargetListener
は、それまでに適用したすべての Drag-under フィードバック効果を取り消します。このときの副作用として、DropTarget
に関連付けられた DropTargetContext
が無効になることに注意してください。
交差している間にユーザがドラッグジェスチャーを終了すると、DropTargetListener
の drop
メソッドが呼び出されます。この通知を受け取ると、DropTargetListener
は、DropTargetDropEvent
オブジェクト上の getSourceActions
メソッドの戻り値によって指定された操作を、getTransferable
メソッドから返された Transferable
オブジェクト上で実行します。その後、関連付けられた DropTargetContext
の dropComplete
メソッドを呼び出して、操作の成功または失敗を示します。
DropTargetEvent
および DropTargetDragEvent
は次のように定義されています。
public abstract class java.awt.dnd.DropTargetEvent extends java.util.EventObject { public DropTargetContext getDropTargetContext(); //... }
DropTargetEvent
は、DropTargetListener
の dragExit
メソッドに渡されます。
public class java.awt.dnd.DropTargetDragEvent extends java.awt.dnd.DropTargetEvent { public Transferable getTransferable(); public Point getLocation(); public int getSourceActions(); public getDropAction(); public DataFlavor[] getCurrentDataFlavors(); public List getCurrentDataFlavorsAsList(); public boolean isDataFlavorSupported(); public void acceptDrag(int operation); public void rejectDrag(); //... }
DropTargetDragEvent
は、DropTargetListener
の dragEnter
、dragOver
、および dropActionChanged
メソッドに渡されます。
getLocation
メソッドは、関連付けられた Component
を原点として、論理 Drag カーソルのホットスポットの現在の相対座標を返します。
getSourceActions
メソッドは、現在の「動作」、つまり DragSource
によって現在のドラッグ&ドロップのジェスチャーに関連付けられた操作 (ACTION_MOVE、ACTION_COPY、または ACTION_REFERENCE) を返します。
getDropAction
メソッドの戻り値は、ユーザジェスチャーによって選択されているアクションを返します。
getCurrentDataFlavors
、getCurrentDataFlavorsAsList
、および isDataFlavorSupported
メソッドは、転送元のリスト型を受け側で調べるときに使用します。
getTransferable
メソッドは、転送元のデータを受け側で調べるときに使用します。DropTargetDragEvent
インスタンス上の getTransferable
はそれぞれの DropTargetListener
のメソッド内でのみ呼び出され、すべての必要なデータはメソッドが返される前に、返された Transferable
から取り出されることに注目してください。
DropTargetDropEvent
は、次のように定義されます。
public class java.awt.dnd.DropTargetDropEvent extends java.awt.dnd.DropTargetEvent { public Point getLocation(); public int getSourceActions(); public int getDropAction(); public void acceptDrop(int dropAction); public void rejectDrop(); public boolean isLocalTransfer(); public DataFlavor[] getCurrentDataFlavors(); public List getCurrentDataFlavorsAsList(); public boolean isDataFlavorSupported(DataFlavor df); public Transferable getTransferable(); public void dropComplete(boolean success); //... }
ドロップが発生すると、DropTargetDropEvent
が DropTargetListener
の drop
メソッドに渡されます。DropTargetDropEvent
は DropTargetListener
に対して、getTransferable
メソッドから返される Transferable
を介して、この操作に関連付けられたデータへのアクセスを提供します。
getSourceActions
メソッドの戻り値は、ドロップの発生時に転送元によって定義された動作を返すように定義されています。
getDropAction
メソッドの戻り値は、ユーザジェスチャーによって現在選択されているアクションを返します。
getLocation
メソッドの戻り値は、ドロップが発生した位置を返すように定義されています。
getCurrentDataFlavors
、getCurrentDataFlavorsAsList
、および isDataFlavorSupported
メソッドは、Transferable
の getTransferData
メソッドによって後続の転送が行われるときに、転送元のデータ型を受け側で調べるときに使用されます。
drop
メソッドの標準の実装は、アクションおよび利用可能な DataFlavor
を検査し、交換が正常に終了するかどうかを判定します。
交換が発生すると、DropTargetListener.drop
実装は、getTransferable
を呼び出す前に、選択された操作で実パラメータとして acceptDrop
を呼び出します。acceptDrop
の前に getTransferable
を呼び出すと、InvalidDnDOperationException
が発生します。
rejectDrop
を呼び出して、ドロップ操作を拒否することも可能です。rejectDrop
を呼び出すと、転送元と受け側の間の対話が停止します。このため、通常は、rejectDrop
を呼び出すと、ただちに drop
メソッドから戻ります。
ドラッグ&ドロップ操作の転送元が、drop
による通知の受け側と同一の物理 JVM に存在する場合は、isLocalTransfer
メソッドから true が返されます。同一の物理 JVM に存在しない場合は、false が返されます。
ローカルの物理 JVM で呼び出された Transferable.getTransferData
からオブジェクト参照を受け取る場合は、この違いが重要になります。この場合、受け取ったオブジェクト参照は、転送元で保持されているものと同じです (コピー、プロキシ、および異なるオブジェクトではない)。このため、受け側では共有オブジェクト参照を、次のような特別な方法で処理する必要があります。
dropCompete
が呼び出されて転送の完了が転送元に通知されるまで、オブジェクトまたはカプセル化されたデータの状態を変更してはならない (また、転送元は、getTransferData
メソッドからこれらのオブジェクトを返したあとでも、dragDropEnd
による通知を受け取るまで、オブジェクトの状態を変更できないことに注意する)
dropComplete
および dragDropEnd
メソッドが処理されるまでは、交換されたオブジェクトまたはそのオブジェクトに含まれるデータの状態を変更することはできない。その後、共有セマンティクスは、共有されているオブジェクトに依存した実装になる
dropComplete
メソッドは、関連付けられたドラッグ&ドロップ操作の終了を通知し、受け側で実行された転送の成功 (または失敗) を返します。このメソッドを呼び出すと、DragSourceListener
の dragDropEnd
メソッドが、DragSourceDropEvent
で使用できる適切な状態で呼び出されます。このメソッドの呼び出しに失敗すると、ドラッグ&ドロップ操作が正常に終了しません。
多くの GUI Component
は、大規模な (大規模になり得る) データセットに対し、スクロール可能な「ビューポート」を提供します。ドラッグ&ドロップ操作時には、これらのビューポートを自動スクロールできることが望ましいでしょう。そうすれば、操作の対象物をドロップしたい特定の (最初はビューポートに表示されていない) メンバの位置までスクロールしながら、データセット上を移動することができます。
スクロール可能な Component
は、次のインタフェースを実装することによって、DropTarget
にドラッグの「自動スクロール」機能を提供します。
public interface Autoscroll { Insets getAutoscrollInsets(); void autoScrollContent(Point cursorLocn); }
次の条件が満たされた場合、実装する DropTarget
は、関連付けられた Component
(存在する場合) の autoscroll
メソッドを定期的に呼び出し、Component
の座標で表した現在の論理カーソルの位置を渡します。
Component
の可視ジオメトリ、および getAutoscrollInsets
メソッドが返す Insets
によって記述された境界領域と交差した場合
上のいずれかの条件が満たされなくなると、次にトリガとなる条件が発生するまで自動スクロール機能は終了します。
自動スクロール開始前の初期遅延、自動スクロール通知の間隔、およびピクセルのヒステリシス値はすべて、外部で設定でき、Toolkit.getDesktopProperty
メソッドから問い合わせることができます。
有効なドロップが発生した場合は、DropTargetListener
の drop
メソッドは、ジェスチャーに関連付けられたデータの転送に取りかかります。DropTargetDropEvent
は、転送されるデータオブジェクトを表す Transferable
オブジェクトを取得する手段を提供します。
まず、drop
メソッドにより、DropTargetListener
が、rejectDrop
を呼び出してドロップを拒否するか (この場合はすぐに復帰する)、または getSourceActions
によって返された操作から選択された操作を指定する acceptDrop
を呼び出してドロップを受け入れます。
acceptDrop
のあとは、getTransferable
が呼び出され、返された Transferable
の getTransferData
メソッドを介してデータ転送が行われます。最後に、ドロップの転送先で転送元からのオブジェクトの転送が完了すると、DropTargetContext.dropComplete
が呼び出され、転送の成功または即時失敗が通知されます。
DropTargetContext.dropComplete
メソッドから復帰すると同時に、Transferable
および DragSourceContext
のインスタンスが有効であるという保証がなくなるため、後でガベージコレクトできるように、受け側によりインスタンスへのすべての参照が破棄されます。
ACTION_REFERENCE 操作を使う場合は、転送元と転送先でオブジェクトおよび関連付けられた転送のセマンティクスに合意が必要です。一般に、JVM 内の転送では、転送元と転送先の間でライブオブジェクト参照が渡されますが、JVM 間の転送、またはネイティブアプリケーションと Java アプリケーションの間では、ライブオブジェクト参照は無意味で、URI などのほかの種類の参照が交換されます。転送が JVM 内の転送かどうかは、DragSource
と DropTarget
の両方で検出できます。
ターゲットとなるすべてのドラッグ&ドロッププラットフォームは、同様の機構を使って転送データの型を表しますが、この表現方法には違いがあります。Java プラットフォームでは、DataFlavor
内にカプセル化された MIME 形式を使ってデータ型を表します。Java と、プラットフォームにネイティブなアプリケーションとの間でのデータ転送を許可するには、これらのプラットフォーム名の存在が公開される必要があります。このため、これらのプラットフォームに依存する型名、それらの表現方法、および Java MIME ベースの DataFlavor
間で、プラットフォームに依存しない拡張可能なマッピングを作成するための機構が必要です。
この実装は、プラットフォームにネイティブなデータ型 (文字列) と DataFlavors
の構築に使われる MIME 形式 (文字列) との間のマッピングを外部で指定する機構を提供します。この外部マッピングは、背後のプラットフォームのドラッグ&ドロップ機構によって転送元から転送先にエクスポートされる適切な DataFlavors
(MIME 形式) を公開するために、背後のプラットフォーム固有の実装コードで使われます。
背後のシステムは、DragSource
クラスおよび DropTarget
クラスのどちらを使っても、プラットフォームに依存する名前と DataFlavors
間のマッピングにアクセスできます。
public interface java.awt.datatransfer.FlavorMap { java.util.Map getNativesForFlavors(DataFlavor[] dfs); java.util.Map getFlavorsForNatives(String[] natives); }
getNativesForFlavors
メソッドは、DataFlavor
の配列をパラメータにとり、実パラメータ dfs
から、関連付けられた String
型の値 (その MIME 形式に対応するプラットフォームに依存する型名に一致) とともに、DataFlavor
型のゼロ個以上のキーを含む Map
オブジェクトを返します。
getFlavorsForNatives
メソッドは、String
型の配列をパラメータにとり、実パラメータ natives から、関連付けられた DataFlavor
型の値 (そのプラットフォームに依存する型名に対応するプラットフォームに依存しない型に一致) とともに、String
型のゼロ個以上のキーを含む Map
オブジェクトを返します。
これらのメソッドによって返される Map
オブジェクトは可変の場合もありますが、必ずしもその必要はありません。
null がこれらのメソッドのうちのいずれかに渡されると、呼び出しの時点で実装にとって既知であるすべてのキーと値の現在のマップが返されます。
たとえば、Win32 では、シンプルテキストのクリップボード形式の名前は、CF_TEXT (実際にはこれは整数 1) ですが、Motif では、STRING という名前の X11 Atom です。MIME 形式を使ってこれを表現する場合は、text/plain charset=us-ascii です。プラットフォームに対する移植性のある FlavorMap
は、Win32 上の CF_TEXT と Motif/X11 上の STRING 間のマッピングを行います。
一般に、これらのマッピングは、SystemFlavorMap
に実装するときに、外部の固定された設定形式 (プロパティファイルまたは URL) に保持し、プラットフォームからロードして、特定のプラットフォームに適切に FlavorMap
を設定するようにします。
SystemFlavorMap
クラスは、全システムに共通なマッピングのセットを指定するための、プラットフォームで設定が可能な単純な機構を実装するために提供されています。次のように定義されています。
public class java.awt.datatransfer.SystemFlavorMap implements FlavorMap, FlavorTable { public static FlavorMap getSystemFlavorMap(); public synchronized Map getNativesForFlavors(DataFlavor[] dfs); public synchronized Map getFlavorsForNatives(String[] natives); public static String encodeDataFlavor(DataFlavor flav); public static String encodeJavaMIMEType(String mimeType); public static boolean isJavaMIMEType(String mimeStr); public static String decodeJavaMIMEType(String nat); public static DataFlavor decodeDataFlavor(String nat); //... }
SystemFlavorMap
クラスは、プラットフォーム固有の FlavorMap
のプロパティファイル (java.awt.Properties
を参照) を使った単純な実装を提供します。このクラスは、AWT のプロパティである AWT.flavorMapFileURL (Toolkit.getProperty
を参照) の値か、または System.getProperty("java.home") + File.separator + "lib" + File.separator + "flavormap.properties"
のデフォルトのファイル位置を使って、そのプロパティから適切な Map
を作成します。
さらに、このクラスは、Java MimeType
とプラットフォームに依存した名前空間のコード化または復号化に使う、いくつかの static な簡易関数を提供します。プロパティファイルの構文は、次のとおりです。
{ <platform_type_name> ‘=' <IETF_MIME_RFC_conformant_specification> <nl> } *
DragSource
および DropTarget
のデフォルト実装は、その他の実装によってオーバーライドされていなければ、getFlavorMap
メソッドから SystemFlavorMap
を返します。
この API では、Java とネイティブアプリケーションの間でデータをドラッグ&ドロップできることが最優先の目標です。このことが、Java 仮想マシンの境界を越えてデータが渡されたときに行われる、実際のデータ符号化およびデータ交換の方法および機構に大きく影響しています。
このようなデータ交換では、転送元または受け側が Java のデータ型を認識しないネイティブアプリケーションであるため、このドラッグ&ドロップのシステムでは単純に Java オブジェクトの参照を渡すことができません。転送元または受け側で Java のデータ型の認識または操作を行うことができない可能性があるためです。
データ交換が発生すると、転送元と受け側の実装に関係なく、データ型および符号化の方式に双方が合意しているときに限り、データ交換が実現されます。つまり残念なことに、交換で発生する問題は、ほとんどの場合、転送元および受け側のアプリケーションが原因です。
実質的には、プラットフォームに依存したイメージ、ドキュメント、その他の「Content-Type」など、「ネイティブ」なデータ形式の場合において、関連する外部形式の符号化と復号化は、転送を行う転送元と転送先の責任によって行われます。
このドラッグ&ドロップシステムでは、そのような Java 仮想マシンの境界を越える「ネイティブ」なデータ型の外部表現が、java.io.InputStream
またはそのサブクラス内にカプセル化されて公開されます。
つまり、java.io.InputStream
を継承する表現クラスを含むすべての DataFlavor
が、Java 仮想マシンの境界を越えて転送可能であり、転送のために公開されることになります。
このようなネイティブなデータ型の交換を実装するには、DataFlavor
を MIME の「Content-Type」に定義します。MIME の「Content-Type」には、「ネイティブ」なデータ型の特性が、java.io.InputStream
クラスを継承する表現クラスを使って記述されています。java.io.InputStream
クラスによって、カプセル化されたデータがバイトストリームに符号化されます。
特に、このような InputStream
サブクラスによって、次のセマンティクスが実装されます。
java.io.InputStream
型の引数を 1 つ取る public コンストラクタの提供
java.io.InputStream
のサブクラスによってこのコンストラクタが提供されるため、DropTarget
に関連付けられた ドラッグ&ドロップシステムでは、要求された DataFlavor
に指定されている表現クラスのインスタンスが自動的に再構築されます。そのインスタンスは、サブクラスの要求に応じてフォーマットされたカプセル化データを含む InputStream
によって初期化されます。このインスタンスは、初期化されると、Transferable.getTransferData
メソッドの呼び出し側に返されます。次に、呼び出し側では、データストリームが転送されると、フォーマットされた内容が読み取られ解釈されます。
InputStream.read(byte b[], int off, int len)
の実装の提供
このメソッドの提供 (またはスーパークラス実装の継承) によって、DragSource
に関連付けられたドラッグ&ドロップシステムでは、カプセル化されたデータの符号化されたストリームが Transferable
から自動的に抽出されます。この結果、このデータは JVM の境界を越えて、DataFlavor
のリクエスタに単純なバイトストリームとして転送されます。
ドラッグ&ドロップ転送の典型的な対象として、プラットフォームに依存する 1 つ以上のファイル名のリストを挙げることができます。ファイル名リストの作成または処理を行うプログラムを簡単に開発できるように、ドラッグ&ドロップシステムでは、ファイル名リストは独自に処理されます。
DataFlavor
が application/x-java-file-list;class=java.util.List
という MIME「Content-Type」に指定されている場合、ドラッグ&ドロップシステムでは、リストの要素が java.io.File
型のオブジェクトのリストと同質であることを前提としています。したがって、ファイルリストの転送がサポートされている場合は、この DataFlavor
が要求されると、転送元では、その File
オブジェクトの List
が構築されます。また、受け側が、有効な DataFlavor
を要求した場合は、その File
オブジェクトの List
を転送元から受け取ります。転送元とターゲット間でファイルリストを転送するときは、この独自の処理による簡単な機構が使用されます。
RMI 機構の機能を使用すれば、JVM 間でオブジェクト参照をドラッグ&ドロップすることができます。ドラッグ&ドロップシステムでは、次の要件を満たすように、オブジェクト参照の転送が自動的に構成されます。
DataFlavor
に関連付けられたインタフェースの表現クラスが、java.rmi.Remote
と java.io.Serializable
の両方を実装している
(MIME の「Content-Type」には、任意の適合したデータ型、または application/x-java-remote-object を指定できる)
(効果的に実装するには、転送されたオブジェクト実装クラスは、java.rmi.server.UnicastRemoteObject
から継承されていなければならない。RMI システムには必要な初期化がいくつか実装されているためである。その初期化が実装されていない場合は、転送は正常に完了しない)
これらの条件が満たされている場合は、適切な DataFlavor
が要求されると、リクエスタ (転送元と異なる JVM に存在する場合) に返されるオブジェクトは、DataFlavor
の表現クラスとして指定されている Remote
オブジェクトサブインタフェースのインスタンスへの RMI 参照になります。
特定の基本的なプラットフォームのドラッグ&ドロップ、およびウィンドウシステムの実装には制限があるため、ドラッグ操作の対話、および AWT Component
へのイベント送信のセマンティクスは、プラットフォームに依存しています。このため、ドラッグ操作中に DragSource
がそのドラッグに属するプラットフォームのウィンドウシステムイベントの処理を行い、通常のイベント処理が排除されることがあります。
プラットフォームネイティブなドラッグ&ドロップシステムのシングルスレッドの処理部と、AWT 内の実装を担当するネイティブなウィンドウシステムイベントの対話により、DropTargetListener
、および DragSourceListener
への「コールバック」は、AWT システムイベントを処理するスレッド上か、またはスレッドと同期して発生します。これは、セキュリティの面で望ましくない動作ですが、構造ではなく実装上の特徴なので、避けることができません。
JVM 内のドラッグ&ドロップ転送を可能にするため、既存の DataFlavor
クラスは、直列化された固定表現ではなく、「ライブ」オブジェクト参照の型を表現できるように拡張されます。このようなオブジェクトは、同じ JVM、および ClassLoader
コンテキスト内にある転送元と転送先の間で転送されます。
MIME コンテンツタイプは、application/x-java-local-objectref になります。
Transferable
オブジェクト、それに関連付けられた DataFlavor
、およびドラッグ&ドロップ操作のオペランドに指定された基本的なデータをカプセル化するオブジェクトは、少なくとも、操作を制御する DragSource
に関連付けられた DragSourceListener
が dragDropEnd
イベントを受け取るまで有効です。転送元と転送先の間での操作対象の有効期間は、その時点を過ぎて定義される実装です。
正常に終了したドラッグ&ドロップ (ACTION_MOVE) 操作の「転送元」は、転送が正常に完了したあと、すぐに Transferable
の対象であるオブジェクトへの参照を削除または放棄する必要があります。これは、DragSourceListener.dragDropEnd
通知から戻る前に行う必要があります。
以前のバージョンの仕様に対する開発者からのフィードバックの結果、動作タグ ACTION_REFERENCE が追加されました。このタグにより、既存のプラットフォームのドラッグ&ドロップ「リンク」セマンティクスを含めることができます。
参照、つまりリンクのセマンティクスは、プラットフォームネイティブのドラッグ&ドロップにとって非常に不都合なものであるため、ネイティブなアプリケーション間でさえも本質的に使い物にならなくなっていると言えます。このため、ネイティブと、プラットフォームに依存しない Java アプリケーションとの間では、このセマンティクスの使用は推奨されません。
Java 対 Java で使用する場合、求められるセマンティクス (同一の JVM および ClassLoader
内) は、転送先が転送対象への Java オブジェクト参照を取得するように定義されています。JVM または ClassLoader
間では、セマンティクスの実装は定義済みですが、転送元から転送先に URL を送るか、RMI Remote
参照によって実装することもできます。
この定義は、この仕様の標準的な部分ではありませんが、仕様をわかりやすくするために含められています。
public interface DropTargetPeer { void addDropTarget(DropTarget dt); void removeDropTarget(DropTarget dt); }
この定義は、この仕様の標準的な部分ではありませんが、仕様をわかりやすくするために含められています。
public interface DragSourceContextPeer { void startDrag(DragSourceContext dsc, Cursor c, Image di, Point ioff ) throws InvalidDnDOperationException; Cursor getCursor(); void setCursor(Cursor c) throws InvalidDnDOperationException; void transferablesFlavorsChanged(); }
この定義は、この仕様の標準的な部分ではありませんが、仕様をわかりやすくするために含められています。
public interface DropTargetContextPeer { int getTargetActions(); void setTargetActions(int actions); DropTarget getDropTarget(); DataFlavor[] getTransferDataFlavors(); Transferable getTransferable() throws InvalidDnDOperationException; boolean isTransferableJVMLocal(); void acceptDrag(int dragAction); void rejectDrag(); void acceptDrop(int dropAction); void rejectDrop(); void dropComplete(boolean success); }