Java 2 Platform Standard Edition 5.0のドラッグ・アンド・ドロップ・サブシステム

このドキュメントには次のセクションがあります。

1.0 要件

この仕様では、Java 2プラットフォームのドラッグ・アンド・ドロップ機能のAPIを定義します。

この仕様で規定するプライマリ要件は、次のとおりです。

  1. AWTおよびSwingクラスによって実装されるJava GUIクライアントに対して、プラットフォームに依存しないドラッグ・アンド・ドロップ機能を提供する。
  2. プラットフォームに依存するドラッグ・アンド・ドロップ機能を統合し、次のような機能を使うネイティブ・アプリケーション間で行われるドラッグ・アンド・ドロップ操作にJavaクライアントが参加できるようにする。
    • OLE (Win32)ドラッグ・アンド・ドロップ
    • XDNDプロトコル
    • CDE/Motif動的プロトコル
    • MacOS
    • OS/2
  3. 100% Pure JavaOS/Javaの実装サポート。
  4. 既存のjava.awt.datatransfer.*パッケージを活用して、MIME標準ベースの拡張可能なデータ型システムに記述されている、データの転送を使用可能にする。
  5. ユーザー補助機能が利用できる場合に、その機能の使用を除外しないこと。
  6. さまざまな入力デバイスのサポートが可能な拡張性。

この仕様は、上で言及した以前の研究から派生していますが、JavaBeansイベント・モデルや軽量(Swing)コンポーネントが出現し、クロス・プラットフォームの統合と相互運用性の問題の理解が深まってきた結果、元の研究とはかなり異なった仕様が組み入れられています。

2.0 API

以降のセクションでは、ドラッグ・アンド・ドロップAPIについて説明します。

2.1 概要

ドラッグ・アンド・ドロップは、多くのグラフィカル・ユーザー・インタフェース(GUI)システムにみられる直接的な操作のジェスチャで、GUI内の表現要素に論理的に関連付けられた2つの構成要素間で情報を転送するためのメカニズムを提供します。通常、ドラッグ・アンド・ドロップは、ユーザーが適切な入力デバイスを使用して行う物理的なジェスチャによって生じます。ドラッグ・アンド・ドロップは、GUIの表現要素上でデータ転送の結果がわかるように、ナビゲーション中に、ユーザーに継続的にフィードバックするメカニズムと、続いて行われるデータのネゴシエーションおよび転送を容易にする機能を提供します。

一般的なドラッグ・アンド・ドロップ操作は、次のようにいくつかの状態に分けることができます(この順番どおり行われるわけではない)。

このドキュメントの以降の部分では、このモデルをサポートするために提案されたAPIの変更の詳細について説明します。

2.2 ドラッグ・ジェスチャの認識

ドラッグ・アンド・ドロップ操作を開始できるジェスチャは、プラットフォーム、Componentおよびデバイスごとに異なります。このため、操作の依存性をカプセル化するためのメカニズムが必要です。このメカニズムがあれば、ドラッグ・アンド・ドロップ操作を開始するComponentの作成が簡単になります。

2.2.1 DragGestureRecognizer

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クラスの特定のセマンティックスをサポートするために、プラットフォームによってその他のabstractサブクラスが提供されることがあります。この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によって、直前に認識されたジェスチャの特性に関する情報がすべてカプセル化されます。次の情報がカプセル化されます。

2.3 ドラッグ・ソース

DragSource (ドラッグ元)は、ドラッグ・アンド・ドロップ操作を開始する構成要素です。

2.3.1 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は、数多くの状況で使用される可能性があります。

制御オブジェクトは、ドラッグ操作を処理するために、ユーザーのジェスチャの前にDragSourceのインスタンスを取得して、関連するComponentを有効にします。インスタンスを取得したら、DragGestureRecognizerを取得して、DragSourceComponentに関連付ける必要があります。

ユーザーのジェスチャの最初の解釈、および以降のドラッグ操作の開始は、通常はDragGestureRecognizerによって実装される実装側のComponentの役割です。

ジェスチャが発生すると、ユーザーによる操作ジェスチャを処理し、ドラッグ・アンド・ドロップ・プロトコルの通知を配布するために、DragSourcestartDragメソッドが呼び出されます。DragSourceは、どの時点においても現在の操作として1つのドラッグ・アンド・ドロップ操作のみを許可し、それ以上のstartDrag要求はすべて、現在の操作が完了するまでIllegalDnDOperationExceptionをスローすることによって拒否します。

ドラッグ操作を開始するために、startDragメソッドの呼出し元は、次のパラメータを提供します。

前述したように、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は、DragSourcestartDrag()メソッドに渡すことができます。nullも渡すことができますが、この場合は、DragSourceクラスまたはインスタンスの「デフォルト」のFlavorMapが使用されます。

2.3.2 DragSourceContextの定義

DragSourcestartDragメソッドが正常に呼び出された結果、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サブインタフェースを介して、startDragDragSourceに登録されたDragSourceListenerを実装する任意のオブジェクトに委譲します。

DragSourceListenerのプライマリの役目は、ドラッグ・アンド・ドロップ操作中にユーザー操作の進行をモニターして、Drag-Over効果をユーザーにフィードバックすることです。一般的に、フィード・バックは、Drag Cursorを変更することで行われます。

各ドラッグ操作には、次の2種類の論理カーソル(ドラッグ・カーソル)の状態が関連付けられています。

Cursorの状態は、DragSourceContextsetCursorメソッドを呼び出すことによって変更できます。

2.3.3 DragSourceListenerの定義

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);
}

ドラッグ操作が進行するに従って、DragSourceListenerdragEnterdragOver、およびdragExitメソッドが呼び出されます。これは、DropTargetが関連付けられているGUI Componentのジオメトリに交差するように、論理Dragカーソルの位置をユーザーがナビゲートした結果です(DropTargetのプロトコルの相互作用に関する詳細は次を参照)。

DragSourceListenerdragEnterメソッドは、次の条件が満たされたときに呼び出されます。

DropTargetに登録されたDropTargetListener dragEnterメソッドが呼び出され、正常に処理を返す。

登録されたDropTargetListenerが、DropTargetDragEventacceptDragメソッドを呼び出して、転送元が実行する可能性のあるドロップ・アクション、および利用可能なデータ型(DataFlavors)を調べた上で、ドラッグを受け入れます。

DragSourceListenerのdragOverメソッドは、次の条件が満たされたときに呼び出されます。

DragSourceListenerdragExitメソッドは、次の条件のうちの1つが満たされたときに呼び出されます。

DragSourceListenerdropActionChanged()メソッドは、ドラッグ操作を実行するためにユーザーが使用している、マウス・ボタンやキーボードのキーなどの入力デバイスの状態が変わったときに呼び出されます。

dragDropEnd()メソッドは、操作が完了したことを示すために呼び出されます。DragSourceDropEventgetDropSuccessメソッドは、終了状態を確認するために使用されます。getDropActionメソッドは、DropTargetDropTargetDropEventacceptDropパラメータを介してドロップ操作に適用するために選択した操作を返します。

このメソッドが完了すると、現在のDragSourceContextおよび関連付けられたリソースが無効になります。

2.3.4 DragSourceEventの定義

DragSourceEventクラスは、DragSourceに属するすべてのイベントのルートEventクラスで、次のように定義されています。

public class   java.awt.dnd.DragSourceEvent extends java.util.EventObject {
        public DragSourceEvent(DragSourceContext dsc);
        public DragSourceContext getDragSourceContext();
        //...
};

このイベントのインスタンスは、DragSourceListenerdragExitメソッドに渡されます。

2.3.5 DragSourceDragEventの定義

DragSourceDragEventクラスは、次のように定義されます。


public class java.awt.dnd.DragSourceDragEvent extends DragSourceEvent {
        public int getTargetActions();
        public int getUserAction();
        public int getGestureModifiers();
        public int getGestureModifiersEx();
        public int getDropAction();
}

このクラスのインスタンスは、DragSourceListenerdragEnterdragOver、およびdragGestureChangedの各メソッドに渡されます。

getDragSourceContextメソッドは、現在のドラッグ・アンド・ドロップ操作に関連付けられたDragSourceContextを返します。

getUserActionメソッドは、ユーザー・ジェスチャによって現在選択されているアクションを返します。

getTargetActionsメソッドは、ドロップ・アクションがドラッグ・ソースによってサポートされている場合には、現在のドロップ・ターゲットにより選択されているドロップ・アクションを返し、ドロップ・アクションがドラッグ・ソースによりサポートされていない場合にはDnDConstants.ACTION_NONEを返します。

これら2つの結果とドラッグ・ソースによりサポートされる一連のドロップ・アクションの論理的な相互作用が、ドロップによる実際の効果を定義し、getDropActionを介して返されます。

getGestureModifiersメソッドは、入力デバイスの修飾子の現在の状態を返します。通常、入力デバイスの修飾子は、ユーザーのジェスチャに関連付けられたマウス・ボタンおよびキーボードのキーです。

getGestureModifiersExメソッドは、ユーザーのジェスチャに関連付けられた入力デバイスの拡張修飾子の現在の状態を返します。

2.3.6 DragSourceDropEventの定義

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();
}

このクラスのインスタンスは、DragSourceListenerdragDropEndメソッドに渡されます。このイベントはドラッグ・アンド・ドロップ操作の終了状態をDragSourceのためにカプセル化します。

ドロップが発生して、ドロップに関係したDropTargetDropTargetContextdropCompleteメソッドを介してデータ転送の成功または失敗を示し、イニシエータはgetDropSuccessメソッドを介してこのステータスを取得できます。ドロップ先であるDropTargetがドラッグの対象に対して実行する操作は、(DropTargetacceptDropメソッドにより渡された) getDropActionメソッドを介して返されます。

ユーザーがDropTargetの外部でジェスチャを終了するか、DropTargetrejectDropを呼び出した場合など、何らかの理由でドロップが発生する前にドラッグ操作が中止された場合は、getDropSuccessメソッドはfalseを返します。そうでない場合はtrueを返します。

2.4 ドロップ・ターゲット

2.4.1 DropTargetの登録および登録解除のためのjava.awt.Componentの追加

java.awt.Componentクラスには、DropTargetとの関連付けおよび関連付け解除を可能にするために、2つのメソッドが追加されました。特に次の点が重要です。

public class java.awt.Component /* ... */ {
        //...
        public synchronized void setDropTarget(DropTarget dt);
        public synchronized DropTarget getDropTarget(DropTarget df);
        //...
}

DropTargetComponentに関連付けるには、DropTarget.setCompononentまたはComponent.setDropTargetのどちらのメソッドを呼び出すこともできます。このため、相互再帰呼出しを防ぐために、両方のメソッドの実装に準拠する必要があります。

DropTargetComponentの関連付けを解除するには、DropTarget.setCompononent(null)またはComponent.setDropTarget(null)のどちらのメソッドを呼び出すこともできます。

DropTargetComponentの両方の設定メソッドの仕様に準拠する実装は、互いの状況を適切に管理するように実装する必要があります。

DropTargetの実パラメータがComponentの、このクラスまたはインスタンスとともに使うことが不適切な場合は、setDropTargetメソッドは、IllegalArgumentExceptionをスローします。また、ComponentDropTargetの外部設定をサポートしていない場合なども、このメソッドはUnsupportedOperationExceptionをスローします。

2.4.2 DropTargetの定義

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メソッドは、新しいFlavorMapDropTargetに割り当てます。パラメータにnullが指定された場合は、「デフォルト」のFlavorMapDropTargetにインストールします。

createDropTargetContextメソッドは、ドラッグ操作で最初にDropTargetに関連付けられたComponentを検出したときに、背後のプラットフォームに依存したピアに、新しいDropTargetContextのインスタンスを提供するためだけに呼び出されます。現在DropTargetに関連付けられているDropTargetContextがない場合は、getDropTargetContextの呼出しに許可されている副作用によって、新しいDropTargetContextのインスタンスが生成されます。

addNotifyおよびremoveNotifyメソッドは、ComponentComponentPeerへの関連付け(および関連付けの解除)をDropTargetに通知するためだけに、Componentから呼び出されます。

DropTarget自体がDropTargetListenerを実装することに注目してください。これにより、プラットフォームによって作成されたプラットフォームのピアであるDropTargetContextPeerのインスタンスは、DropTargetに進行中の操作状態の変化について通知できるようになり、したがってDropTargetは、プラットフォームとDropTargetに登録されているDropTargetListenerの間に割り込むことができるようになります。

2.4.3 DropTargetContextの定義

進行中のドラッグ・アンド・ドロップ操作に関連付けられた論理カーソルが、DropTargetに関連付けられたComponentの可視ジオメトリと最初に交差すると、DropTargetに関連付けられたDropTargetContextがインタフェースになります。このインタフェースを介して、DropTargetListenerから受け側のプロトコルの状態を制御したりアクセスしたりできます。

DropTargetの<>DropTargetContextが存在しない場合は、DropTargetgetDropTargetContextメソッドが呼び出されたときに、副作用としてDropTargetcreateDropTargetContextメソッドによって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のメソッドdragEnterdragOver、またはdropActionChangedから呼び出されます。rejectDragの呼出しは、現在ユーザーが選択しているアクションを受け取れないことを意味します。

acceptDropメソッドは、DropTargetDropEventの類似のメソッドから委譲されていて、DropTargetListenerdropメソッドから呼び出されます。acceptDropの呼出しは、受け側では指定された操作を含むドロップの受け取りの準備ができていることを意味します。通常は、現在ユーザーが選択しているアクションが操作として指定されます。

rejectDropメソッドは、DropTargetDropEventの類似のメソッドから委譲されていて、DropTargetListenerdropメソッドから呼び出されます。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です。

2.4.4 DropTargetListenerの定義

適切な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);
}

次のコンテキストでこのグラフィックスを説明します。

DropTargetListenerdragEnterメソッドは、論理Dragカーソルのホット・スポットが、DropTargetに関連付けられたComponentのジオメトリの可視部分と交差したときに呼び出されます。この通知を受け取ると、DropTargetListenerは、DragSourceから提供される操作またはアクション、あるいはデータ型(DataFlavors)およびデータ自体を調べて、適切なアクションおよびDrag-underフィードバックを決定し、acceptDragまたはrejectDragを呼びます。

DropTargetListenerdragOverメソッドは、動いている論理Dragカーソルのホット・スポットが、DropTargetに関連付けられたComponentのジオメトリの可視部分と交差し続けている間に呼び出されます。この通知を受け取ると、DropTargetListenerは、DragSourceから提供されるアクション、およびデータ型あるいはデータ自身を調べて、適切なアクションおよびDrag-underフィードバックを決定し、acceptDragまたはrejectDragを呼び出します。

DropTargetListenerdragExitメソッドは、論理Dragカーソルのホット・スポットが、DropTargetに関連付けられたComponentのジオメトリの可視部分と交差しなくなったとき、またはdropによる通知が行われる直前に呼び出されます。この通知を受け取ると、DropTargetListenerは、それまでに適用したすべてのDrag-underフィードバック効果を取り消します。このときの副作用として、DropTargetに関連付けられたDropTargetContextが無効になることに注意してください。

交差している間にユーザーがドラッグ・ジェスチャを終了すると、DropTargetListenerdropメソッドが呼び出されます。この通知を受け取ると、DropTargetListenerは、DropTargetDropEventオブジェクト上のgetSourceActionsメソッドの戻り値によって指定された操作を、getTransferableメソッドから返されたTransferableオブジェクト上で実行します。その後、関連付けられたDropTargetContextdropCompleteメソッドを呼び出して、操作の成功または失敗を示します。

2.4.5 DropTargetDragEventおよびDropTargetDropEventの定義

DropTargetEventおよびDropTargetDragEventは次のように定義されています。

public abstract class java.awt.dnd.DropTargetEvent
          extends java.util.EventObject {

        public DropTargetContext getDropTargetContext();
        //...
}

DropTargetEventは、DropTargetListenerdragExitメソッドに渡されます。

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は、DropTargetListenerdragEnterdragOver、およびdropActionChangedメソッドに渡されます。

getLocationメソッドは、関連付けられたComponentを原点として、論理Dragカーソルのホット・スポットの現在の相対座標を返します。

getSourceActionsメソッドは、現在の「アクション」、つまりDragSourceによって現在のドラッグ・アンド・ドロップのジェスチャに関連付けられた操作(ACTION_MOVE、ACTION_COPY、またはACTION_REFERENCE)を返します。

getDropActionメソッドの戻り値は、ユーザー・ジェスチャによって現在選択されているアクションを返します。

getCurrentDataFlavorsgetCurrentDataFlavorsAsList、および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);
        //...
}

ドロップが発生すると、DropTargetDropEventDropTargetListenerdropメソッドに渡されます。DropTargetDropEventDropTargetListenerに対して、getTransferableメソッドから返されるTransferableを介して、この操作に関連付けられたデータへのアクセスを提供します。

getSourceActionsメソッドの戻り値は、ドロップの発生時に転送元によって定義されたアクションを返すように定義されています。

getDropActionメソッドの戻り値は、ユーザー・ジェスチャによって現在選択されているアクションを返します。

getLocationメソッドの戻り値は、ドロップが発生した位置を返すように定義されています。

getCurrentDataFlavorsgetCurrentDataFlavorsAsList、およびisDataFlavorSupportedメソッドは、TransferablegetTransferDataメソッドによって後続の転送が行われるときに、転送元のデータ型を受け側で調べるときに使用されます。

dropメソッドの標準の実装は、アクションおよび利用可能なDataFlavorを検査し、交換が正常に終了するかどうかを判定します。

交換が発生すると、DropTargetListener.drop実装は、getTransferableを呼び出す前に、選択された操作で実パラメータとしてacceptDropを呼び出します。acceptDropの前にgetTransferableを呼び出すと、InvalidDnDOperationExceptionが発生します。

rejectDropを呼び出して、ドロップ操作を拒否することも可能です。呼び出すと、転送元と受け側の間の対話が停止します。このため、通常は、rejectDropを呼び出すと、ただちにdropメソッドから戻ります。

ドラッグ・アンド・ドロップ操作の転送元が、dropによる通知の受け側と同一の物理JVMに存在する場合は、isLocalTransferメソッドからtrueが返されます。同一の物理JVMに存在しない場合は、falseが返されます。

ローカルで呼び出されたTransferable.getTransferDataからオブジェクト参照を受け取る場合は、この違いが重要になります。この場合、受け取ったオブジェクト参照は、転送元で保持されているものと同じです(コピー、プロキシ、および異なるオブジェクトではない)。このため、受け側では共有オブジェクト参照を、次のような特別な方法で処理する必要があります。

dropCompleteメソッドは、関連付けられたドラッグ・アンド・ドロップ操作の終了を通知し、受け側で実行された転送の成功(または失敗)を返します。このメソッドを呼び出すと、DragSourceListenerdragDropEndメソッドが、DragSourceDropEventで使用できる適切な状態で呼び出されます。このメソッドの呼出しに失敗すると、ドラッグ・アンド・ドロップ操作が正常に終了しません。

2.4.6 自動スクロールのサポート

多くのGUI Componentは、大規模な(大規模になり得る)データ・セットに対し、スクロール可能な「ビューポート」を提供します。ドラッグ・アンド・ドロップ操作時には、これらのビューポートを自動スクロールできることが望ましいでしょう。そうすれば、操作の対象物をドロップしたい特定の(最初はビューポートに表示されていない)メンバーの位置までスクロールしながら、データ・セット上を移動できます。

スクロール可能なComponentは、次のインタフェースを実装することによって、DropTargetにドラッグの「自動スクロール」機能を提供します。

public interface Autoscroll {
        Insets getAutoscrollInsets();
        void autoScrollContent(Point cursorLocn);
}

次の条件が満たされた場合、実装するDropTargetは、関連付けられたComponent (存在する場合)のautoscrollメソッドを定期的に呼び出し、Componentの座標で表した現在の論理カーソルの位置を渡します。

上のいずれかの条件が満たされなくなると、次にトリガーとなる条件が発生するまで自動スクロール機能は終了します。

自動スクロール開始前の初期遅延、自動スクロール通知の間隔、およびピクセルのヒステリシス値はすべて、外部で構成でき、Toolkit.getDesktopPropertyメソッドから問い合わせることができます。

2.5 データ転送段階

有効なドロップが発生した場合は、DropTargetListenerdropメソッドは、ジェスチャに関連付けられたデータの転送に取りかかります。DropTargetDropEventは、転送されるデータ・オブジェクトを表すTransferableオブジェクトを取得するための手段を提供します。

まず、dropメソッドにより、DropTargetListenerが、rejectDropを呼び出してドロップを拒否するか(この場合はすぐに復帰する)、またはgetSourceActionsによって返された操作から選択された操作を指定するacceptDropを呼び出してドロップを受け入れます。

acceptDropのあとは、getTransferableが呼び出され、返されたTransferablegetTransferDataメソッドを介してデータ転送が行われます。最後に、ドロップの転送先で転送元からのオブジェクトの転送が完了すると、DropTargetContext.dropCompleteが呼び出され、転送の成功または即時失敗が通知されます。

DropTargetContext.dropCompleteメソッドから復帰すると同時に、TransferableおよびDragSourceContextのインスタンスが有効であるという保証がなくなるため、あとでガベージ・コレクトできるように、受け側によりインスタンスへのすべての参照が破棄されます。

ACTION_REFERENCE操作を使う場合は、転送元と転送先でオブジェクトおよび関連付けられた転送のセマンティックスに合意が必要です。一般に、JVM内の転送では、転送元と転送先の間でライブ・オブジェクト参照が渡されますが、JVM間の転送、またはネイティブ・アプリケーションとJavaアプリケーションの間では、ライブ・オブジェクト参照は無意味で、URIなどのほかの種類の参照が交換されます。転送がJVM内の転送かどうかは、DragSourceDropTargetの両方で検出できます。

2.5.1 FlavorMapおよびSystemFlavorMap

ターゲットとなるすべてのドラッグ・アンド・ドロッププラットフォームは、同様のメカニズムを使用して転送データの型を表しますが、この表現方法には違いがあります。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を返します。

2.5.2 JVM境界を越えるデータの転送

この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サブクラスによって、次のセマンティックスが実装されます。

このメソッドの提供(またはスーパー・クラス実装の継承)によって、DragSourceに関連付けられたドラッグ・アンド・ドロップ・システムでは、カプセル化されたデータのエンコードされたストリームがTransferableから自動的に抽出されます。この結果、このデータはJVMの境界を越えて、DataFlavorのリクエスタに単純なバイト・ストリームとして転送されます。

2.5.3 JVM境界を越えるファイル・リストの転送

ドラッグ・アンド・ドロップ転送の典型的な対象として、プラットフォームに依存する1つ以上のファイル名のリストを挙げることができます。ファイル名リストの作成または処理を行うプログラムを簡単に開発できるように、ドラッグ・アンド・ドロップ・システムでは、ファイル名リストは独自に処理されます。

DataFlavorapplication/x-java-file-list;class=java.util.ListというMIME「Content-Type」に指定されている場合、ドラッグ・アンド・ドロップ・システムでは、リストの要素がjava.io.File型のオブジェクトの同一種リストであることを前提としています。したがって、ファイル・リストの転送がサポートされている場合は、このDataFlavorが要求されると、転送元では、そのFileオブジェクトのListが構築されます。また、受け側が、有効なDataFlavorを要求した場合は、そのFileオブジェクトのListを転送元から受け取ります。転送元とターゲット間でファイル・リストを転送するときは、この独自の処理による簡単なメカニズムが使用されます。

2.5.4 JVM境界を越えるjava.rmi.Remote参照の転送

RMIメカニズムの機能を使用すれば、JVM間でオブジェクト参照をドラッグ・アンド・ドロップすることができます。ドラッグ・アンド・ドロップ・システムでは、次の要件を満たすように、オブジェクト参照の転送が自動的に構成されます。

これらの条件が満たされている場合は、適切なDataFlavorが要求されると、要求元(転送元と異なるJVMに存在する場合)に返されるオブジェクトは、DataFlavorの表現クラスとして指定されているRemoteオブジェクト・サブインタフェースのインスタンスへのRMI参照になります。

3.0 問題点

3.0.1 さまざまなプラットフォーム・プロトコル・エンジンに関する問題点

特定の基本的なプラットフォームのドラッグ・アンド・ドロップ、およびウィンドウ・システムの実装には制限があるため、ドラッグ操作の対話、およびAWT Componentへのイベント送信のセマンティックスは、プラットフォームに依存しています。このため、ドラッグ操作中にDragSourceがそのドラッグに属するプラットフォームのウィンドウ・システム・イベントの処理を行い、通常のイベント処理が排除されることがあります。

プラットフォーム・ネイティブなドラッグ・アンド・ドロップ・システムのシングル・スレッドの処理部と、AWT内の実装を担当するネイティブなウィンドウ・システム・イベントの対話により、DropTargetListener、およびDragSourceListenerへの「コールバック」は、AWTシステム・イベントを処理するスレッド上か、またはスレッドと同期して発生します。これは、セキュリティの面で望ましくない動作ですが、構造ではなく実装上の特徴なので、避けることができません。

3.0.2 VM間の転送か、それともVM内の転送か

JVM内のドラッグ・アンド・ドロップ転送を可能にするため、既存のDataFlavorクラスは、直列化された固定表現ではなく、「ライブ」オブジェクト参照の型を表現できるように拡張されます。このようなオブジェクトは、同じJVM、およびClassLoaderコンテキスト内にある転送元と転送先の間で転送されます。

MIMEコンテンツ・タイプは、application/x-java-local-objectrefになります。

3.0.3 Transferableのライフ・タイム

Transferableオブジェクト、それに関連付けられたDataFlavor、およびドラッグ・アンド・ドロップ操作のオペランドに指定された基本的なデータをカプセル化するオブジェクトは、少なくとも、操作を制御するDragSourceに関連付けられたDragSourceListenerdragDropEndイベントを受け取るまで有効です。転送元と転送先の間での操作対象のライフ・タイムは、その時点を過ぎて定義される実装です。

3.0.4 Transferableを介して公開される転送元オブジェクトのACTION_MOVEセマンティックス

正常に終了したドラッグ・アンド・ドロップ(ACTION_MOVE)操作の「転送元」は、転送が正常に完了したあと、すぐにTransferableの対象であるオブジェクトへの参照を削除または放棄する必要があります。これは、DragSourceListener.dragDropEnd通知から戻る前に行う必要があります。

3.0.5 ACTION_REFERENCE操作のセマンティックス

以前のバージョンの仕様に対する開発者からのフィード・バックの結果、動作タグACTION_REFERENCEが追加されました。このタグにより、既存のプラットフォームのドラッグ・アンド・ドロップ「リンク」セマンティックスを含めることができます。

参照、つまりリンクのセマンティックスは、プラットフォーム・ネイティブのドラッグ・アンド・ドロップにとって非常に不都合なものであるため、ネイティブなアプリケーション間でさえも本質的に使い物にならなくなっていると言えます。このため、ネイティブと、プラットフォームに依存しないJavaアプリケーションとの間では、このセマンティックスの使用は非推奨です。

Java対Javaで使用する場合、求められるセマンティックス(同一のJVMおよびClassLoader内)は、転送先が転送対象へのJavaオブジェクト参照を取得するように定義されています。JVMまたはClassLoader間では、セマンティックスの実装は定義済みですが、転送元から転送先にURLを送るか、RMI Remote参照によって実装することもできます。

付録A: DropTargetPeer定義

この定義は、この仕様の標準的な部分ではありませんが、仕様をわかりやすくするために含められています。

public interface DropTargetPeer {
        void addDropTarget(DropTarget dt);
        void removeDropTarget(DropTarget dt);
}

付録B: DragSourceContextPeer定義

この定義は、この仕様の標準的な部分ではありませんが、仕様をわかりやすくするために含められています。

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();
}

付録C: DropTargetContextPeer定義

この定義は、この仕様の標準的な部分ではありませんが、仕様をわかりやすくするために含められています。

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);
}

Copyright © 1993, 2020, Oracle and/or its affiliates. All rights reserved.