ヘッダーをスキップ
Oracle® Fusion Middleware Oracle ADF FacesによるWebユーザー・インタフェースの開発
12c (12.1.2)
E48096-02
  目次へ移動
目次

前
 
次
 

36 ドラッグ・アンド・ドロップ機能の追加

この章では、ユーザーが属性やオブジェクトの値をコンポーネントから別のコンポーネントにドラッグしたり、コンポーネントをドラッグ・アンド・ドロップしたりできるようにするドラッグ・アンド・ドロップ機能を、ページに追加する方法について説明します。属性、オブジェクト、コレクション、コンポーネント、カレンダおよびサポートされるDVTコンポーネントのドラッグ・アンド・ドロップ機能を追加する方法を説明します。panelDashboard コンポーネントにドラッグ・アンド・ドロップ機能を追加する方法についても説明します。

この章では、次の項目について説明します。

36.1 ドラッグ・アンド・ドロップ機能について

ADF Facesフレームワークには、ページ上の場所から別の場所へアイテムをドラッグ・アンド・ドロップする機能があります。ほとんどの場合、ドラッグ・アンド・ドロップは、ソースおよびターゲットに適切なタグを追加し、マネージドBeanにコードを実装することにより、簡単に実装できます。ドラッグ・アンド・ドロップにより、ユーザーはWebアプリケーションでは当然期待されるGUI経験を体感できます。たとえば、File Explorerアプリケーションでは、図36-1で示すように、ファイルを「表」タブからドラッグし、別のディレクトリ・フォルダにドロップできます。

図36-1 File Explorerアプリケーションでのドラッグ・アンド・ドロップ

ファイルを別のディレクトリ・フォルダへドラッグできます

このシナリオでは、オブジェクトを実際にコレクション(Folder0)からドラッグし、別のコレクション(Folder2)にドロップしています。これは、多数サポートされているドラッグ・アンド・ドロップ・シナリオの1つです。ADF Facesでは、次のシナリオがサポートされています。

ユーザーがソースをクリックしてドラッグし始めると、ブラウザにはドラッグされている要素がマウス・ポインタにアタッチされたゴースト要素として表示されます。ゴースト要素が有効なターゲット上に移動すると、そのターゲット・コンポーネントにはなんらかのフィードバック(強調表示され、カーソルが変化してターゲットが有効であることを示すなど)が現れます。ユーザーがゴースト要素を無効なターゲットにドラッグすると、カーソルが変わり、そのターゲットが有効でないことを示します。

属性値をドラッグするとき、ユーザーはターゲットに対して値のコピーしかできません。他のすべてのドラッグ・アンド・ドロップ・シナリオの場合、ドロップ時に要素は、コピー(コピー・アンド・ペースト)、移動(カット・アンド・ペースト)またはリンク(リンクが実際のファイル・オブジェクトの参照となるディレクトリ内のファイルへのショートカットを作成)できます。

ドラッグされ値を含むコンポーネントは、ソースと呼ばれます。ドロップを受け入れるコンポーネントは、ターゲットと呼ばれます。ソースおよびターゲット・コンポーネントに子として特定のタグを使用し、フレームワークにドロップを許可するように指示します。表36-1に、様々なドラッグ・アンド・ドロップのシナリオ、有効なソースおよびターゲット、そのシナリオで使用するように関連付けられたタグを示しています。

表36-1 ドラッグ・アンド・ドロップのシナリオ

シナリオ ソース ターゲット

属性値のドラッグ

コンポーネント上の属性値

別のコンポーネント上の属性値(同じオブジェクト型である場合)

タグ:
attributeDragSource

タグ:
attributeDropTarget

オブジェクトをコンポーネントから別のコンポーネントへドラッグ

すべてのコンポーネント

すべてのコンポーネント

タグ:
attributeDragSource

タグ:
dropTarget

アイテムをコレクションからドラッグして別のコレクションにドロップ

tabletreeおよびtreeTableコンポーネント

tabletreeおよびtreeTableコンポーネント

タグ:
dragSource

タグ:
collectionDropTarget

コンポーネントをコンテナから別のコンテナへドラッグ

すべてのコンポーネント

すべてのコンポーネント

タグ:
componentDragSource

タグ:
dropTarget

カレンダ・アクティビティをある開始時刻または開始日から別の時刻または日付にドラッグ

calendarActivityオブジェクト

calendarコンポーネント

Tag:
不要

タグ:
calendarDropTarget

panelBoxコンポーネントをpanelDashboardコンポーネントにドラッグ

panelBoxコンポーネント

panelDashboardコンポーネント

タグ:
componentDragSource

タグ:
dataFlavor

panelBoxコンポーネントをpanelDashboardコンポーネントからドラッグ

panelDashboardコンポーネント内のpanelBoxコンポーネント

すべてのコンポーネント

タグ:
componentDragSource

タグ:
dropTarget

DVTグラフ内のマーカーをドラッグ

graphコンポーネント

graphコンポーネント

タグ:
dragSource

タグ:
dropTarget

DVTガント・チャートからオブジェクトをドラッグし、別のコンポーネントにドロップ

ガント・チャート

すべてのコンポーネント

タグ:
dragSource

タグ:
dropTarget

DVT階層ビューア、サンバースト、またはツリーマップからノードをドラッグし、別のコンポーネントにドロップします

階層ビューア, サンバースト、またはツリーマップコンポーネント

すべてのコンポーネント

タグ:
dragSource

タグ:
dropTarget

時系列からイベントをドラッグしてコレクション・コンポーネントにドロップします

timelineコンポーネント

tabletreeおよびtreeTableコンポーネント

タグ:
dragSource

タグ:
collectionDropTarget


ターゲットにドロップできるオブジェクトの型は、dataFlavorタグを追加することで制限でいます。これは、ターゲットでは1つのオブジェクト型しか受け入れられないのに、ソースが多数の異なる型の1つである場合に役立ちます。dataFlavorタグでは、ターゲットで複数のソースまたは複数の型を含む可能性のあるソースからオブジェクトを受け入れることができるよう、複数の型を設定することもできます。ドロップが成功するためには、ターゲットとソースの両方にdataFlavorタグがあり、dataFlavorが識別値とともにカプセル化するJavaタイプがソースとターゲットの間で同一でなければなりません。


注意:

ドラッグ・アンド・ドロップ機能は、ウィンドウ間ではサポートされていません。ウィンドウ境界を越えるドラッグは取り消されます。ポップアップ・ウィンドウとポップアップのベース・ページとの間のドラッグ・アンド・ドロップ機能はサポートされています。

また、ドラッグ・アンド・ドロップ機能はアクセスできないため、ドラッグ・アンド・ドロップを実行するために使用できるキーボード・ストロークがありません。したがって、アプリケーションですべての機能をアクセス可能にすることが求められる場合、このロジックを提供する必要があります。たとえば、ページでユーザーに、オブジェクトを選択する方法と、選択したオブジェクトを移動できるようにする「移動」ボタンまたはメニュー項目を提供する場合もあります。


36.1.1 ドラッグ・アンド・ドロップの追加機能

ドラッグ・アンド・ドロップを実装する前に、その他のADF Faces機能を理解しておくと役に立ちます。ドラッグ・アンド・ドロップの実装に役立つ他の項へのリンクは、次のとおりです。

  • マネージドBean: コードにマネージドBeanを使用している可能性があります。マネージドBeanの使用の詳細は、3.6項「マネージドBeanの作成と使用」を参照してください。

  • イベント: 表およびツリー・コンポーネントでは、なんらかのロジックを実行することにより、アプリケーションを反応させることができるサーバー側およびクライアント側の両方のイベントを起動します。詳細は、第6章「イベントの処理」を参照してください。

36.2 属性のドラッグ・アンド・ドロップ機能の追加

属性のドラッグ・アンド・ドロップ機能は、あるコンポーネントの属性をターゲットとして定義し、別のコンポーネントの属性をソースとして定義して追加します。


注意:

ターゲットとソースの属性値は同じデータ型である必要があります。たとえば、ソースとターゲットの両方がString型の場合、属性のドラッグ・アンド・ドロップが使用可能です。どちらも数値型の場合は、両方で同じコンバータを使用します。


36.2.1 ドラッグ・アンド・ドロップ機能の追加方法

JSFページにすでにあるターゲットとソースのコンポーネントをドラッグ・アンド・ドロップできます。

始める前に:

ドラッグ・アンド・ドロップ機能について理解しておくと役立ちます。詳細は、36.2項「属性のドラッグ・アンド・ドロップ機能の追加」を参照してください。

他のADF Faces機能を使用して追加できる機能について理解することが役立つ場合もあります。詳細は、36.1.1項「ドラッグ・アンド・ドロップの追加機能」を参照してください。

属性のドラッグ・アンド・ドロップ機能を追加する手順:

  1. 「コンポーネント」ウィンドウで、「操作」パネルの「ドラッグ・アンド・ドロップ」グループから、「属性ドロップ・ターゲット」をページのターゲット・コンポーネントに子としてドラッグ・アンド・ドロップします。

  2. 「属性ドロップ・ターゲットの挿入」ダイアログで「属性」ドロップダウンを使用して、ドラッグ・アンド・ドロップ・アクションによる移入先の属性を選択します。このドロップダウン・リストには、ターゲット・コンポーネントの有効な属性がすべて表示されます。

  3. 「コンポーネント」ウィンドウで、「操作」パネルの「ドラッグ・アンド・ドロップ」グループから、「属性ドラッグ元」をターゲットに値を提供するコンポーネントに子としてドラッグ・アンド・ドロップします。

  4. 「属性ドラッグ元の挿入」ダイアログで、「属性」ドロップダウンを使用して、ターゲット属性への移入に使用される値の属性を選択します。このドロップダウン・リストには、ソース・コンポーネントの有効な属性がすべて表示されます。

36.3 オブジェクトのドラッグ・アンド・ドロップ機能の追加

ユーザーが属性値以外をドラッグできるようにする場合、またはあるコンポーネントから別のコンポーネントへ属性をコピーする以外の操作をユーザーができるようにする場合、dropTargetタグを使用します。また、DataFlavorオブジェクトを使用して、ドロップ・ターゲットに対して有効なソースのJava型を決めます。ドロップ・ターゲットとドラッグ・ソースが複数ある場合のために、識別値を使用して有効な組合せを制限できます。ドラッグ・アンド・ドロップ・アクションを受けて必要となる機能の実装も必要です。

たとえば、図36-2に示すように、Stringsの配列を持つoutputTextコンポーネントがあり、ユーザーがoutputTextコンポーネントをpanelBoxコンポーネントにドラッグできるようにして、panelBoxString配列を表示させるとします。

図36-2 配列オブジェクトのドラッグ・アンド・ドロップ

オブジェクトのドラッグ・アンド・ドロップ

outputTextコンポーネントにはattributeDragSourceタグが含まれます。ただし、String値の配列outputTextコンポーネントからドラッグしたいので、ターゲットのoutputTextコンポーネントでattributeDropTargetタグではなくdropTargetタグを使用する必要があります。また、dataFlavorタグを使用してarrayオブジェクトのみがターゲットで受け入れられるようにします。

dataFlavorタグの識別値の定義もできます。同じオブジェクト型の2つのターゲットと2つのソースがある場合に、これは有用です。識別値を作成することで、各ターゲットで有効なソースのみが受け入れられることが保証されます。たとえば、EMPLOYEEオブジェクトを受け入れるTargetAとTargetBの2つのターゲットがあるとします。EMPLOYEEオブジェクトのソースも2つあるとします。TargetAにalphaという値を使用して識別値を設定することにより、識別値alphaを持つEMPLOYEEソースのみが受け入れられます。

ドロップ・イベントのリスナーも実装する必要があります。ドロップ・イベントのオブジェクトはTransferableと呼ばれ、ドロップのペイロードを含みます。リスナーはTransferableオブジェクトにアクセスし、ここからDataFlavorオブジェクトを使用してオブジェクトがドロップ可能なことを確認します。その後、ドロップ・イベントを使用してターゲット・コンポーネントを取得し、ドロップされたオブジェクトを使用してプロパティを更新します。このリスナーの詳細は、36.8項「DVTコンポーネントのドラッグ・アンド・ドロップ機能の追加」の手順で説明します。

36.3.1 単一オブジェクトのドラッグ・アンド・ドロップ機能の追加方法

ドラッグ・アンド・ドロップ機能を追加するには、まず、コンポーネントをドラッグ・アンド・ドロップ・アクションのターゲットとして定義するタグをコンポーネントに追加します。次に、ドラッグ・アンド・ドロップ・アクションのロジックを処理するイベント・ハンドラ・メソッドを実装します。最後に、ドラッグ・アンド・ドロップのソースを定義します。

始める前に:

ドラッグ・アンド・ドロップ機能について理解しておくと役立ちます。詳細は、36.3項「オブジェクトのドラッグ・アンド・ドロップ機能の追加」を参照してください。

他のADF Faces機能を使用して追加できる機能について理解することが役立つ場合もあります。詳細は、36.1.1項「ドラッグ・アンド・ドロップの追加機能」を参照してください。

次のタスクを完了する必要があります。

ページにソースおよびターゲット・コンポーネントを作成します。

ドラッグ・アンド・ドロップ機能を追加する手順:

  1. 「コンポーネント」ウィンドウで、「操作」パネルの「ドラッグ・アンド・ドロップ」グループから、「ドロップ・ターゲット」をドラッグし、ページのターゲット・コンポーネントに子としてドロップします。

  2. 「ドロップ・ターゲットの挿入」ダイアログで、イベントを処理するマネージドBeanのメソッド(このコードはステップ5で作成)に評価される式を入力します。

    マネージドBeanの使用の詳細は、3.6項「マネージドBeanの作成と使用」を参照してください。


    ヒント:

    clientDropListener属性を挿入して、クライアントでドロップを捕捉することもできます。詳細は、36.3.3項「ClientDropListenerの使用に関する必知事項」を参照してください。


  3. 「データ・フレーバの挿入」ダイアログで、ターゲットにドロップ可能なオブジェクトのクラス(java.lang.Objectなど)を入力します。この選択は、dataFlavorタグを作成するために使用され、このタグにより、ターゲットにドロップできるオブジェクトの型(StringDateオブジェクトなど)が決まります。1つのドロップ・ターゲットに複数のdataFlavorタグを使用し、ドロップ・ターゲットでこれらの型のいずれも受け入れるようにすることができます。


    ヒント:

    DataFlavorタグに型指定された配列を指定するには、java.lang.Object[]のようにクラス名に大カッコ([])を追加します。


  4. 構造ウィンドウで、dropTargetタグを選択します。「プロパティ」ウィンドウで、actions属性の値を選択します。これによって、ドロップ・ターゲットでサポートされるアクションが定義されます。有効な値は、COPY(コピーして貼付け)、MOVE(切り取って貼付け)およびLINK(コピーしてリンクとして貼付け)です。

    MOVE COPY
    

    アクションが指定されない場合、デフォルトはCOPYです。

    例36-1に、panelBoxコンポーネントに挿入され、配列オブジェクトをドロップ・ターゲットとするdropTargetコンポーネントのコードを示します。アクションが定義されていないため、許可されるアクションはCOPYのみであることに注意してください。

    例36-1 dropTargetタグのコード

    <af:panelBox text="PanelBox2">
      <f:facet name="toolbar"/>
      <af:dropTarget dropListener="#{myBean.handleDrop}">
        <af:dataFlavor flavorClass="java.lang.Object[]"/>
      </af:dropTarget>
    </af:panelBox>
    
  5. ステップ2で作成したEL式で参照されるマネージドBeanに、ドラッグ・アンド・ドロップ機能を処理するイベント・ハンドラ・メソッドを(EL式での名前と同じ名前を使用して)作成します。

    このメソッドでは、パラメータとしてDropEventイベントをとり、DnDActionオブジェクトを返す必要があり、これはソースをドロップするときに実行されるアクションです。有効な戻り値は、DnDAction.COPYDnDAction.MOVEおよびDnDAction.LINKで、ステップ4でターゲット属性を定義したときに設定されたものです。このメソッドでは、DropEventイベントをチェックし、ドロップを受け入れるかどうか判断する必要があります。ドロップを受け入れる場合、メソッドではドロップを実行し、実行したDnDActionオブジェクトを返します。そうでない場合は、ドロップが拒否されたことを示すDnDAction.NONEを返します。

    このメソッドでは、各dataFlavorオブジェクトの存在も優先順に確認される必要があります。


    ヒント:

    ターゲットに複数のdataFlavorオブジェクトが定義されている場合、Transferable.getSuitableTransferData()メソッドを使用できます。このメソッドでは、Transferableオブジェクトで使用可能なTransferDataオブジェクトのListが適合性の高いものから順に返されます。


    DataFlavorオブジェクトでは、ドロップされるデータの型(java.lang.Objectなど)が定義されます。これは、手順3で作成したJSPのDataFlavorタグでの定義と同じである必要があります。


    ヒント:

    DataFlavorオブジェクトに型指定された配列を指定するには、java.lang.Object[]のようにクラス名に大カッコ([])を追加します。

    DataFlavorオブジェクトではポリモフィズムがサポートされるため、ドロップ・ターゲットでjava.util.Listが受け入れられる場合、Transferableオブジェクトにjava.util.ArrayListを含むドロップは正常終了します。同様に、この機能ではArraysListsとの間の自動変換もサポートされます。

    ドラッグ・アンド・ドロップ・フレームワークで、サーバーのDataFlavorオブジェクトをクライアント・コンポーネントで表す方法がわからない場合、すべてのドロップがクライアントで正常終了するようドロップ・ターゲットが構成されます。


    例36-2に、イベント・ハンドラ・メソッドがコールするプライベート・メソッドを示します(イベント・ハンドラそのものは何もしませんが、このメソッドをコールします。このメソッドには、panelBoxコンポーネントでoutputTextコンポーネントの値となるStringパラメータも必要です)。このメソッドでは、イベント・ペイロードから配列オブジェクトをコピーし、そのイベントを開始したコンポーネントに割り当てます。

    例36-2 dropListenerのイベント・ハンドラ・コード

    public DnDAction handleDrop(DropEvent dropEvent) 
    {
      Transferable dropTransferable = dropEvent.getTransferable();
              Object[] drinks = dropTransferable.getData(DataFlavor.OBJECT_ARRAY_FLAVOR);
            
        if (drinks != null)
        {
          UIComponent dropComponent = dropEvent.getDropComponent();
              
    // Update the specified property of the drop component with the Object[] dropped
          dropComponent.getAttributes().put("value", Arrays.toString(drinks));
              
          return DnDAction.COPY;
        }
        else
        {
          return DnDAction.NONE;      
        }    
      }   
    

    この例では、ドロップ・コンポーネントはpanelBoxコンポーネントです。panelBoxにはvalue属性がないので、panelBoxtext属性を設定するには次のメソッドを呼び出す必要があります。

    dropComponent.getAttributes().put("text", Arrays.toString(drinks));
    
  6. 「コンポーネント」ウィンドウの「操作」パネルから、「クライアント属性」をドラッグし、ページのソース・コンポーネントに子としてドロップします。

    このタグは、イベントに対するソースのペイロードの定義に使用されます。「プロパティ」ウィンドウで、clientAttributeタグに次を定義します。

    • 名前: ペイロードの名前を入力します。

    • 値: ペイロードの値と評価されるEL式を入力します。飲み物を例とすると、これは異なる飲み物の値を含むArrayに解決されます。

  7. 「コンポーネント」ウィンドウで、「操作」パネルの「ドラッグ・アンド・ドロップ」グループから、「属性ドラッグ元」をドラッグし、ページのソース・コンポーネントに子としてドロップします。

    「属性ドラッグ元の挿入」ダイアログで、前述の手順で作成したclientAttributeタグに定義するnameをドロップダウン・リストから選択します。これにより、clientAttributeタグの値がソースのペイロードになります。例36-3に、ドラッグ・アンド・ドロップ操作のソースであるoutputTextコンポーネントのコードを示します。

    例36-3 ドラッグ・ソースのコード

    <af:outputText value="Drag to see drinks">
      <af:clientAttribute name="drinks" value="#{myBean.drinks}"/>
      <af:attributeDragSource attribute="drinks"/>
    </af:outputText>
    

36.3.2 実行時の処理: キーボード修飾子の使用方法

ドラッグ・アンド・ドロップ操作時、ユーザーはキーボードのキーを押して(キーボード修飾子と呼ばれます)、ドラッグ・アンド・ドロップで行われるアクションを選択できます。ドラッグ・アンド・ドロップ・フレームワークでは、次のキーボード修飾子がサポートされます。

  • [Shift]: MOVE

  • [Ctrl]: COPY

  • [Ctrl]+[Shift]: LINK

ユーザーがドラッグ・アンド・ドロップ操作を行うと、ドロップ・ターゲットで、まず、ドラッグ・ソースのデータ形式の値が受け入れ可能かどうかを判断します。ソースとターゲットがコレクションの場合、次に、フレームワークでドラッグ・ソースとドロップ・ターゲットとの間で可能なアクションの論理積を求め、論理積のアクション(COPY、MOVEまたはLINKのうち1つ)をこの順に実行します。有効なアクションが1つのみの場合、そのアクションが実行されます。複数のアクションが可能で、ユーザーのキーボード修飾子がそのうちの1つに合致する場合、それが実行されます。キーボード修飾子が使用されない、あるいはキーボード修飾子と可能なアクションが合致しない場合、可能なアクションのセットからCOPY、MOVE、LINKがこの順にフレームワークで選択されます。

たとえば、COPYとMOVEをサポートするドロップ・ターゲットがあるとします。まず、ドロップ・ターゲットでは、ドラッグ・ソースが有効なデータ・フレーバであることを確認します。次に、ユーザーがドロップを実行したときに、どのアクションを実行するかを判断します。この例では、セットはCOPYとMOVEです。ユーザーがドラッグ中に[Shift]キーを押し続けると(MOVEのキーボード修飾子)、フレームワークではMOVEアクションが選択されます。ユーザーがドラッグ中に[Shift]キーを押し続ける以外のことをしている場合、修飾子キーが選択されていないときはCOPYがデフォルトであるため(順番の1番目)、アクションはCOPYになります。ユーザーが[Ctrl]キーを押している場合は、その修飾子はCOPYと一致し、その結果COPYが実行されます。ユーザーが[Ctrl]キーと[Shift]キーを押していた場合、その修飾子は許可されたアクションの論理積のセットにはないLINKアクションと一致するため、アクションはやはりCOPYになります。


注意:

JavaとJavaScriptとの間のラウンドトリップで情報が失われるため、ドロップでのデータが見込みとは異なる型の場合があります。たとえば、すべての数値型はdoubleオブジェクトとして、charオブジェクトはStringオブジェクトとして、ListオブジェクトとArrayオブジェクトはListオブジェクトとして、その他の大部分のオブジェクトはMapオブジェクトとして表されます。詳細は、6.4.3項「データのマーシャリングとアンマーシャリングに関する必知事項」を参照してください。


36.3.3 ClientDropListenerの使用に関する必知事項

dropTargetタグにはclientDropListener属性が含まれており、この属性によりクライアントでドロップ・イベントを処理するJavaScriptを参照できます。クライアント・ハンドラはパラメータをとることはなく、AdfDnDContextアクションを返します。たとえば、メソッドがAdfDnDContext.ACTION_NONEを返すと、ドロップ操作は取り消され、サーバーでコールされません。メソッドがAdfDnDContext.ACTION_COPYを返すと、コピー操作が許可され、dropListenerが存在する場合には、それを実行するコールがサーバーで発生します。

たとえば、ドロップ・イベントの起動時にメッセージをログ出力するとします。メッセージの出力を処理し、サーバー・リスナーが起動されるよう適切なアクションを返すクライアント・ハンドラを作成します。例36-4に、メッセージの出力にロガーを使用するクライアント・ハンドラを示します。

例36-4 clientDropListenerハンドラ

<script>
/**
 * Shows a message.
 */
function showMessage()
{
  AdfLogger.LOGGER.logMessage(AdfLogger.ALL, "clientDropListener handler,
    copying...");
  return AdfDnDContext.ACTION_COPY;
}
</script>

36.4 コレクションのドラッグ・アンド・ドロップ機能の追加

ユーザーは、collectionDropTargetおよびdragSourceタグを使用して、コレクションからアイテム(表から行など)をドラッグし、ツリーなどの別のコレクション・コンポーネントにドロップできるドラッグ・アンド・ドロップ機能を追加します。たとえば、File Explorerアプリケーションでは、ユーザーは、ディレクトリの内容を表示する表からディレクトリ・ツリーのフォルダにファイルをドラッグできます。図36-3に、Folder0ディレクトリの内容を表示する表からFolder3ディレクトリにドラッグされるFile0.docオブジェクトを示します。ドロップが完了すると、オブジェクトはFolder3を構成するコレクションの一部になります。

図36-3 File Explorerアプリケーションでのドラッグ・アンド・ドロップ機能

ディレクトリへのファイルのドラッグ

単一オブジェクトのドラッグ・アンド・ドロップ同様、コレクションに対しドロップによりコピー、移動またはコピーしてリンクとして貼り付ける(あるいは3つを組み合せる)ことができ、dataFlavorタグを使用してターゲットでの受け入れ対象を限定できます。

ターゲット・ソースがコレクションで、移動動作がサポートされている場合、dragDropEndListener属性のメソッドを実装して、ソース・コンポーネントから参照し、ドラッグ・アンド・ドロップ操作後のコレクションのクリーン・アップに使用することもできます。詳細は、36.4.2項「dragDropEndListenerに関する必知事項」を参照してください。

36.4.1 コレクションのドラッグ・アンド・ドロップ機能の追加方法

コレクションのドラッグ・アンド・ドロップ機能を追加するには、dropTargetタグを使用するかわりにcollectionDropTargetタグを使用します。その後、ドラッグ・アンド・ドロップ・アクションのロジックを処理するイベント・ハンドラ・メソッドを実装する必要があります。次に、dragSourceタグを使用して、ドラッグ・アンド・ドロップ操作のソースを定義します。

始める前に:

ドラッグ・アンド・ドロップ機能について理解しておくと役立ちます。詳細は、36.4項「コレクションのドラッグ・アンド・ドロップ機能の追加」を参照してください。

他のADF Faces機能を使用して追加できる機能について理解することが役立つ場合もあります。詳細は、36.1.1項「ドラッグ・アンド・ドロップの追加機能」を参照してください。

次のタスクを完了する必要があります。

ページにソースおよびターゲット・コンポーネントを作成します。

ドラッグ・アンド・ドロップ機能を追加する手順:

  1. 「コンポーネント」ウィンドウで、「操作」パネルの「ドラッグ・アンド・ドロップ」グループから、「コレクション・ドロップ・ターゲット 」をドラッグし、ページのターゲット・コレクション・コンポーネントに子としてドロップします。

  2. 「コレクション・ドロップ・ターゲットの挿入」ダイアログで、イベントを処理するマネージドBeanのメソッド(このコードはステップ4で作成)に評価される式をdropListener属性に入力します。

  3. 「プロパティ」ウィンドウで、次を設定します。

    • actions: ドラッグ・アンド・ドロップ操作時にソースで行われるアクションを選択します。

      アクションが指定されない場合、デフォルトはCOPYです。

    • modelName: コレクションのモデルを定義します。

      modelName属性の値は、互換性のためにドラッグ・ソースの識別に使用されるStringオブジェクトです。この属性の値は、ステップ6で使用するdragSourceタグのdiscriminant属性の値と一致させる必要があります。つまり、これは任意の名前で、ターゲットとソースが同じmodelName値や識別値を共有する場合に役立ちます。

  4. ステップ2でEL式に挿入されたマネージドBeanに、ドロップ・イベントのハンドラを実装します。

    このメソッドでは、DropEventイベントをパラメータとして使用し、DnDActionを返す必要があります。このメソッドでは、DropEventを使用して、 Transferableオブジェクトを取得し、そこからRowKeySet (ドラッグのために選択された行)を取得します。Transferableオブジェクトから取得したCollectionModelを使用して、実際のrowDataを取得し、ドロップを完了することができます。メソッドでは次にDropEventをチェックして、ドロップを受け入れるかどうかを判断します。メソッドでドロップを受け入れる場合は、ドロップを実行して、実行したDnDAction (DnDAction.COPYDnDAction.MOVEまたはDnDAction.LINK)を返し、受け入れない場合は、DnDAction.NONEを返して、ドロップが拒否されたことを示します。

    例36-5に、2つの表の間での行のコピーを処理するcollectionDropTargetデモに使用されるCollectionDnd.javaマネージドBeanのイベント・ハンドラ・メソッドを示します。

    例36-5 コレクションのdropListenerのイベント・ハンドラ・コード

    public DnDAction handleDrop(DropEvent dropEvent)
      {
        return _handleDrop(dropEvent, getTargetValues(), "DnDDemoModel");
      }
    private DnDAction _handleDrop(DropEvent dropEvent, 
                                    ArrayList<DnDDemoData> targetValues,
                                    String discriminator)
    {
      Transferable transferable = dropEvent.getTransferable();
      // The data in the transferable is the row key for the dragged component.
      DataFlavor<RowKeySet> rowKeySetFlavor =
                           DataFlavor.getDataFlavor(RowKeySet.class, discriminator);
      RowKeySet rowKeySet = transferable.getData(rowKeySetFlavor);
      if (rowKeySet != null)
      {
        // Get the model for the dragged component.
        CollectionModel dragModel = transferable.getData(CollectionModel.class);
        if (dragModel != null)
        {
          // Set the row key for this model using the row key from the transferable.
          Object currKey = rowKeySet.iterator().next();
          dragModel.setRowKey(currKey);
            
          // And now get the actual data from the dragged model.
          // Note this won't work in a region.
          //Need to change this to use collectionModel data flavor.
          DnDDemoData dnDDemoData = (DnDDemoData)dragModel.getRowData();
          
          // Put the dragged data into the target model directly. 
          // Note that if you wanted validation/business rules on the drop,
          // this would be different.
          // getTargetValues() is the target collection used by the target component
            if (dropEvent.getProposedAction() == DnDAction.LINK)
              dnDDemoData = DnDDemoData.addALink(dnDDemoData);
              targetValues.add(dnDDemoData);
        }
        return dropEvent.getProposedAction();
      }
      else
      {
        return DnDAction.NONE;      
      }
    }
      
    
  5. 「コンポーネント」ウィンドウで、「操作」パネルの「ドラッグ・アンド・ドロップ」グループから、「ドラッグ元」をドラッグし、ソース・コンポーネントに子としてドロップします。

  6. dragSourceタグを選択して、「プロパティ」ウィンドウでactionsdiscriminantおよび任意のdragDropEndListenerをターゲットに対して構成済として設定します。たとえば、dragSourceタグは次のようになります。

    <af:dragSource actions="MOVE" discriminant="DnDDemoModel
    dragDropEndListener="#{collectionDnD.endListener}"/>
    

36.4.2 dragDropEndListenerに関する必知事項

ドロップ・イベントの後でソース・コレクションをクリーンアップする必要がある場合が考えられます。たとえば、ドラッグで移動を行った場合、移動した項目がコレクションの一部ではなくなるように、ソース・コンポーネントをクリーンアップする必要があることがあります。

dragSourceタグには、ドラッグ・アンド・ドロップ操作の終了後のロジックを含むハンドラを登録できるdragDropEndListener属性が含まれます。

たとえば、ドラッグ・アンド・ドロップでオブジェクトを移動する場合、ドロップの正常終了後にソース・コンポーネントからオブジェクトを物理的に削除する必要があります。例36-6に、dragDropEndListener属性のハンドラを示します。

例36-6 dragDropEndListenerのハンドラ

public void endListener(DropEvent dropEvent)
{
  Transferable transferable = dropEvent.getTransferable();
  
  // The data in the transferrable is the row key for the dragged component.
  DataFlavor<RowKeySet> rowKeySetFlavor =
      DataFlavor.getDataFlavor(RowKeySet.class, "DnDDemoModel");
  RowKeySet rowKeySet = transferable.getData(rowKeySetFlavor);
  if (rowKeySet != null)
  {
    Integer currKey = (Integer)rowKeySet.iterator().next();

   // Remove the dragged data from the source model directly.
   // getSourceValues() represents a collection object used by the source
   // component
    Object removed = getSourceValues().remove(currKey.intValue());
  }
  // Need to add the drag source table so it gets redrawn.
  // The drag source component needs to be partially refreshed explicitly, while 
  // drop target component automatically refreshed and displayed.
    AdfFacesContext.getCurrentInstance().addPartialTarget(dropEvent.getDragComponent());
  

36.5 コンポーネントのドラッグ・アンド・ドロップ機能の追加

ある親から別の親へのコンポーネントの移動を可能にしたり、親コンポーネントの子コンポーネントの並替えを可能にしたりできます。例として、図36-4に、panelGridコンポーネントの最初の子で最後に移動される暗色のpanelBoxコンポーネントを示します。

図36-4 コンポーネント間のドラッグ・アンド・ドロップ機能

コンポーネントをドラッグ・アンド・ドロップできます

注意:

panelDashboardコンポーネントでのコンポーネントの出し入れを行う場合、そのコンポーネント固有のプロシージャを使用する必要があります。詳細は、36.6項「panelDashboardコンポーネントでのドラッグ・アンド・ドロップ機能の追加」を参照してください。


36.5.1 コンポーネントのドラッグ・アンド・ドロップ機能の追加方法

コンポーネントに対するドラッグ・アンド・ドロップ機能の追加は、オブジェクトに対するものと同様です。ただし、attributeDragSourceタグを使用するかわりにcomponentDragSourceタグを使用します。オブジェクトまたはコレクションのドラッグ・アンド・ドロップ同様、dropListenerハンドラを実装する必要もあります。

始める前に:

ドラッグ・アンド・ドロップ機能について理解しておくと役立ちます。詳細は、36.5項「コンポーネントのドラッグ・アンド・ドロップ機能の追加」を参照してください。

他のADF Faces機能を使用して追加できる機能について理解することが役立つ場合もあります。詳細は、36.1.1項「ドラッグ・アンド・ドロップの追加機能」を参照してください。

ドラッグ・アンド・ドロップ機能を追加する手順:

  1. 「コンポーネント」ウィンドウで、「操作」パネルの「ドラッグ・アンド・ドロップ」グループから、「ドロップ・ターゲット」をドラッグし、ページのターゲット・コンポーネントに子としてドロップします。

  2. 「ドロップ・ターゲットの挿入」ダイアログで、イベントを処理するマネージドBeanのメソッド(このコードはステップ4で作成)に評価される式を入力します。

  3. dropTargetタグを選択した状態のまま、「プロパティ」ウィンドウでaction属性に有効なアクション・セットを選択します。

  4. ステップ2で作成したEL式で参照されるマネージドBeanに、ドラッグ・アンド・ドロップ機能を処理するイベント・ハンドラ・メソッドを(EL式での名前と同じ名前を使用して)dropListener属性に対して作成します。

    メソッドでドロップを受け入れる場合は、ドロップを実行して、実行したDnDAction (DnDAction.COPYDnDAction.MOVEまたはDnDAction.LINK)を返し、受け入れない場合は、DnDAction.NONEを返して、ドロップが拒否されたことを示します。

    このハンドラ・メソッドでは、DropEventイベントを使用してTransferableオブジェクトとそのデータを取得し、移動またはコピーを完了して、必要に応じてコンポーネントを並べ替えます。ドロップを完了したら、メソッドでは実行したDnDActionを返します。そうでない場合は、ドロップが拒否されたことを示すDnDAction.NONEを返します。

    例36-7に、デモ・アプリケーションのcomponentDragSource JSFページで使用されるDemoDropHandler.javaマネージドBeanのhandleComponentMoveイベント・ハンドラを示します。

    例36-7 コンポーネントの移動を処理するdropListenerのイベント・ハンドラ・コード

    public DnDAction handleComponentMove(DropEvent dropEvent)
    {
      Transferable dropTransferable = dropEvent.getTransferable();
      UIComponent movedComponent =  dropTransferable.getData
                                   (DataFlavor.UICOMPONENT_FLAVOR);
      if ((movedComponent != null) &&
           DnDAction.MOVE.equals(dropEvent.getProposedAction()))
      {
        UIComponent dropComponent = dropEvent.getDropComponent();
        UIComponent dropParent = dropComponent.getParent();
        UIComponent movedParent = movedComponent.getParent();
        UIComponent rootParent = null;
        ComponentChange change = null;
        
        // Build the new list of IDs, placing the moved component after the dropped
        //component.
        String movedLayoutId = movedParent.getId();
        String dropLayoutId = dropComponent.getId();
          
        List<String> reorderedIdList = new
                                       ArrayList<String>(dropParent.getChildCount());
            
        for (UIComponent currChild : dropParent.getChildren())
        {
          String currId = currChild.getId();
            
          if (!currId.equals(movedLayoutId))
            {
              if(!movedLayoutIdFound && currId.equals(dropLayoutId))
                reorderedIdList.add(movedLayoutId);
              reorderedIdList.add(currId);
              if(movedLayoutIdFound && currId.equals(dropLayoutId))
                reorderedIdList.add(movedLayoutId);              
            }
            else
              movedLayoutIdFound = true;
          }
          
        change = new ReorderChildrenComponentChange(reorderedIdList);
        rootParent = dropParent;
        ChangeManager cm = RequestContext.getCurrentInstance().getChangeManager();
     
       // add the change
       cm.addComponentChange(FacesContext.getCurrentInstance(),rootParent, change);
          
       // apply the change to the component tree immediately
       change.changeComponent(rootParent);
          
       // redraw the shared parent
       AdfFacesContext.getCurrentInstance().addPartialTarget(rootParent);
          
       return DnDAction.MOVE;
       }
       else
       {
          return DnDAction.NONE;      
       }
     }
    
  5. 「コンポーネント」ウィンドウで、「操作」パネルの「ドラッグ・アンド・ドロップ」グループから、「コンポーネント・ドラッグ元」をドラッグし、ページのソース・コンポーネントに子としてドロップします。

    たとえば、componentDragSourceタグは次のようになります。

    <af:componentDragSource discriminant="col2"/>
    

36.6 panelDashboardコンポーネントでのドラッグ・アンド・ドロップ機能の追加

デフォルトで、panelDashboardコンポーネントではそれ自体の内部でのコンポーネントのドラッグ・アンド・ドロップがサポートされています。つまり、panelDashboardコンポーネントでは、リスナーを実装したり、追加のタグを使用したりする必要なしに、内部のコンポーネントを並べ替えることができます。ただし、panelDashboardコンポーネントにコンポーネントをドラッグ、またはpanelDashboardコンポーネントからコンポーネントをドラッグできるようにする場合は、タグを使用し、リスナーを実装する必要があります。コンポーネントのドラッグ・アンド・ドロップをするため、panelDashboardへのドラッグの際には、componentDragSourceタグを使用します。ただし、panelDashboardではすでにドロップ・ターゲットになることがサポートされているため、dropTargetタグを使用する必要はありません。かわりに、識別値の付いたdataFlavorを使用する必要があります。タグおよび識別値は、フレームワークにそのドロップが外部コンポーネントからのものであることを知らせます。

panelDashboardからのコンポーネントのドラッグは、他のコンポーネントのドラッグ・アンド・ドロップとほとんど同じです。ターゲットにはdropTargetタグを、ソースにはcomponentDragSourceタグを使用します。ただし、dataFlavorタグと識別値も使用する必要があります。

36.6.1 a panelDashboardコンポーネントへのドラッグ・アンド・ドロップ機能の追加方法

panelDashboardコンポーネントには、ダッシュボード内のpanelBoxコンポーネントの並替えに使用するドラッグ・アンド・ドロップ機能が組み込まれているため、dropTargetタグを使用する必要はありませんが、識別値の付いたdataFlavorタグを使用し、dropListenerを実装する必要があります。その実装では、コンポーネントの並替えを処理する必要があります。

始める前に:

ドラッグ・アンド・ドロップ機能について理解しておくと役立ちます。詳細は、36.6項「panelDashboardコンポーネントでのドラッグ・アンド・ドロップ機能の追加」を参照してください。

他のADF Faces機能を使用して追加できる機能について理解することが役立つ場合もあります。詳細は、36.1.1項「ドラッグ・アンド・ドロップの追加機能」を参照してください。

始める前に:

  1. panelDashboardコンポーネントを作成します。詳細は、9.8項「ダッシュボードでのコンテンツの配置」を参照してください。

  2. panelBoxコンポーネントを含むpanelDashboardの外にもう1つのコンポーネントを作成します。panelBoxコンポーネントの詳細は、9.9.3項「panelBoxコンポーネントの使用方法」を参照してください。

panelDashboardコンポーネントにドラッグ・アンド・ドロップ機能を追加する手順:

  1. 構造ウィンドウで、ターゲット・コンポーネントとなる「panelDashboard」コンポーネントを選択します。

  2. 「プロパティ」ウィンドウで、「DropListener」に、マネージドBean上でドロップ・イベントを処理するメソッド(このコードはステップ6で作成)として評価される式を入力します。

  3. 「コンポーネント」ウィンドウの「ドラッグ・アンド・ドロップ」グループで、「データ・フレーバ」をドラッグし、panelDashboardコンポーネントに子としてドロップします。

  4. 「データ・フレーバの挿入」ダイアログで、javax.faces.component.UIComponentを入力します。

  5. 「プロパティ」ウィンドウで、Discriminantを、panelDashboardコンポーネントへのドラッグを許可されたコンポーネントを識別する一意の名前(dragIntoDashboardなど)に設定します。

  6. 「コンポーネント」ウィンドウで、「操作」パネルの「ドラッグ・アンド・ドロップ」グループで、「コンポーネント・ドラッグ元」をドラッグし、ソース・コンポーネントになるpanelBoxコンポーネントの子としてドロップします。

  7. 「プロパティ」ウィンドウで、「Discriminant」をステップ5「panelDashboard」上の「Discriminant」に入力したのと同じ値になるように設定します。

36.6.2 panelDashboardコンポーネントからのドラッグ・アンド・ドロップ機能の追加方法

panelDashboardコンポーネントからのドラッグ・アンド・ドロップ機能の実装は、識別値付きのdataFlavorタグを使用する必要があることを除けば、その他のコンポーネントの標準のドラッグ・アンド・ドロップ機能と同様です。

始める前に:

ドラッグ・アンド・ドロップ機能について理解しておくと役立ちます。詳細は、36.6項「panelDashboardコンポーネントでのドラッグ・アンド・ドロップ機能の追加」を参照してください。

他のADF Faces機能を使用して追加できる機能について理解することが役立つ場合もあります。詳細は、36.1.1項「ドラッグ・アンド・ドロップの追加機能」を参照してください。

panelDashboardコンポーネントからドラッグ・アンド・ドロップ機能を追加する方法:

  1. 「コンポーネント」ウィンドウで、「操作」パネルの「ドラッグ・アンド・ドロップ」グループから、「ドロップ・ターゲット」をドラッグし、ターゲット・コンポーネントに子としてドロップします。

  2. 「ドロップ・ターゲットの挿入」ダイアログで、イベントを処理するマネージドBeanのメソッド(このコードはステップ5で作成)に評価される式を入力し、javax.faces.component.UIComponentを「FlavorClass」として入力します。

  3. dropTargetタグを選択した状態のまま、「プロパティ」ウィンドウでaction属性の値としてMOVEを選択します。

  4. 構造ウィンドウで、「dataFlavor」タグを選択し、「プロパティ」ウィンドウで、「Discriminant」をこのコンポーネントへのドラッグを許可されたpanelBoxコンポーネントを識別する一意の名前(dragOutOfDashboardなど)に設定します。

  5. ステップ2で作成したEL式で参照されるマネージドBeanに、ドラッグ・アンド・ドロップ機能を処理するイベント・ハンドラ・メソッドを(EL式での名前と同じ名前を使用して)dropListener属性に対して作成します。

    このハンドラ・メソッドでは、DropEventイベントを使用してTransferableオブジェクトとそのデータを取得し、移動を完了して、必要に応じてコンポーネントを並べ替えます。ドロップを完了したら、メソッドではNONEのDnDActionを返します。

    dashboardComponent.prepareOptimizedEncodingOfDeletedChild()メソッドを使用して、panelBoxコンポーネントの削除をアニメーション化できます。

    例36-8に、デモ・アプリケーションでdashboard JSFページにより使用されるoracle.adfdemo.view.layout.DemoDashboardBean.javaマネージドBeanでのhandleSideBarDropイベント・ハンドラおよびヘルパー・メソッドを示します。

    例36-8 panelDashboardからpanelBoxを移動するdropListenerのイベント・ハンドラのコード

    public DnDAction handleSideBarDrop(DropEvent e)
      {
        UIComponent dragComponent = e.getDragComponent();
        UIComponent dragParent    = dragComponent.getParent();
        // Ensure that the drag source is one of the items from the dashboard:
        if (dragParent.equals(_getDashboard()))
        {
          _minimize(dragComponent);
        }
        return DnDAction.NONE; // the client is already updated, so no need to redraw it again
    }
    
    private void _minimize(UIComponent panelBoxToMinimize)
      {
        // Make this panelBox non-rendered:
        panelBoxToMinimize.setRendered(false);
     
        // If the dashboard is showing, let's perform an optimized render so the whole dashboard doesn't
        // have to be re-encoded.
        // If the dashboard is hidden (because the panelBox is maximized), we will not do an optimized
        // encode since we need to draw the whole thing.
        if (_maximizedPanelKey == null)
        {
          int deleteIndex = 0;
          RichPanelDashboard dashboard = _getDashboard();
          List<UIComponent> children = dashboard.getChildren();
          for (UIComponent child : children)
          {
            if (child.equals(panelBoxToMinimize))
            {
              dashboard.prepareOptimizedEncodingOfDeletedChild(
                FacesContext.getCurrentInstance(),
                deleteIndex);
              break;
            }
            if (child.isRendered())
            {
              // Only count rendered children since that's all that the panelDashboard can see:
              deleteIndex++;
            }
          }
        }
        RequestContext rc = RequestContext.getCurrentInstance();
        if (_maximizedPanelKey != null)
        {
          // Exit maximized mode:
          _maximizedPanelKey = null;
          UIXSwitcher switcher = _getSwitcher();
          switcher.setFacetName("restored");
          rc.addPartialTarget(switcher);
        }
        // Redraw the side bar so that we can update the colors of the opened items:
        rc.addPartialTarget(_getSideBarContainer());
    }
    
  6. 「コンポーネント」ウィンドウで、「操作」パネルから、「コンポーネント・ドラッグ元」を、panelDashboardコンポーネント内のソースとなるpanelBoxコンポーネントの子としてドラッグ・アンド・ドロップします。

  7. 「プロパティ」ウィンドウで、「Discriminant」をステップ4でターゲット・コンポーネントのdataFlavorタグ上の「Discriminant」に入力したのと同じ値になるように設定します。

36.7 Calendarへのドラッグ・アンド・ドロップ機能の追加

Calendarには、ユーザーがアクティビティのハンドルをドラッグして終了時間を変更できる機能が含まれています。ただし、ユーザーがアクティビティを別の開始時間、さらには別の日にドラッグ・アンド・ドロップできるようにする場合は、ドラッグ・アンド・ドロップ機能を実装します。ドラッグ・アンド・ドロップを使用すると、アクティビティを移動できるだけでなく、コピーすることもできます。

36.7.1 Calendarへのドラッグ・アンド・ドロップ機能の追加方法

calendarDropTargetタグを使用して、ドラッグ・アンド・ドロップ機能を追加します。コレクションをドラッグ・アンド・ドロップするのと異なり、ソース・タグの必要はなく、アクティビティの移動はターゲット(アクティビティの移動先のオブジェクト、この場合はカレンダ)の役割です。ソース(移動またはコピーされるアイテム)がカレンダ内のアクティビティである場合、calendarDropTargetタグのみを使用します。タグでは、TransferableオブジェクトはCalendarActivityオブジェクトになります。

ただし、Calendarの外からオブジェクトをドラッグ・アンド・ドロップすることもできます。この操作を有効にする場合は、ソース・オブジェクト(calendarActivityオブジェクト以外のオブジェクト)をドロップできるように構成されているdataFlavorタグを使用します。

始める前に:

ドラッグ・アンド・ドロップ機能について理解しておくと役立ちます。詳細は、36.7項「Calendarへのドラッグ・アンド・ドロップ機能の追加」を参照してください。

他のADF Faces機能を使用して追加できる機能について理解することが役立つ場合もあります。詳細は、36.1.1項「ドラッグ・アンド・ドロップの追加機能」を参照してください。

Calendarにドラッグ・アンド・ドロップ機能を追加する手順:

  1. 「コンポーネント」ウィンドウで、「操作」パネルの「ドラッグ・アンド・ドロップ」グループから、「カレンダ・ドロップ・ターゲット」をドラッグし、calendarコンポーネントに子としてドロップします。

  2. 「Calendarドロップ・ターゲットの挿入」ダイアログで、イベントを処理するマネージドBeanのメソッドに対して評価されるdropListener属性の式を入力します(このコードは手順4で作成)。

  3. 「プロパティ」ウィンドウで、「処理」を設定します。この値で、アクティビティ(または他のソース)の移動、コピー、リンクとしてコピー、またはこの3つの任意の組合せを実行できるかどうかが決まります。アクションを指定しない場合、デフォルトはCOPYです。

  4. ステップ2でEL式に挿入されたマネージドBeanに、ドロップ・イベントのハンドラを実装します。

    このメソッドでは、DropEventイベントをパラメータとして使用し、DnDActionを返す必要があります。DnDActionは、ソースをドロップするときに実行されるアクションです。有効な戻り値は、COPYMOVEおよびLINKで、ステップ3actions属性を定義するときに設定されます。このメソッドでは、DropEventを使用してTransferableオブジェクトを取得し、そこからドラッグされたデータ内のCalendarModelオブジェクトにアクセスし、そこから実際のデータのアクセスします。その結果、リスナーではそのデータをソースのモデルに追加してから、実行したDnDAction (DnDAction.COPYDnDAction.MOVEまたはDnDAction.LINK)を返し、そうでない場合は、DnDAction.NONE返して、ドロップが拒否されたことを示します。

    ドロップ・イベントのドロップ・サイトは、oracle.adf.view.rich.dnd.CalendarDropSiteクラスのインスタンスです。Calendarのドラッグ・アンド・ドロップ・ハンドラの例は、ADF Facesデモ・アプリケーションのoracle.adfdemo.view.calendar.rich.DemoCalendarBeanマネージドBeanのhandleDropメソッドを参照してください。

  5. アクティビティのソースがカレンダの外部にある場合は、「データ・フレーバ」をドラッグし、子として「calendarDropTarget」タグにドロップします。このタグにより、ターゲットにドロップできるオブジェクトの型(StringDateオブジェクトなど)が決まります。1つのドロップ・ターゲットに複数のdataFlavorタグを使用し、ドロップ・ターゲットでこれらの型のいずれも受け入れるようにすることができます。

  6. 「データ・フレーバの挿入」ダイアログで、ターゲットにドロップ可能なオブジェクトのクラス(java.lang.Objectなど)を入力します。


    ヒント:

    dataFlavorタグに型指定された配列を指定するには、java.lang.Object[]のようにクラス名に大カッコ([])を追加します。


36.7.2 Calendarのドラッグ・アンド・ドロップに関する必知事項

Calendar内のドラッグ・アンド・ドロップ・アクティビティの場合、ユーザーは表示内でのみドラッグ・アンド・ドロップを行うことができます。つまり、ユーザーは、日表示内の1つの時間スロットから別の時間スロットにアクティビティをドラッグできますが、日表示からアクティビティを切り取り、月表示に貼り付けることはできません。

ユーザーが日表示または週表示でアクティビティをドラッグ・アンド・ドロップしている場合、Calendarでは30分ごとにドロップ・サイトがマークされます。日表示では、終日のアクティビティまたは複数日のアクティビティは移動できません。

週表示では、終日のアクティビティおよび複数日のアクティビティを移動できますが、その他の終日のスロットにのみドロップできます。つまり、終日のアクティビティを、開始時間と終了時間が設定されているアクティビティには変更できません。月表示では、終日のアクティビティおよび複数日のアクティビティを任意の日に移動できます。

36.8 DVTコンポーネントのドラッグ・アンド・ドロップ機能の追加

次のDVTコンポーネントのドラッグ・アンド・ドロップ機能を構成できます。

DVTコンポーネントは基本的に、他のADF Facesコンポーネントのドラッグ・アンド・ドロップと同じプロセスを使用します。ただし、DVTコンポーネントではコンポーネントからドラッグしてドロップできる項目に制約がある場合があります。

オブジェクトまたはコレクションのドラッグ・アンド・ドロップ同様、dropListenerハンドラを実装する必要もあります。ドロップ・イベントのオブジェクトはTransferableと呼ばれ、ドロップのペイロードを含みます。リスナーはTransferableオブジェクトにアクセスし、ここからDataFlavorオブジェクトを使用してオブジェクトがドロップ可能なことを確認します。その後、ドロップ・イベントを使用してターゲット・コンポーネントを取得し、ドロップされたオブジェクトを使用してプロパティを更新します。

36.8.1 DVTグラフのドラッグ・アンド・ドロップ機能の追加

DVTバブル・グラフおよび散布図のドラッグ・アンド・ドロップを構成でき、それにより、ユーザーはマーカーを再配置することで、マーカーの値を変更できます。ユーザーがグラフでドラッグ・アンド・ドロップできるようにする場合、dragSourceタグとdropTargetタグを使用します。また、DataFlavorオブジェクトを使用して、ドロップ・ターゲットに対して有効なソースのJava型を決めます(この場合はGraphSelectionSetオブジェクト)。ドラッグ・アンド・ドロップ・アクションを受けて必要となる機能の実装も必要です。

たとえば、bubbleGraphコンポーネントがあり、図36-5で示すように、従業員の職能評定を調整するために、ユーザーが人型のマーカーをドラッグできるようにします。

図36-5 オブジェクトのドラッグ・アンド・ドロップ

オブジェクトのドラッグ・アンド・ドロップ

bubbleGraphコンポーネントには、dragSourceタグとdropTargetタグの両方が含まれます。また、dataFlavorタグを使用して、ドロップされるオブジェクトの型を決めます。

ドロップ・イベントのリスナーも実装する必要があります。ドロップ・イベントのオブジェクトはTransferableと呼ばれ、ドロップのペイロードを含みます。リスナーはTransferableオブジェクトにアクセスし、ここからDataFlavorオブジェクトを使用してオブジェクトがドロップ可能なことを確認します。その後、ドロップ・イベントを使用してターゲット・コンポーネントを取得し、ドロップされたオブジェクトを使用してプロパティを更新します。

36.8.1.1 DVTグラフのドラッグ・アンド・ドロップ機能の追加方法

ドラッグ・アンド・ドロップ機能を追加するには、まずソース・タグとターゲット・タグをグラフに追加します。次に、ドラッグ・アンド・ドロップ・アクションのロジックを処理するイベント・ハンドラ・メソッドを実装します。実行時の処理の詳細は、36.3.2項「実行時の処理: キーボード修飾子の使用方法」を参照してください。

ドラッグ・アンド・ドロップ機能を追加する手順:

  1. 「コンポーネント」ウィンドウで、「操作」パネルから、「ドロップ・ターゲット」タグをドラッグし、子としてグラフ・コンポーネントにドロップします。

  2. 「ドロップ・ターゲットの挿入」ダイアログで、イベントを処理するマネージドBeanのメソッド(このコードはステップ6で作成)に評価される式を入力します。

  3. 「データ・フレーバの挿入」ダイアログで、ターゲットにドロップできるオブジェクトのクラス、oracle.adf.view.faces.bi.component.graph.GraphSelectionSetを入力します。このエントリは、dataFlavorタグを作成するために使用され、このタグにより、ターゲットにドロップできるオブジェクトの型が決まります。

  4. 「プロパティ」ウィンドウで、必要に応じて識別値の値を設定します。識別値は、ターゲットにドロップできるソースを判断するために使用される任意の文字列です。たとえば、どちらもGraphSelectionSetオブジェクトを受け入れるGraphAとGraphBの2つのグラフがあるとします。GraphSelectionSetオブジェクトの2つのソースもあるとします。GraphAにalphaという値を使用して識別値を設定することにより、識別値alphaを持つGraphSelectionSetソースのみが受け入れられます。

  5. 構造ウィンドウで、dropTargetタグを選択します。「プロパティ」ウィンドウにおいて、「アクション」フィールドに、ドロップ・ターゲットが受け入れる操作のリストを、空白で区切って入力します。許容値は、COPY(コピーして貼付け)、MOVE(切り取って貼付け)またはLINK(コピーしてリンクとして貼付け)です。I値を指定しない場合、ドロップ・ターゲットはCOPYを使用します。

    たとえば、図36-5で人のマーカーを別の値に変更するには、ドロップ・ターゲットの「処理」フィールドはMOVEに設定されます。

  6. 「コンポーネント」ウィンドウで、「操作」パネルから、「ドラッグ元」をドラッグし、子としてグラフ・コンポーネントにドロップします。

  7. 構造ウィンドウで、dragSourceタグを選択します。「プロパティ」ウィンドウにおいて、「処理」フィールドに、ドラッグ元がサポートする操作のリストを、空白で区切って入力します。許容値は、COPYMOVEまたはLINKです。値を指定しないと、ドラッグ元はCOPYを使用します。dataFlavorタグに設定されているように、必要な識別値を追加します。

    たとえば、図36-5で人のマーカーを別の値に変更するには、ドラッグ元の「処理」フィールドはMOVEに設定されます。

  8. ステップ2で作成したEL式で参照されるマネージドBeanに、ドラッグ・アンド・ドロップ機能を処理するイベント・ハンドラ・メソッドを(EL式での名前と同じ名前を使用して)作成します。

    このメソッドでは、パラメータとしてDropEventイベントをとり、DnDActionオブジェクトを返す必要があり、これはソースをドロップするときに実行されるアクションです(この例ではDnDAction.MOVE)。このメソッドでは、DropEventイベントをチェックし、ドロップを受け入れるかどうか判断する必要があります。ドロップを受け入れる場合、メソッドではドロップを実行し、実行したDnDActionオブジェクトを返します。そうでない場合は、ドロップが拒否されたことを示すDnDAction.NONEを返します。このメソッドでは、dataFlavorオブジェクトの存在も確認する必要があります(この例ではoracle.adf.view.faces.bi.component.graph.GraphSelectionSet)。

36.8.2 DVTガント・チャートのドラッグ・アンド・ドロップ機能の追加

ユーザーがガント・チャートとその他のコンポーネントとの間でドラッグ・アンド・ドロップできるようにする場合、dragSourceタグとdropTargetタグを使用します。また、DataFlavorオブジェクトを使用して、ドロップ・ターゲットに対して有効なソースのJava型を決めます。ドラッグ・アンド・ドロップ・アクションを受けて必要となる機能の実装も必要です。projectGanttおよびschedulingGanttコンポーネントでは、ドラッグ・アンド・ドロップ機能がサポートされています。

たとえば、図36-6に示すように、projectGanttコンポーネントがあり、ユーザーが時間バケットをtreeTableコンポーネントにドラッグできるようにして、そのコンポーネントに時間バケットについての情報を表示させるとします。

図36-6 オブジェクトのドラッグ・アンド・ドロップ

オブジェクトのドラッグ・アンド・ドロップ

projectGanttコンポーネントにはdragSourceタグが含まれます。ユーザーは、表示された出力テキストのString値のみでなく、オブジェクト全体をドラッグするため、attributeDropTargetタグのかわりにdropTargetタグを使用します。

また、dataFlavorタグを使用して、ドロップされるオブジェクトの型を決めます。このタグでは、識別値を定義できます。同じオブジェクト型の2つのターゲットと2つのソースがある場合に、これは有用です。識別値を作成することで、各ターゲットで有効なソースのみが受け入れられることが保証されます。たとえば、TaskDragInfoオブジェクトを受け入れるTargetAとTargetBの2つのターゲットがあるとします。TaskDragInfoブジェクトのソースも2つあるとします。TargetAにalphaという値を使用して識別値を設定することにより、識別値alphaを持つTaskDragInfoソースのみが受け入れられます。

ドロップ・イベントのリスナーも実装する必要があります。ドロップ・イベントのオブジェクトはTransferableと呼ばれ、ドロップのペイロードを含みます。リスナーはTransferableオブジェクトにアクセスし、ここからDataFlavorオブジェクトを使用してオブジェクトがドロップ可能なことを確認します。その後、ドロップ・イベントを使用してターゲット・コンポーネントを取得し、ドロップされたオブジェクトを使用してプロパティを更新します。

36.8.2.1 DVTコンポーネントのドラッグ・アンド・ドロップ機能の追加方法

ドラッグ・アンド・ドロップ機能を追加するには、まず、コンポーネントをドラッグ・アンド・ドロップ・アクションのターゲットとして定義するタグをコンポーネントに追加します。次に、ドラッグ・アンド・ドロップ・アクションのロジックを処理するイベント・ハンドラ・メソッドを実装します。最後に、ドラッグ・アンド・ドロップのソースを定義します。実行時に行われる処理の詳細は、36.3.2項「実行時の処理: キーボード修飾子の使用方法」を参照してください。clientDropListener属性の使用方法の詳細は、36.3.3項「ClientDropListenerの使用に関する必知事項」を参照してください。

ドラッグ・アンド・ドロップ機能を追加する手順:

  1. 「コンポーネント」ウィンドウで、「操作」パネルから、「ドロップ・ターゲット」タグをドラッグし、子としてターゲット・コンポーネントにドロップします。

  2. 「ドロップ・ターゲットの挿入」ダイアログで、イベントを処理するマネージドBeanのメソッド(このコードはステップ6で作成)に評価される式を入力します。


    ヒント:

    clientDropListener属性を挿入して、クライアントでドロップを捕捉することもできます。詳細は、36.3.3項「ClientDropListenerの使用に関する必知事項」を参照してください。


  3. 「データ・フレーバの挿入」ダイアログで、ターゲットにドロップ可能なオブジェクトのクラス(java.lang.Objectなど)を入力します。この選択は、dataFlavorタグを作成するために使用され、このタグにより、ターゲットにドロップできるオブジェクトの型が決まります。1つのドロップ・ターゲットに複数のdataFlavorタグを使用し、ドロップ・ターゲットでこれらの型のいずれも受け入れるようにすることができます。


    ヒント:

    DataFlavorタグに型指定された配列を指定するには、java.lang.Object[]のようにクラス名に大カッコ([])を追加します。


  4. 「プロパティ」ウィンドウで、必要に応じて識別値の値を設定します。識別値は、dataFlavorで指定されたタイプのどのソースがソースとして受け入れられるかを判断するために使用される任意の文字列です。

  5. 構造ウィンドウで、dropTargetタグを選択します。「プロパティ」ウィンドウで、「処理」の値を選択します。これによって、ドロップ・ターゲットでサポートされるアクションが定義されます。有効な値は、COPY(コピーして貼付け)、MOVE(切り取って貼付け)およびLINK(コピーしてリンクとして貼付け)です。

    MOVE COPY
    

    アクションが指定されない場合、デフォルトはCOPYです。

    例36-9に、ドロップ・ソースとしてTaskDragInfoオブジェクトをとるdropTargetコンポーネントのコードを示します。actions属性の値としてCOPYが設定されているため、それが許可される唯一のアクションになります。

    例36-9 dropTargetタグのJSPコード

    <af:treeTable id="treeTableDropTarget"
                  var="task" value="#{projectGanttDragSource.treeTableModel}">
      <f:facet name="nodeStamp">
        <af:column headerText="Task Name">
          <af:outputText value="#{task.taskName}"/>
        </af:column>
      </f:facet>
      <af:column headerText="Resource">
        <af:outputText value="#{task.resourceName}"/>
      </af:column>
      <af:column headerText="Start Date">
        <af:outputText value="#{task.startTime}"/>
      </af:column>
      <af:column headerText="End Date">
        <af:outputText value="#{task.endTime}"/>
      </af:column>
      <af:dropTarget actions="COPY"
                     dropListener="#{projectGanttDragSource.onTableDrop}">
        <af:dataFlavor flavorClass=
                    "oracle.adf.view.faces.bi.component.gantt.TaskDragInfo"/>
      </af:dropTarget>
    </af:treeTable>
    
  6. ステップ2で作成したEL式で参照されるマネージドBeanに、ドラッグ・アンド・ドロップ機能を処理するイベント・ハンドラ・メソッドを(EL式での名前と同じ名前を使用して)作成します。

    このメソッドでは、パラメータとしてDropEventイベントをとり、DnDActionオブジェクトを返す必要があり、これはソースをドロップするときに実行されるアクションです。有効な戻り値は、DnDAction.COPYDnDAction.MOVEおよびDnDAction.LINKで、ステップ5でターゲット属性を定義したときに設定されたものです。このメソッドでは、DropEventイベントをチェックし、ドロップを受け入れるかどうか判断する必要があります。ドロップを受け入れる場合、メソッドではドロップを実行し、実行したDnDActionオブジェクトを返します。そうでない場合は、ドロップが拒否されたことを示すDnDAction.NONEを返します。

    このメソッドでは、各dataFlavorオブジェクトの存在も優先順に確認される必要があります。


    ヒント:

    ターゲットに複数のdataFlavorオブジェクトが定義されている場合、Transferable.getSuitableTransferData()メソッドを使用できます。このメソッドでは、Transferableオブジェクトで使用可能なTransferDataオブジェクトのListが適合性の高いものから順に返されます。


    DataFlavorオブジェクトでは、ドロップされるデータの型(java.lang.Objectなど)が定義されます。これは、手順3で作成したJSPのDataFlavorタグでの定義と同じである必要があります。


    ヒント:

    DataFlavorオブジェクトに型指定された配列を指定するには、java.lang.Object[]のようにクラス名に大カッコ([])を追加します。

    DataFlavorオブジェクトではポリモフィズムがサポートされるため、ドロップ・ターゲットでjava.util.Listが受け入れられる場合、Transferableオブジェクトにjava.util.ArrayListを含むドロップは正常終了します。同様に、この機能ではArraysListsとの間の自動変換もサポートされます。

    ドラッグ・アンド・ドロップ・フレームワークで、サーバーのDataFlavorオブジェクトをクライアント・コンポーネントで表す方法がわからない場合、すべてのドロップがクライアントで正常終了するようドロップ・ターゲットが構成されます。


    例36-10に、イベント・ペイロードからTaskDragInfoオブジェクトをコピーし、そのイベントを開始したコンポーネントに割り当てるハンドラ・メソッドを示します。

    例36-10 dropListenerのイベント・ハンドラ・コード

    public DnDAction onTableDrop(DropEvent evt)
    { 
      // retrieve the information about the task dragged
      DataFlavor<TaskDragInfo> _flv = DataFlavor.getDataFlavor(TaskDragInfo.class, null);
      Transferable _transferable = evt.getTransferable();
     
      // if there is no data in the Transferable, then the drop is unsuccessful 
      TaskDragInfo _info = _transferable.getData(_flv);
      if (_info == null)
        return DnDAction.NONE;
     
      // find the task
      Task _draggedTask = findTask(_info.getTaskId());
      if (_draggedTask != null) {
      // process the dragged task here and indicate the drop is successful by returning DnDAction.COPY
       return DnDAction.COPY;
      }
      else
    return DnDAction.NONE;
    }
    
  7. 「コンポーネント」ウィンドウで、「操作」パネルから、「ドラッグ元」をドラッグし、子としてソース・コンポーネントにドロップします。

  8. dragSourceタグを選択している場合、「プロパティ」ウィンドウで、ターゲットに構成される、許容処理と必要な識別値を設定します。

36.8.3 DVT階層ビューア、サンバースト、およびツリーマップにドラッグ・アンド・ドロップ機能を追加する

階層ビューア、サンバースト、およびツリーマップを、ページ上でサポートされたコンポーネント間のドラッグ・アンド・ドロップ操作のドラッグ・ソース、およびドロップ・ターゲットとして構成できます。

36.8.3.1 DVT階層ビューアのドラッグ・アンド・ドロップの例

階層ビューアは、次のドラッグ・アンド・ドロップ操作をサポートします。

  • 階層ビューア内で、1つ以上のノードをドラッグ・アンド・ドロップします

  • 階層ビューアから1つ以上のノードを別のコンポーネントにドラッグします

  • 別のコンポーネントから階層ビューアに1つ以上のアイテムをドラッグします

図36-7に、その中でのドラッグ・アンド・ドロップを可能とするように構成した階層ビューアを示します。ノードをクリックし0.5秒を超えて保持すると、バックグラウンドにドラッグして階層内の別のルートにしたり、別のノードにドラッグしてそのノードの子として追加したりすることができます。

図36-7 ノード・ドラッグを示す階層ビューア

ノード・ドラッグを示す階層ビューア

この例では、ノードを別のノードにドラッグすると、ドラッグされたノードとその子は、ターゲット・ノードの子となります。図36-8に、Nina Evansのデータを含むノードへのドラッグの結果を示します。Nancy Greenとその部下は、今はNina Evansの部下として示されます。

図36-8 別のノードへのノード・ドラッグ後の階層ビューア

別のノードへのノード・ドラッグ後の階層ビューア

36.8.3.2 DVTサンバーストのドラッグ・アンド・ドロップの例

サンバーストは、1つ以上のノードの別コンポーネントへのドラッグをサポートします。ドラッグのペイロードは、org.apache.myfaces.trinidad.model.RowKeySetです。サンバーストが別のオブジェクトからのドロップを受け入れるように構成することもできます。

図36-9に、それからaf:outputFormattedコンポーネントへのドラッグを可能とするように構成されたサンバーストを示します。サンバーストが複数選択が可能なように構成されている場合、ユーザーは複数のノードをCtrl+D操作でドラッグできます。

図36-9 ドラッグ・ソースとして構成されたサンバースト

ドラッグ・ソースとして構成されたサンバースト

36.8.3.3 DVTツリーマップのドラッグ・アンド・ドロップの例

ツリーマップは、1つ以上のノードの別コンポーネントへのドラッグをサポートします。ドラッグのペイロードは、org.apache.myfaces.trinidad.model.RowKeySetです。ツリーマップが別のオブジェクトからのドロップを受け入れるように構成することもできます。

図36-10に、ドロップ・ターゲットとして構成されたツリーマップを示します。この例では、ドラッグ・ソースはaf:outputFormattedコンポーネントです。

図36-10 ドロップ・ターゲットとして構成されたツリーマップ

ドロップ・ターゲットとして構成されたツリーマップ

36.8.3.4 DVT階層ビューア、サンバースト、またはツリーマップ・コンポーネントのドラッグ・アンド・ドロップ機能の追加方法

ドラッグ・アンド・ドロップの機能を追加するには、第一に、サポート対象のDVTコンポーネントに、ドラッグ・アンド・ドロップ・アクションのターゲットとしてそれを定義しているタグを追加します。次に、ドラッグ・アンド・ドロップ・アクションのロジックを処理するイベント・ハンドラ・メソッドを実装します。最後に、ドラッグ・アンド・ドロップのソースを定義します。実行時に行われる処理の詳細は、36.3.2項「実行時の処理: キーボード修飾子の使用方法」を参照してください。clientDropListener属性の使用方法の詳細は、36.3.3項「ClientDropListenerの使用に関する必知事項」を参照してください。

始める前に:

ドラッグ・アンド・ドロップ機能について理解しておくと役立ちます。詳細は、36.1項「ドラッグ・アンド・ドロップ機能について」を参照してください。

次のタスクを実行する必要があります。

  • DVTコンポーネントをユーザーのページに加えます。

    DVTコンポーネント作成時のヘルプについては、第22章「ADFデータ視覚化コンポーネントの概要」を参照してください。

  • DVTコンポーネントへのドロップを可能にする予定であれば、ドラッグ・ソースとするコンポーネントをページに加えます。

    他のADF Facesコンポーネント追加の詳細は、第1.3項「ADF Facesコンポーネント」を参照してください。

  • DVTコンポーネントから別のコンポーネントヘのドラッグを可能にする予定であれば、ドロップ・ターゲットとするコンポーネントをページに加えます。

DVT階層ビューア、サンバースト、あるいはツリーマップ・コンポーネントにドラッグ・アンド・ドロップ機能を追加するには:

  1. DVTコンポーネントをドロップ・ターゲットとして構成するには、次を実行します。

    1. 「コンポーネント」ウィンドウで、「操作」パネルから、「ドロップ・ターゲット」タグをドラッグし、ドラッグ・アンド・ドロップをサポートするDVTコンポーネントの子としてドロップします。

    2. 「ドロップ・ターゲットの挿入」ダイアログで、イベントを処理するマネージドBean上のドロップ・リスナー・メソッド(このコードはステップ6で作成)に評価される式を入力します。


      ヒント:

      clientDropListener属性を挿入して、クライアントでドロップを捕捉することもできます。詳細は、36.3.3項「ClientDropListenerの使用に関する必知事項」を参照してください。


    3. 「データ・フレーバの挿入」ダイアログで、ターゲットにドロップ可能なオブジェクトのクラス(java.lang.Objectなど)を入力します。この選択は、dataFlavorタグを作成するために使用され、このタグにより、ターゲットにドロップできるオブジェクトの型が決まります。1つのドロップ・ターゲットに複数のdataFlavorタグを使用し、ドロップ・ターゲットでこれらの型のいずれも受け入れるようにすることができます。


      ヒント:

      DataFlavorタグに型指定された配列を指定するには、java.lang.Object[]のようにクラス名に大カッコ([])を追加します。


    4. 「プロパティ」ウィンドウで、必要に応じて識別値の値を設定します。識別値は、ターゲットにドロップできるソースを判断するために使用される任意の文字列です。たとえば、どちらもjava.lang.Objectを受け入れる2つのツリーマップ、ツリーマップAとツリーマップBがあるとします。ソースも2つあり、どちらもjava.lang.Objectオブジェクトです。GraphAにalphaという値を使用して識別値を設定することにより、識別値alphaを持つjava.lang.Objectソースのみが受け入れられます。

    5. 構造ウィンドウで、dropTargetタグを選択します。「プロパティ」ウィンドウで、「処理」の値を選択します。これによって、ドロップ・ターゲットでサポートされるアクションが定義されます。有効な値は、COPY(コピーして貼付け)、MOVE(切り取って貼付け)およびLINK(コピーしてリンクとして貼付け)です。

      MOVE COPY
      

      アクションが指定されない場合、デフォルトはCOPYです。

      例36-11に、java.lang.Objectをドラッグ・ソースとして受け入れるツリーマップ・コンポーネントのコードを示します。「処理」の値としてCOPYが設定されているため、それが許可される唯一のアクションになります。

      例36-11 DVTツリーマップ・コンポーネントのdropTargetタグのJSPコード

      <dvt:treemap id="t1" value="#{treemap.censusData}" var="row"
                   displayLevelsChildren="3" colorLabel="Median Household Income
                   sizeLabel="Population" summary="Treemap Configured as Drag Source"
                   legendSource="ag1">
        <dvt:treemapNode id="tn1" value="#{row.size}" label="#{row.text}">
          <dvt:attributeGroups id="ag1" value="#{row.income > 50000}"
                         label="#{row.income > 50000 ? 'High Income' : 'Low Income'}"
                         type="color"/>
          </dvt:treemapNode>
        <af:dropTarget dropListener="#{treemap.toDropListener}"
                       actions="COPY">
          <af:dataFlavor flavorClass="java.lang.Object"/>
        </af:dropTarget>
      </dvt:treemap>
      
    6. ステップ2で作成したEL式で参照されるマネージドBeanに、ドラッグ・アンド・ドロップ機能を処理するイベント・ハンドラ・メソッドを(EL式での名前と同じ名前を使用して)作成します。

      このメソッドでは、パラメータとしてDropEventイベントをとり、DnDActionオブジェクトを返す必要があり、これはソースをドロップするときに実行されるアクションです。有効な戻り値は、DnDAction.COPYDnDAction.MOVEおよびDnDAction.LINKで、ステップ5でターゲット属性を定義したときに設定されたものです。このメソッドでは、DropEventイベントをチェックし、ドロップを受け入れるかどうか判断する必要があります。ドロップを受け入れる場合、メソッドではドロップを実行し、実行したDnDActionオブジェクトを返します。そうでない場合は、ドロップが拒否されたことを示すDnDAction.NONEを返します。

      このメソッドでは、各dataFlavorオブジェクトの存在も優先順に確認される必要があります。


      ヒント:

      ターゲットに複数のdataFlavorオブジェクトが定義されている場合、Transferable.getSuitableTransferData()メソッドを使用できます。このメソッドでは、Transferableオブジェクトで使用可能なTransferDataオブジェクトのListが適合性の高いものから順に返されます。


      DataFlavorオブジェクトでは、ドロップされるデータの型(java.lang.Objectなど)が定義されます。これは、手順3で作成したJSPのDataFlavorタグでの定義と同じである必要があります。


      ヒント:

      DataFlavorオブジェクトに型指定された配列を指定するには、java.lang.Object[]のようにクラス名に大カッコ([])を追加します。

      DataFlavorオブジェクトではポリモフィズムがサポートされるため、ドロップ・ターゲットでjava.util.Listが受け入れられる場合、Transferableオブジェクトにjava.util.ArrayListを含むドロップは正常終了します。同様に、この機能ではArraysListsとの間の自動変換もサポートされます。

      ドラッグ・アンド・ドロップ・フレームワークで、サーバーのDataFlavorオブジェクトをクライアント・コンポーネントで表す方法がわからない場合、すべてのドロップがクライアントで正常終了するようドロップ・ターゲットが構成されます。


      例36-12に、イベント・ペイロードからjava.lang.Objectオブジェクトをコピーして、イベントを開始したコンポーネントに割り当てるハンドラ・メソッドを示します。

      例36-12 DVTツリーマップのサンプル・ドロップ・リスナー

      // imports needed by methods
      import java.util.Map;
      import oracle.adf.view.rich.dnd.DnDAction;
      import oracle.adf.view.rich.event.DropEvent;
      import oracle.adf.view.rich.datatransfer.DataFlavor;
      import oracle.adf.view.rich.datatransfer.Transferable;
      import org.apache.myfaces.trinidad.context.RequestContext;
      import org.apache.myfaces.trinidad.render.ClientRowKeyManager;
      import javax.faces.context.FacesContext;
      import oracle.adf.view.faces.bi.component.treemap.UITreemap;
      import javax.faces.component.UIComponent;
      // variables need by methods
      private String dragText = "Drag this text onto a node";
      // drop listener
      public DnDAction toDropListener(DropEvent event) {
        Transferable transferable = event.getTransferable();
        DataFlavor<Object> dataFlavor = DataFlavor.getDataFlavor(Object.class);
        Object transferableObj = transferable.getData(dataFlavor);
        if(transferableObj == null)
          return DnDAction.NONE;
        // Build up the string that reports the drop information
        StringBuilder sb = new StringBuilder();
        // Start with the proposed action
        sb.append("Drag Operation: ");
        DnDAction proposedAction = event.getProposedAction();
        if(proposedAction == DnDAction.COPY) {
          sb.append("Copy<br>");
        }
        else if(proposedAction == DnDAction.LINK) {
          sb.append("Link<br>");
        }
        else if(proposedAction == DnDAction.MOVE) {
          sb.append("Move<br>");
        }
        // Then add the rowKeys of the nodes that were dragged
        UIComponent dropComponent = event.getDropComponent();
        Object dropSite = event.getDropSite();
        if(dropSite instanceof Map) {
          String clientRowKey = (String) ((Map) dropSite).get("clientRowKey");
          Object rowKey = getRowKey(dropComponent, clientRowKey);
          if(rowKey != null) {
            sb.append("Drop Site: ");
            sb.append(getLabel(dropComponent, rowKey));
          }
        }
        // Update the output text
        this.dragText = sb.toString();
        RequestContext.getCurrentInstance().addPartialTarget(event.getDragComponent());
        return event.getProposedAction();
      }
      
      public String getDragText() {
        return dragText;
      }
      
      private String getLabel(UIComponent component, Object rowKey) {
        if(component instanceof UITreemap) {
          UITreemap treemap = (UITreemap) component;
          TreeNode rowData = (TreeNode) treemap.getRowData(rowKey);
          return rowData.getText();
        }
        return null;
      }
      
      private Object getRowKey(UIComponent component, String clientRowKey) {
        if(component instanceof UITreemap) {
          UITreemap treemap = (UITreemap) component;
          ClientRowKeyManager crkm = treemap.getClientRowKeyManager();
          return crkm.getRowKey(FacesContext.getCurrentInstance(), component, clientRowKey);
        }
        return null;
      }
      
  2. DVTコンポーネントをドラッグ・ソースとして構成するには、次を実行します。

    1. 「コンポーネント」ウィンドウで、「操作」パネルから、「ドラッグ元」をドラッグし、子としてDVTコンポーネントにドロップします。

    2. dragSourceタグを選択している場合、「プロパティ」ウィンドウで、ターゲットに構成される、許容処理と必要な識別値を設定します。

    例36-13に、ドラッグ・ソースとして構成された、ツリーマップのJSPコードを示します。すべてのアクション(COPYMOVEおよびLINK)が許されることに注意します。

    例36-13 DVTツリーマップのdragSourceタグのJSPサンプル・コード

    <dvt:treemap id="t1" value="#{treemap.censusData}" var="row"
                 displayLevelsChildren="3" colorLabel="Median Household Income
                 sizeLabel="Population" summary="Treemap Configured as Drag Source"
                 legendSource="ag1">
      <dvt:treemapNode id="tn1" value="#{row.size}" label="#{row.text}">
        <dvt:attributeGroups id="ag1" value="#{row.income > 50000}"
                       label="#{row.income > 50000 ? 'High Income' : 'Low Income'}"
                       type="color"/>
        </dvt:treemapNode>
      <af:dragSource defaultAction="MOVE" actions="COPY MOVE LINK"/>
    </dvt:treemap>
    
  3. DVTコンポーネントを別のコンポーネントからのドラッグを可能とするドロップ・ターゲットとして使用するには、「コンポーネント」ウィンドウで、「操作」パネルから「ドラッグ元」を、ドラッグのソースとなるコンポーネントの子としてドラッグ・アンド・ドロップします。

    たとえば、ドラッグ元af:outputFormattedコンポーネントの子としてドラッグ・アンド・ドロップし、ツリーマップに関するノード情報を表示します。dragSourceタグを選択している場合、「プロパティ」ウィンドウで、許容処理とターゲットに必要な識別値を設定します。

  4. DVTコンポーネントを別のサポートされたDVTやADF Facesのコンポーネントのドラッグ・ソースとして追加するには、以下を実行します。

    1. 「コンポーネント」ウィンドウで、「Operations」パネルから、「ドロップ・ターゲット」を、ドロップを受け取るコンポーネント上にドラッグ・アンド・ドロップします。

      たとえば、ドロップ・ターゲットツリー表コンポーネント上にドラッグ・アンド・ドロップします。

    2. 「ドロップ・ターゲットの挿入」ダイアログで、コンポーネントがDVTコンポーネントのドロップへの対応に使用するドロップ・リスナーの名前を入れます。

      サンプルのリスナーについては、この章の例を参照してください。

    3. 「データ・フレーバの挿入」ダイアログで、ドロップ・ターゲットが受け入れるオブジェクトを入れます。または、ドロップダウン・メニューを使用してオブジェクトの階層をナビゲートし、希望するオブジェクトを選択します。

      たとえば、ユーザーがツリーマップ・ノードをtreeTableコンポーネントにドラッグし、そのコンポーネントにツリーマップについての情報を表示できるようにする場合、org.apache.myfaces.trinidad.model.RowKeySetをデータ・フレーバに入れます。

    4. 構造ウィンドウでaf:dropTargetコンポーネントを右クリックし、「プロパティに移動」を選択します。

    5. 「プロパティ」ウィンドウにおいて、「アクション」フィールドに、ドロップ・ターゲットが受け入れる操作のリストを、空白で区切って入力します。許容値は、COPYMOVEまたはLINKです。I値を指定しない場合、ドロップ・ターゲットはCOPYを使用します。

      例36-14に、ツリーマップからのドラッグを可能なように構成したaf:outputFormattedコンポーネントのサンプル・コードを示します。

      例36-14 ツリーマップからaf:outputFormattedコンポーネントへデータをドラッグするJSPサンプル・コード

      <af:outputFormatted value="#{treemap.dropText}" id="of1">
        <af:dropTarget dropListener="#{treemap.fromDropListener}">
          <af:dataFlavor flavorClass="org.apache.myfaces.trinidad.model.RowKeySet"/>
        </af:dropTarget>
      </af:outputFormatted>
      

36.8.4 時系列コンポーネントのドラッグ・アンド・ドロップ機能の追加

時系列は、ページ上のコレクション・コンポーネントとの間のドロップ・ターゲットまたはドラッグ元として構成できます。たとえば、1つのコレクションからアイテム(表の行など)をドラッグして時系列にドロップしたり、時系列からイベントをドラッグして表にドロップしたりできます。

図36-11に、時系列内のイベントと表の行との間でドラッグ・アンド・ドロップができるように構成された時系列を示します。

図36-11 表との間のドラッグ・アンド・ドロップ用に構成された時系列

表との間のドラッグ・アンド・ドロップ用に構成された時系列

ドラッグ・アンド・ドロップの機能を追加するには、第一に、サポート対象のDVTコンポーネントに、ドラッグ・アンド・ドロップ・アクションのターゲットとしてそれを定義しているタグを追加します。次に、ドラッグ・アンド・ドロップ・アクションのロジックを処理するイベント・ハンドラ・メソッドを実装します。最後に、ドラッグ・アンド・ドロップのソースを定義します。実行時に行われる処理の詳細は、36.3.2項「実行時の処理: キーボード修飾子の使用方法」を参照してください。clientDropListener属性の使用方法の詳細は、36.3.3項「ClientDropListenerの使用に関する必知事項」を参照してください。

始める前に:

ドラッグ・アンド・ドロップ機能について理解しておくと役立ちます。詳細は、36.1項「ドラッグ・アンド・ドロップ機能について」を参照してください。

次のタスクを実行する必要があります。

  • DVTコンポーネントをユーザーのページに加えます。

    DVTコンポーネント作成時のヘルプについては、第22章「ADFデータ視覚化コンポーネントの概要」を参照してください。

  • DVTコンポーネントへのドロップを可能にする予定であれば、ドラッグ・ソースとするコンポーネントをページに加えます。

    他のADF Facesコンポーネント追加の詳細は、第1.3項「ADF Facesコンポーネント」を参照してください。

  • DVTコンポーネントから別のコンポーネントヘのドラッグを可能にする予定であれば、ドロップ・ターゲットとするコンポーネントをページに加えます。

時系列にドラッグ・アンド・ドロップ・サポートを追加するには:

  1. 構造ウィンドウでtimelineコンポーネントを右クリックして、「時系列の中に挿入」「ドロップ・ターゲット」と選択します。

  2. 「ドロップ・ターゲットの挿入」ダイアログで、ドロップ・リスナーの名前を入力するか、ドロップダウン・メニューを使用して「編集」を選択し、時系列のマネージドBeanにドロップ・リスナー・メソッドを追加します。または、ドロップダウン・メニューを使用して式ビルダーを選び、ドロップ・リスナーのEL式を入力してください。

    たとえば、dndというマネージドBeanにhandleDropOnTimeline()というメソッドを追加するには、「編集」を選択し、ドロップダウン・メニューから「dnd」を選択して、「メソッド」フィールドの右にある「新規」をクリックし、handleDropOnTimeline()メソッドを作成します。

    例36-15に、図36-11に表示されている時系列のサンプル・ドロップ・リスナーと、それをサポートするメソッドを示します。

    例36-15 時系列のサンプル・ドロップ・リスナー

    // imports needed by methods
    import java.text.DateFormat;
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.ArrayList;
    import java.util.Date;
    import javax.faces.bean.ManagedBean;
    import javax.faces.bean.SessionScoped;
    import javax.faces.bean.RequestScoped;
    import oracle.adf.view.rich.datatransfer.DataFlavor;
    import oracle.adf.view.rich.datatransfer.Transferable;
    import oracle.adf.view.rich.dnd.DnDAction;
    import oracle.adf.view.rich.event.DropEvent;
    import org.apache.myfaces.trinidad.context.RequestContext;
    import org.apache.myfaces.trinidad.model.CollectionModel;
    import org.apache.myfaces.trinidad.model.ModelUtils;
    import org.apache.myfaces.trinidad.model.RowKeySet;
    // drop listener
    public DnDAction handleDropOnTimeline(DropEvent event)
      {
        Date _date = (Date)event.getDropSite();       
        Transferable _transferable = event.getTransferable();
        RowKeySet _rowKeySet = _transferable.getData(DataFlavor.ROW_KEY_SET_FLAVOR);
        Object _rowKey = _rowKeySet.iterator().next();
        EmpEvent _event = (EmpEvent)m_tableModel.getRowData(_rowKey);
        _event.setDate(_date);
        orderInsert(_event);
        RequestContext.getCurrentInstance().addPartialTarget
            (event.getDragComponent());
        return DnDAction.COPY;
      }
      private void orderInsert(EmpEvent event)
      {
        int _index = -1;
        ArrayList _list = (ArrayList)m_timelineModel.getWrappedData();
        for (int i=0; i<_list.size(); i++)
        {
          EmpEvent _current = (EmpEvent)_list.get(i);
          if (event.getDate().before(_current.getDate()))
          {
            _index = i;
            break;
          }
        }
        if (_index == -1)
            _list.add(event);
        else
            _list.add(_index, event);
        ArrayList _list2 = (ArrayList)m_tableModel.getWrappedData();
        _list2.remove(event);                
    }
    
  3. 「OK」をクリックし、「データ・フレーバの挿入」ダイアログに、org.apache.myfaces.trinidad.model.RowKeySetを入力します。

  4. 構造ウィンドウでaf:dropTargetコンポーネントを右クリックし、「プロパティに移動」を選択して、「プロパティ」ウィンドウで次の属性を設定します。

    • Actions: ドロップ・ターゲットが受け入れる操作をスペース区切りのリストで入力します。許容値は、COPYMOVEまたはLINKです。値を指定しない場合、ドロップ・ターゲットはCOPYを使用します。

    • Discriminant: ドロップ・ターゲットとドラッグ元が互換性のために共有するモデル名を指定します。この属性の値は、時系列からドラッグを受けるコレクション・コンポーネントに設定する、af:dragSourceコンポーネントのdiscriminant属性の値に一致する必要があります。

  5. 別のコレクション・コンポーネントを時系列へのドロップのドラッグ元として構成するには、次のようにします。

    1. 「コンポーネント」ウィンドウで、「操作」パネルから、「ドラッグ元」タグをドラッグのソースとなるコンポーネントの子としてドラッグ・アンド・ドロップします。

      たとえば、「ドラッグ元」のタグをaf:tableコンポーネントの子としてドラッグ・アンド・ドロップします。

    2. 「プロパティ」ウィンドウで、コンポーネントの「Actions」フィールドに、ドロップ・ターゲットが受け入れる操作をスペース区切りのリストで入力します。

    3. コンポーネントの「Discriminant」フィールドに、ドロップ・ターゲットとドラッグ元が互換性のために共有するモデル名を指定します。

  6. 時系列をドラッグ元として構成するには、「コンポーネント」ウィンドウの「操作」パネルから、「ドラッグ元」のタグを時系列の子としてドラッグ・アンド・ドロップします。

  7. 構造ウィンドウでaf:dragSourceコンポーネントを右クリックし、「プロパティに移動」を選択して、「プロパティ」ウィンドウで次の属性を設定します。

    • Actions: コレクション・ドロップ・ターゲット・コンポーネントが受け入れる操作をスペース区切りのリストで入力します。

    • Discriminant: ドラッグ元とコレクション・ドロップ・ターゲットが互換性のために共有するモデル名を指定します。この属性の値は、時系列からドラッグを受けるコレクション・コンポーネントに設定する、af:collectionDropTargetコンポーネントのmodelName属性の値に一致する必要があります。

  8. 別のコレクション・コンポーネントを時系列からのドロップのドロップ・ターゲットとして構成するには、次のようにします。

    1. 「コンポーネント」ウィンドウの「操作」パネルで、「コレクション・ドロップ・ターゲット」を、ドロップを受けるコンポーネントにドラッグ・アンド・ドロップします。

      たとえば、「コレクション・ドロップ・ターゲット」を、ドロップの結果を表示するaf:tableコンポーネントの子としてドラッグ・アンド・ドロップします。

    2. ドロップ・ターゲットを挿入ダイアログで、ドロップ・リスナーの名前を入力するか、ドロップダウン・メニューを使用して編集を選び、ドロップ・リスナー・メソッドを適切なマネージドBeanに追加してください。

      例36-16に、図36-11に表示されている時系列のサンプル・ドロップ・リスナーを示します。この例は例36-15で使用されたものと同じインポートとヘルパー・メソッドを使用しており、それらはここには含まれていません。

      例36-16 時系列をドラッグ元として使用する表のサンプル・ドロップ・リスナー

      //Drop Listener
      public DnDAction handleDropOnTable(DropEvent event)
      {
        Integer _dropSite = (Integer)event.getDropSite();
        Transferable _transferable = event.getTransferable();
        RowKeySet _rowKeySet = _transferable.getData(DataFlavor.ROW_KEY_SET_FLAVOR);
        Object _rowKey = _rowKeySet.iterator().next();
        EmpEvent _event = (EmpEvent)m_timelineModel.getRowData(_rowKey);
        ArrayList _list = (ArrayList)m_tableModel.getWrappedData();
        _list.add(_dropSite.intValue(), _event);
        ArrayList _list2 = (ArrayList)m_timelineModel.getWrappedData();
        _list2.remove(_event); 
        RequestContext.getCurrentInstance().addPartialTarget
             (event.getDragComponent());
        return DnDAction.COPY;
      }
      private static Date parseDate(String date)
      {
        Date ret = null;
        try
        {
          ret = s_format.parse(date);
        }
        catch (ParseException e)
        {
          e.printStackTrace();
        }
        return ret;
      }
      
    3. 「OK」をクリックし、「データ・フレーバの挿入」ダイアログに、org.apache.myfaces.trinidad.model.RowKeySetを入力します。

    4. 構造ウィンドウでaf:dropTargetコンポーネントを右クリックし、「プロパティに移動」を選択します。

    5. 「プロパティ」ウィンドウにおいて、「アクション」フィールドに、ドロップ・ターゲットが受け入れる操作のリストを、空白で区切って入力します。

    6. 「ModelName」フィールドに、コレクションのモデルを定義します。modelName属性の値は、互換性の目的でドラッグ元の特定に使用されるStringオブジェクトです。この属性の値は、af:dragSourceコンポーネントのdiscriminant属性の値に一致する必要があります。

例36-17に、図36-11に示すADF Facesデモ・アプリケーションのJSFページのサンプル・コードを示します。af:tableコンポーネントの詳細は、第12章「表、ツリー、およびその他のコレクションベースのコンポーネントの使用」を参照してください。

例36-17 時系列のドロップ・ターゲットとドラッグ元のサンプル・コード

<dvt:timeline id="tl1" startTime="2010-01-01" endTime="2011-12-31"
    inlineStyle="width:800px;height:400px" itemSelection="single">
  <f:attribute name="horizontalFetchSizeOverride" value="3000"/>
  <dvt:timelineSeries id="ts1" var="evt" value="#{dnd.timelineModel}">
    <dvt:timelineItem id="ti1" value="#{evt.date}" group="#{evt.group}">
      <af:panelGroupLayout id="pg1" layout="horizontal">
        <af:image id="img1" inlineStyle="width:30px;height:30px"
            source="/resources/images/timeline/employment.png"/>
        <af:spacer width="3"/>
        <af:panelGroupLayout id="pg2" layout="vertical">
          <af:outputText id="ot1" inlineStyle="color:#084B8A"
              value="#{evt.description}" noWrap="true"/>
          <af:outputText id="ot2" value="#{evt.date}"
              inlineStyle="color:#6e6e6e" noWrap="true">
          <af:convertDateTime dateStyle="medium"/>
          </af:outputText>
        </af:panelGroupLayout>
      </af:panelGroupLayout>
    </dvt:timelineItem>
  <af:dragSource actions="COPY" discriminant="model"/>
  <af:dropTarget actions="COPY" dropListener="#{dnd.handleDropOnTimeline}">
    <af:dataFlavor flavorClass="org.apache.myfaces.trinidad.model.RowKeySet"
        discriminant="model2"/>
  </af:dropTarget>
  </dvt:timelineSeries>
  <dvt:timeAxis id="ta1" scale="weeks"/>
  <dvt:timelineOverview id="ov1">
    <dvt:timeAxis id="ta2" scale="years"/>
  </dvt:timelineOverview
</dvt:timeline>
<af:table var="row" value="#{dnd.tableModel}" rowSelection="single"
    inlineStyle="width:370px;height:400px">
  <af:column headerText="ID" width="20">
    <af:outputText value="#{row.id}"/>
  </af:column>
  <af:column headerText="Event" width="340">
    <af:outputText value="#{row.description}"/>
  </af:column>
  <af:dragSource actions="COPY" discriminant="model2"/>                    
  <af:collectionDropTarget actions="COPY" modelName="model"
      dropListener="#{dnd.handleDropOnTable}"/>
</af:table>