このドキュメントには次のセクションがあります。
この仕様では、Java 2 プラットフォームのドラッグ&ドロップ機能の API を定義します。
この仕様で規定するプライマリ要件は、次のとおりです。
java.awt.datatransfer.* パッケージを活用して、MIME 標準ベースの拡張可能なデータ型システムに記述されている、データの転送を使用可能にする。この仕様は、上で言及した以前の研究から派生していますが、JavaBeans イベントモデルや軽量 (Swing) コンポーネントが出現し、クロスプラットフォームの統合と相互運用性の問題の理解が深まってきた結果、元の研究とはかなり異なった仕様が組み入れられています。
以降のセクションでは、ドラッグ&ドロップ API について説明します。
ドラッグ&ドロップは、多くのグラフィカルユーザーインタフェース (GUI) システムにみられる直接的な操作のジェスチャーで、GUI 内の表現要素に論理的に関連付けられた 2 つの構成要素間で情報を転送するためのメカニズムを提供します。通常、ドラッグ&ドロップは、ユーザーが適切な入力デバイスを使用して行う物理的なジェスチャーによって生じます。ドラッグ&ドロップは、GUI の表現要素上でデータ転送の結果がわかるように、ナビゲーション中に、ユーザーに継続的にフィードバックするメカニズムと、続いて行われるデータのネゴシエーションおよび転送を容易にする機能を提供します。
一般的なドラッグ&ドロップ操作は、次のようにいくつかの状態に分けることができます (この順番どおり行われるわけではない)。
Transferable (転送可能になり得る) データのドラッグ&ドロップを開始するために、GUI の表現要素 (Component) に関連付けられた DragSource (ドラッグソース) が作成されます。Transferable データ型を消費できる可能性のある、GUI の表現要素 (Components) に関連付けられた 1 つ以上の DropTarget が生成または削除されます。DragGestureRecognizer が DragSource から取得され、ユーザーのドラッグ開始ジェスチャーを Component 上で追跡し識別するために、Component と関連付けられます。Component 上でドラッグジェスチャーを行うと、登録された DragGestureRecognizer がそれを検出し、その DragGestureListener に通知します。
注:このドキュメントでは、ドラッグ&ドロップ操作の開始要因が、人間であるユーザーによる物理的なジェスチャーであることを繰り返し言及していますが、これには、DragSource が適切に実装されている場合の、プログラムによるドラッグ&ドロップ操作も含まれています。
DragGestureListener によって、DragSource がユーザーの代わりにドラッグ&ドロップ操作を開始します。このとき、GUI Cursor がアニメーション化されたり、操作の対象である項目の Image がレンダリングされたりすることがあります。DropTarget が関連付けられている GUI の Component の上を移動すると、サポートされる操作および関連するデータ型に基づいて、DragSource は「ドラッグオーバー」フィードバック効果を提供するために通知を受信し、DropTarget は「ドラッグアンダー」フィードバック効果を提供するために通知を受け取ります。
ジェスチャー自体は、論理カーソルを GUI 階層全体にわたって移動し、GUI Component の幾何学的図形と交差します。これにより、論理的な Drag カーソルが Component とそれに関連付けられた DropTarget に入り、横切り、その後離れる可能性があります。
DragSource オブジェクトはユーザーに「ドラッグオーバー」フィードバックを示します。通常の場合、論理カーソルに関連した GUI Cursor を動画化します。
DropTarget オブジェクトは、通常は関連付けられた GUI Component の GUI Cursor にアニメーションをレンダリングすることによって、「ドラッグアンダー」フィードバックをユーザーに示します。
DragSource と DropTarget の両方がサポートする変換「操作」、つまり Copy、Move または Reference(link) によって、パラメータ化される。DragSource が提供するデータ型のセットと、DropTarget が包括できるデータ型のセットとの共通部分によって、パラメータ化される。DragSource および DropTarget は、DragSource に関連した情報を含みその情報の型のネゴシエーションおよび変換となる通知を、Transferable オブジェクトを介して受け取る。このドキュメントの以降の部分では、このモデルをサポートするために提案された API の変更の詳細について説明します。
ドラッグ&ドロップ操作を開始できるジェスチャーは、プラットフォーム、Component、およびデバイスごとに異なります。このため、操作の依存性をカプセル化するためのメカニズムが必要です。このメカニズムがあれば、ドラッグ&ドロップ操作を開始する 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 の具象スーパークラスでは、プラットフォームに依存するマウスベースのジェスチャーがカプセル化されます。この具象スーパークラスは、createDragGestureRecognizer(Class adgrc, DragSource ds, Component c, int sa, DragGestureListener dgl) メソッドを介して Toolkit オブジェクトから取得できます。この 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 によって、直前に認識されたジェスチャーの特性に関する情報がすべてカプセル化されます。次の情報がカプセル化されます。
DragGestureRecognizerComponentDragSourceInputEvent オブジェクトのリスト。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 のインスタンス、または Component インスタンスに関連付けられているアプリケーション固有のオブジェクトごとに 1 つ。実装により異なる制御オブジェクトは、ドラッグ操作を処理するために、ユーザーのジェスチャーの前に DragSource のインスタンスを取得して、関連する Component を有効にします。インスタンスを取得したら、DragGestureRecognizer を取得して、DragSource を Component に関連付ける必要があります。
ユーザーのジェスチャーの最初の解釈、および以降のドラッグ操作の開始は、通常は DragGestureRecognizer によって実装される実装側の Component の役割です。
ジェスチャーが発生すると、ユーザーによる操作ジェスチャーを処理し、ドラッグ&ドロッププロトコルの通知を配布するために、DragSource の startDrag メソッドが呼び出されます。DragSource は、どの時点においても現在の操作として 1 つのドラッグ&ドロップ操作のみを許可し、それ以上の 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 メソッドは、次の条件が満たされたときに呼び出されます。
dragEnter の呼び出しに関連付けられた Component の可視ジオメトリに、まだ交差している。Component に、DropTarget が関連付けられている。DropTarget がまだアクティブである。DropTarget に登録された DropTargetListener dragOver メソッドが呼び出され、正常に処理を返す。DropTarget が、rejectDrag を介してドラッグ拒否しない。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 メソッドは、ユーザージェスチャーによって現在選択されているアクションを返します。
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 間で、プラットフォームに依存しない拡張可能なマッピングを作成するためのメカニズムが必要です。
この実装は、プラットフォームにネイティブなデータ型 (文字列) と DataFlavor の構築に使われる 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);
}