Oracle® Fusion Middleware Oracle Application Development Framework Webユーザー・インタフェース開発者ガイド 11gリリース1 (11.1.1.7.0) B52029-07 |
|
前 |
次 |
この章では、ページにドラッグ・アンド・ドロップ機能を追加する方法について説明します。これにより、コンポーネントの属性やオブジェクトの値を別のコンポーネントにドラッグしたり、コンポーネントをドラッグ・アンド・ドロップしたりすることができます。
この章では、次の項目について説明します。
ADF Facesフレームワークでは、1つのページ上で、ある場所から別の場所にアイテムをドラッグ・アンド・ドロップする機能が提供されます。たとえばファイル・エクスプローラ・アプリケーションでは、ファイルをTableタブからドラッグし、それを図34-1に示すように、別のディレクトリ・フォルダにドロップできます。
このシナリオでは、あるコレクション(Folder0)のオブジェクトを実際にドラッグして、別のコレクション(Folder3)にドロップします。これは、サポートされている数多くのドラッグ・アンド・ドロップ・シナリオの1つです。ADF Facesでは、次のシナリオがサポートされます。
あるコンポーネント・インスタンスの属性値をドラッグして、別のインスタンスにコピーします。たとえば、ユーザーはoutputText
コンポーネントをinputText
コンポーネントにドラッグできます。ドラッグすると、outputText
コンポーネントのtext
属性の値がinputText
コンポーネントのtext
属性の値になります。
あるオブジェクトの値が別のオブジェクトの値になるように、値をドラッグしてドロップします。たとえば、outputText
コンポーネントを別のoutputText
コンポーネントにドラッグできます。ドラッグすると、String
オブジェクトの配列が2番目のoutputText
コンポーネントのtext
属性に移入されます。
図34-1に示すように、あるコレクションのオブジェクトをドラッグして別のコレクションにドロップします。
1つのページ上で、ある場所から別の場所にコンポーネントをドラッグします。たとえば、既存のpanelBox
コンポーネントを、panelGrid
コンポーネント内の新しい場所にドラッグできます。
カレンダのアクティビティを、ある開始日時から別の開始日時にドラッグします。
コンポーネントをpanelDashboard
コンポーネントに(から)ドラッグします。
DVT散布図またはバブル・グラフのマーカーをドラッグして、その値を変更します。
DVTガント・チャートのオブジェクトを別のコンポーネントにドラッグします。
DVTツリーマップとサンバースト・コンポーネントから1つ以上のノードをドラッグするか、DVTツリーマップとサンバースト・コンポーネントへオブジェクトをドロップします。
1つ以上のノードをDVT階層ビューア内でドラッグ・アンド・ドロップ、1つ以上のノードを階層ビューアから別のコンポーネントへドラッグ、あるいは1つ以上のコンポーネントから階層ビューアへドラッグします。
ユーザーがソースをクリックしてドラッグを開始すると、ブラウザには、マウス・ポインタに付属するゴースト要素として、ドラッグする要素が表示されます。ゴースト要素が有効なターゲット上に来ると、ターゲット・コンポーネントには、いくつかのフィードバック(強調表示など)が表示されます。ゴースト要素を無効なターゲット上にドラッグすると、カーソルが変わり、ターゲットが無効であることが示されます。
属性値をドラッグする場合、ターゲットへの値のコピーのみが可能です。他のドラッグ・アンド・ドロップ・シナリオの場合、ドロップでは、要素のコピー(コピーして貼付け)、移動(切り取って貼付け)、リンク(コピーしてリンクとして貼付け(テキストをコピーして実際のURLとして貼付けなど))が可能です。
ドラッグするコンポーネントで、値が含まれるものをソースと呼びます。ドロップを受け入れるコンポーネントをターゲットと呼びます。ドロップの許可をフレームワークに指示する特定のタグを、ソース・コンポーネントとターゲット・コンポーネントの子として使用します。表34-1に、ドラッグ・アンド・ドロップの異なるシナリオ、有効なソースとターゲット、およびそのシナリオに関連付けられたタグを示します。
表34-1 ドラッグ・アンド・ドロップのシナリオ
シナリオ | ソース | ターゲット |
---|---|---|
属性値のドラッグ |
コンポーネントの属性値 |
別のコンポーネントの属性値(同じオブジェクト・タイプに限る) |
タグ: |
タグ: |
|
あるコンポーネントから別のコンポーネントへのオブジェクトのドラッグ |
任意のコンポーネント |
任意のコンポーネント |
タグ: |
タグ: |
|
あるコレクションのアイテムをドラッグして別のコレクションにドロップ |
|
|
タグ: |
タグ: |
|
あるコンテナから別のコンテナへのコンポーネントのドラッグ |
任意のコンポーネント |
任意のコンポーネント |
タグ: |
タグ: |
|
ある開始時間または開始日から別の開始時間または開始日へのカレンダ・アクティビティのドラッグ |
|
|
タグ: |
タグ: |
|
|
|
|
タグ: |
タグ: |
|
panelBoxコンポーネントの |
|
任意のコンポーネント |
タグ: |
タグ: |
|
DVTグラフのマーカーのドラッグ |
|
|
タグ: |
タグ: |
|
DVTガント・チャートのオブジェクトをドラッグして別のコンポーネントにドロップ |
ガント・チャート |
任意のコンポーネント |
タグ: |
タグ: |
|
DVT階層ビューア、サンバースト、またはツリーマップからノードをドラッグし、別のコンポーネントにドロップします |
|
任意のコンポーネント |
タグ: |
タグ: |
ターゲットにドロップできるオブジェクトのタイプを制限するには、dataFlavor
タグを追加します。これは、ターゲットで受入れ可能なオブジェクト・タイプを1つのみにする場合に役立ちます。ただし、ソースは各種タイプのうちのいずれかになります。dataFlavor
タグでは、ターゲットで複数のソースまたは複数の型を含む可能性のあるソースからオブジェクトを受け入れることができるよう、複数の型を設定することもできます。ドロップが成功するには、ターゲットとソースの両方にdataFlavor
タグを含め、値が同じである必要があります。
注意: ドラッグ・アンド・ドロップ機能は、ウィンドウ間ではサポートされていません。ウィンドウ境界を越えるドラッグは取り消されます。ポップアップ・ウィンドウとポップアップのベース・ページとの間のドラッグ・アンド・ドロップ機能はサポートされています。 ドラッグ・アンド・ドロップ機能は利用できない点にも注意してください。つまり、ドラッグ・アンド・ドロップの実行に使用できるキーボード・ストロークはありません。したがって、アプリケーションですべての機能を利用できるようにする場合、このロジックを備える必要があります。たとえば、使用するページに、オブジェクトを選択するメソッドと、選択したオブジェクトを移動できる移動ボタンやメニュー・アイテムを表示することもできます。 |
属性のドラッグ・アンド・ドロップ機能は、あるコンポーネントの属性をターゲットとして定義し、別のコンポーネントの属性をソースとして定義して追加します。
注意: ターゲットとソースの属性値は同じデータ型である必要があります。 |
次の手順では、ターゲットとソースのコンポーネントはJSFページにすでにあるものとします。
属性のドラッグ・アンド・ドロップ機能を追加する手順:
コンポーネント・パレットの「操作」パネルで、「属性ドロップ・ターゲット」をターゲット・コンポーネントの子としてドラッグ・アンド・ドロップします。
「属性ドロップ・ターゲットの挿入」ダイアログで「属性」ドロップダウンを使用して、ドラッグ・アンド・ドロップ・アクションによる移入先の属性を選択します。このドロップダウン・リストには、ターゲット・コンポーネントの有効な属性がすべて表示されます。
ターゲットへの値の代入元のコンポーネントの子として、属性ドラッグ・ソースをコンポーネント・パレットからドラッグ・アンド・ドロップします。
「属性ドラッグ元の挿入」ダイアログで「属性」ドロップダウンを使用して、ターゲット属性への移入に使用される値の属性を選択します。このドロップダウン・リストには、ソース・コンポーネントの有効な属性がすべて表示されます。
ユーザーが属性値以外をドラッグできるようにする場合、またはあるコンポーネントから別のコンポーネントへ属性をコピーする以外の操作をユーザーができるようにする場合、dropTarget
タグを使用します。また、DataFlavor
オブジェクトを使用して、ドロップ・ターゲットに対して有効なソースのJava型を決めます。ドロップ・ターゲットとドラッグ・ソースが複数ある場合のために、識別値を使用して有効な組合せを制限できます。ドラッグ・アンド・ドロップ・アクションを受けて必要となる機能の実装も必要です。
たとえば、図34-6に示すように、outputText
コンポーネントがあり、ユーザーがoutputText
コンポーネントをpanelBox
コンポーネントにドラッグできるようにし、そのコンポーネントにarray
を表示するとします。
outputText
コンポーネントにはattributeDragSource
タグが含まれます。ただし、(属性のString
値のみでなく)array
をドラッグするため、attributeDropTarget
タグではなくdropTarget
タグを使用する必要があります。また、dataFlavor
タグを使用してarray
オブジェクトのみがターゲットで受け入れられるようにします。
dataFlavor
タグの識別値の定義もできます。同じオブジェクト型の2つのターゲットと2つのソースがある場合に、これは有用です。識別値を作成することで、各ターゲットで有効なソースのみが受け入れられることが保証されます。たとえば、EMPLOYEEオブジェクトを受け入れるTargetAとTargetBの2つのターゲットがあるとします。EMPLOYEEオブジェクトのソースも2つあるとします。TargetAにalpha
という値を使用して識別値を設定することにより、識別値alpha
を持つEMPLOYEEソースのみが受け入れられます。
ドロップ・イベントのリスナーも実装する必要があります。ドロップ・イベントのオブジェクトはtransferable
と呼ばれ、ドロップのペイロードを含みます。リスナーはtransferable
オブジェクトにアクセスし、ここからDataFlavor
オブジェクトを使用してオブジェクトがドロップ可能なことを確認します。その後、ドロップ・イベントを使用してターゲット・コンポーネントを取得し、ドロップされたオブジェクトを使用してプロパティを更新します。このリスナーの詳細は、34.9.1項「DVTコンポーネントのドラッグ・アンド・ドロップ機能の追加方法」の手順で説明します。
ドラッグ・アンド・ドロップ機能を追加するには、まず、コンポーネントをドラッグ・アンド・ドロップ・アクションのターゲットとして定義するタグをコンポーネントに追加します。次に、ドラッグ・アンド・ドロップ・アクションのロジックを処理するイベント・ハンドラ・メソッドを実装します。最後に、ドラッグ・アンド・ドロップのソースを定義します。
この手順では、ソースとターゲットのコンポーネントはすでにページあるものとします。
ドラッグ・アンド・ドロップ機能を追加する手順:
ターゲットを含むJSFページで、コンポーネント・パレットから(「操作」パネルにある)「ドロップ・ターゲット」タグをドラッグ・アンド・ドロップし、dropTarget
タグをターゲット・コンポーネントの子として追加します。
「ドロップ・ターゲットの挿入」ダイアログで、イベントを処理するマネージドBeanのメソッド(このコードはステップ5で作成)に評価される式を入力します。
ヒント:
|
「データ・フレーバの挿入」ダイアログで、ターゲットにドロップ可能なオブジェクトのクラス(java.lang.Object
など)を入力します。この選択を使用してdataFlavor
タグを作成します。これにより、ターゲットにドロップできるオブジェクトのタイプ(String
やDate
など)が決まります。1つのドロップ・ターゲットに複数のdataFlavor
タグを使用し、ドロップ・ターゲットでこれらの型のいずれも受け入れるようにすることができます。
ヒント:
|
構造ウィンドウで、dropTarget
タグを選択します。プロパティ・インスペクタで、actions
属性に値を選択します。これによって、ドロップ・ターゲットでサポートされるアクションが定義されます。有効な値は、COPY
(コピーして貼付け)、MOVE
(切り取って貼付け)およびLINK
(コピーしてリンクとして貼付け)です。
MOVE COPY
アクションが指定されない場合、デフォルトはCOPY
です。
例34-1に、panelBox
コンポーネントに挿入され、配列オブジェクトをドロップ・ソースとするdropTarget
コンポーネントのコードを示します。アクションが定義されていないため、許可されるアクションはCOPY
のみであることに注意してください。
ステップ2で作成したEL式で参照されるマネージドBeanに、ドラッグ・アンド・ドロップ機能を処理するイベント・ハンドラ・メソッドを(EL式での名前と同じ名前を使用して)作成します。
このメソッドは、DropEvent
イベントをパラメータとして取り、DnDAction
オブジェクトを返します。このオブジェクトは、ソースのドロップ時に実行されるアクションです。有効な戻り値は、DnDAction.COPY
、DnDAction.
MOVE
、and DnDAction.LINK
であり、これらは手順5でターゲット属性を定義したときに設定されています。このメソッドは、DropEvent
イベントをチェックして、それがドロップを受け入れるかどうかを判断します。メソッドがドロップを受け入れる場合、ドロップを実行して、実行されたDnDAction
オブジェクトを返します。それ以外の場合、ドロップが拒否されたことを示すDnDAction.NONE
を返します。
このメソッドでは、各dataFlavor
オブジェクトの存在も優先順に確認される必要があります。
ヒント: ターゲットに複数の |
DataFlavor
オブジェクトでは、ドロップされるデータの型(java.lang.Object
など)が定義されます。これは、手順3で作成したJSPのDataFlavor
タグでの定義と同じである必要があります。
ヒント:
ドラッグ・アンド・ドロップ・フレームワークで、サーバーの |
例34-2に、イベント・ハンドラ・メソッドがコールするプライベート・メソッドを示します(イベント・ハンドラそのものは何もしませんが、このメソッドをコールします。このメソッドには、panelBox
コンポーネントでoutputText
コンポーネントの値となるString
パラメータも必要です)。このメソッドは、イベント・ペイロードから配列オブジェクトをコピーして、イベントを開始したコンポーネントに割り当てます。
例34-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; } }
コンポーネント・パレットから(「操作」パネルにある)クライアント属性をドラッグしてclientAttribute
タグをソース・コンポーネントの子として追加します。このタグは、イベントに対するソースのペイロードの定義に使用されます。プロパティ・インスペクタで、clientAttribute
タグに次の定義を行います。
名前: ペイロードの名前を入力します。
値: ペイロードの値と評価されるEL式を入力します。飲み物を例とすると、これは異なる飲み物の値を含むArray
に解決されます。
ソース・コンポーネントの別の子として、パレットから(「操作」パネルにある)属性ドラッグ・ソースをドラッグ・アンド・ドロップします。「属性ドラッグ・ソースの挿入」ダイアログで、前述の手順で作成したclientAttribute
タグに定義するname
をドロップダウン・リストから選択します。これにより、clientAttribute
タグの値がソースのペイロードになります。例34-3に、ドラッグ・アンド・ドロップ操作のソースであるoutputText
コンポーネントのコードを示します。
ドラッグ・アンド・ドロップ操作時、ユーザーはキーボードのキーを押して(キーボード修飾子と呼ばれます)、ドラッグ・アンド・ドロップで行われるアクションを選択できます。ドラッグ・アンド・ドロップ・フレームワークでは、次のキーボード修飾子がサポートされます。
[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になります。これは、変更子を選択しない場合のデフォルトがCOPYであるためです(順序の最初)。[Ctrl]キーを押す場合、その変更子はCOPYと一致するためCOPYが実行されます。[Ctrl]+[Shift]キーを押した場合、アクションはCOPYのままです。これは、その変更子が、許可されるアクションの共通セット内にないLINKアクションと一致するためです。
注意: JavaとJavaScriptとの間のラウンドトリップで情報が失われるため、ドロップでのデータが見込みとは異なる型の場合があります。たとえば、すべての数値型は |
dropTarget
タグには、クライアントでドロップ・イベントを処理するJavaScriptを参照できるclientDropListner
属性が含まれます。クライアント・ハンドラは、パラメータを取らず、AdfDnDContext
アクションを返します。たとえばメソッドがAdfDnDContext.ACTION_NONE
を返すと、ドロップ操作は取り消され、サーバーでコールされません。メソッドがAdfDnDContext.ACTION_COPY
を返すと、コピー操作が許可され、dropListener
メソッドが存在する場合には、それを実行するコールがサーバーで発生します。
たとえば、ドロップ・イベントの起動時にメッセージをログ出力するとします。メッセージの出力を処理し、サーバー・リスナーが起動されるよう適切なアクションを返すクライアント・ハンドラを作成します。例34-4に、メッセージの出力にロガーを使用するクライアント・ハンドラを示します。
collectionDropTarget
およびdragSource
タグを使用して、ユーザーがコレクションからアイテム(表から行など)をドラッグし、ツリーなどの別のコレクション・コンポーネントにドロップできるドラッグ・アンド・ドロップ機能を追加します。たとえば、File Explorerアプリケーションでは、ユーザーは、ディレクトリの内容を表示する表からディレクトリ・ツリーのフォルダにファイルをドラッグできます。図34-3に、Folder0
ディレクトリの内容を表示する表からFolder3
ディレクトリにドラッグされるFile0.doc
オブジェクトを示します。ドロップが完了すると、オブジェクトはFolder3
を構成するコレクションの一部になります。
単一オブジェクトのドラッグ・アンド・ドロップ同様、ドロップによってコピー、移動またはコピーしてリンクとして貼り付けたり(あるいは3つを組み合せたり)、dataFlavor
タグを使用してターゲットでの受け入れ対象を限定できます。
ターゲット・ソースがコレクションで、移動操作をサポートする場合、dragDropEndListener
属性のメソッドも実装できます。これは、ソース・コンポーネントから参照され、ドラッグ・アンド・ドロップ操作後のコレクションの削除に使用されます。詳細は、34.4.2項「dragDropEndListenerについて」を参照してください。
コレクションのドラッグ・アンド・ドロップ機能を追加するには、dropTarget
タグを使用するかわりにcollectionDropTarget
タグを使用します。その後、ドラッグ・アンド・ドロップ・アクションのロジックを処理するイベント・ハンドラ・メソッドを実装する必要があります。次に、dragSource
タグを使用して、ドラッグ・アンド・ドロップ操作のソースを定義します。
この手順では、ソースとターゲットのコンポーネントはすでにページあるものとします。
ドラッグ・アンド・ドロップ機能を追加する手順:
コンポーネント・パレットからコレクション・ドロップ・ターゲットをドラッグし、collectionDropTarget
タグをターゲット・コレクション・コンポーネントの子として追加します。
「コレクション・ドロップ・ターゲットの挿入」ダイアログで、イベントを処理するマネージドBeanのメソッド(このコードはステップ4で作成)に評価される式をdropListener
属性に入力します。
プロパティ・インスペクタで次の設定を行います。
actions
: ドラッグ・アンド・ドロップ操作時にソースで行われるアクションを選択します。
アクションが指定されない場合、デフォルトはCOPY
です。
modelName
: コレクションのモデルを定義します。
modelName
属性の値は、互換性の目的でドラッグ・ソースの特定に使用されるString
オブジェクトです。この属性の値は、手順6で使用するdragSource
タグのdiscriminant
属性の値に一致する必要があります。つまり、これは任意の名前で、ターゲットとソースが同じmodelName
の値または識別値を共有する場合に機能します。
ステップ2でEL式に挿入されたマネージドBeanに、ドロップ・イベントのハンドラを実装します。
このメソッドは、パラメータにDropEvent
イベントを取り、DnDAction
を返す必要があります。このメソッドでは、DropEvent
を使用してTransferable
オブジェクトを取得し、そこからRowKeySet
(ドラッグ用に選択された行)を取得します。Transferable
オブジェクトから取得されたCollectionModel
を使用すると、実際のrowData
を取得してドロップを完了できます。このメソッドはDropEvent
をチェックして、ドロップを受け入れるかどうかを判断します。メソッドがドロップを受け入れる場合は、ドロップを実行して、実行されたDnDAction(DnDAction.COPY、DnDAction.MOVEまたはDnDAction.LINK)を返します。受け入れない場合は、DnDAction.NONEを返して、ドロップが拒否されたことを示します。
例34-5に、2つの表の間で行のコピーを処理するcollectionDropTarget
デモに使用されるCollectionDnd.java
マネージドBeanのイベント・ハンドラ・メソッドを示します。
例34-5 コレクションのdropListenerのイベント・ハンドラ・コード
public DnDAction handleDrop(DropEvent dropEvent) { Transferable transferable = dropEvent.getTransferable(); // The data in the transferable is the row key for the dragged component. DataFlavor<RowKeySet> rowKeySetFlavor = DataFlavor.getDataFlavor(RowKeySet.class, "DnDDemoModel"); 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. 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().add(dnDDemoData); } return dropEvent.getProposedAction(); } else { return DnDAction.NONE; } }
コンポーネント・パレットの「操作」パネルで、「ドラッグ元」をソース・コンポーネントの子としてドラッグ・アンド・ドロップします。
dragSource
タグを選択している場合、プロパティ・インスペクタで、ターゲットに構成される、許容アクションと必要な識別値を設定します。
ドロップ・イベントの後でソース・コレクションをクリーンアップする必要がある場合が考えられます。たとえば、ドラッグで移動を行った場合、移動した項目がコレクションの一部ではなくなるように、ソース・コンポーネントをクリーンアップする必要があることがあります。
dragSource
タグには、ドラッグ・アンド・ドロップ操作の終了後のロジックを含むハンドラを登録できるdragDropEndListener
属性が含まれます。
たとえば、ドラッグ・アンド・ドロップでオブジェクトを移動する場合、ドロップの正常終了後にソース・コンポーネントからオブジェクトを物理的に削除する必要があります。例34-6に、dragDropEndListener
属性のハンドラを示します。
例34-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 dta from the source model directly. Object removed = getSource2Values().remove(currKey.intValue()); } // Need to add the drag source table so it gets redrawn. AdfFacesContext.getCurrentInstance().addPartialTarget(dropEvent.getDragComponent());
ある親から別の親へのコンポーネントの移動を可能にしたり、親コンポーネントの子コンポーネントの並替えを可能にできます。例として、図34-4に、panelGrid
コンポーネントの最初の子で最後に移動される暗色のpanelBox
コンポーネントを示します。
注意: panelDashboardコンポーネントにコンポーネントを移動したり、このコンポーネントから移動したりする場合、該当コンポーネントに固有の手順を使用する必要があります。詳細は、34.6項「panelDashboardコンポーネントに対するドラッグ・アンド・ドロップ機能の追加」を参照してください。 |
コンポーネントに対するドラッグ・アンド・ドロップ機能の追加は、オブジェクトに対するものと同様です。ただし、attributeDragSource
タグを使用するかわりにcomponentDragSource
タグを使用します。オブジェクトまたはコレクションのドラッグ・アンド・ドロップ同様、dropListener
ハンドラを実装する必要もあります。
ドラッグ・アンド・ドロップ機能を追加する手順:
コンポーネント・パレットの「操作」パネルで、「ドロップ・ターゲット」をターゲット・コンポーネントの子としてドラッグ・アンド・ドロップします。
「ドロップ・ターゲットの挿入」ダイアログで、イベントを処理するマネージドBeanのメソッド(このコードはステップ4で作成)に評価される式を入力します。
dropTarget
タグを選択した状態のまま、プロパティ・インスペクタでaction
属性に有効なアクション・セットを選択します。
ステップ2で作成したEL式で参照されるマネージドBeanに、ドラッグ・アンド・ドロップ機能を処理するイベント・ハンドラ・メソッドを(EL式での名前と同じ名前を使用して)dropListener
属性に対して作成します。
このメソッドは、DropEvent
イベントをパラメータとして取り、DnDAction
を返す必要があります。これは、ソースのドロップ時に実行されるアクションです。有効な戻り値は、DnDAction.COPY
、DnDAction.
MOVE
、DnDAction.LINK
であり、これらは手順2でターゲット属性を定義したときに設定されています。
このハンドラ・メソッドは、DropEvent
イベントを使用してtransferable
オブジェクトとそのデータを取得してから、移動またはコピーを完了し、コンポーネントの順序を必要に応じて並べ替えます。メソッドがドロップを完了すると、実行されたDnDAction
を返します。それ以外の場合、ドロップが拒否されたことを示すDnDAction.NONE
を返します。
例34-7に、デモ・アプリケーションのcomponentDragSource
JSFページで使用されるDemoDropHandler.java
マネージドBeanのhandleComponentMove
イベント・ハンドラを示します。
例34-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; ComponentChange change; // 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)) { reorderedIdList.add(currId); if (currId.equals(dropLayoutId)) { reorderedIdList.add(movedLayoutId); } } } change = new ReorderChildrenComponentChange(reorderedIdList); rootParent = dropParent; // 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; } }
コンポーネント・パレットからコンポーネント・ドラッグ・ソースをドラッグ・アンド・ドロップし、ソース・コンポーネントの子としてcomponentDragSource
タグをソース・コンポーネントに追加します。
デフォルトでは、panelDashboard
コンポーネントは、その中にあるコンポーネントのドラッグ・アンド・ドロップをサポートします。つまり、リスナーを実装したり、追加タグを使用したりせずにpanelDashboard
コンポーネント内のコンポーネントを並べ替えることができます。ただし、コンポーネントをpanelDashboard
コンポーネントにドラッグできるようにする場合やpanelDashboard
コンポーネントからコンポーネントをドラッグできるようにする場合、タグを使用してリスナーを実装する必要があります。コンポーネントをドラッグ・アンド・ドロップするため、panelDashboard
にドラッグする場合はcomponentDragSource
タグを使用します。ただし、panelDashboard
はドロップ・ターゲットをすでにサポートしているため、dropTarget
タグを使用する必要はありません。かわりに、dataFlavor
タグと識別値を使用する必要があります。タグと識別値は、ドロップが外部コンポーネントからのものであることをフレームワークに通知します。
panelDashboard
からのコンポーネントのドラッグは、他のコンポーネントのドラッグ・アンド・ドロップとほぼ同じです。ターゲットにdropTarget
タグを使用し、ソースにcomponentDragSource
タグを使用します。ただし、dataFlavor
タグと識別値も使用する必要があります。
panelDashboard
コンポーネントには、ダッシュボード内のpanelBox
コンポーネントの並替えに使用されるドラッグ・アンド・ドロップ機能が組み込まれているため、dropTarget
タグは使用できませんが、dataFlavor
タグと識別値を使用してdropListener
を実装する必要があります。この実装では、コンポーネントの並替えを処理する必要があります。
開始する前に:
panelDashboard
コンポーネントを作成します。詳細は、8.8項「ダッシュボードでのコンテンツの配置」を参照してください。
panelBox
コンポーネントを含むpanelDashboard
から別のコンポーネントを作成します。panelBox
コンポーネントの詳細は、8.9.3項「panelBoxコンポーネントの使用方法」を参照してください。
panelDashboardコンポーネントへのドラッグ・アンド・ドロップ機能の追加手順:
構造ウィンドウで、ターゲット・コンポーネントになるpanelDashboard
コンポーネントを選択します。
プロパティ・インスペクタで、ドロップ・イベント(手順6でこのコードを作成)を処理するマネージドBeanのメソッドに評価される式をDropListenerに入力します。
コンポーネント・パレットの「操作」パネルで、「データ・フレーバ」をドラッグし、panelDashboard
コンポーネントの子としてドロップします。
「データ・フレーバの挿入」ダイアログで、javax.faces.component.UIComponent
と入力します。
プロパティ・インスペクタで、panelDashboard
コンポーネントにドラッグできるコンポーネント(dragIntoDashboard
など)を識別する識別値を一意の名前に設定します。
ステップ2で作成したEL式で参照されるマネージドBeanに、ドラッグ・アンド・ドロップ機能を処理するイベント・ハンドラ・メソッドを(EL式での名前と同じ名前を使用して)dropListener
属性に対して作成します。
このメソッドは、DropEvent
イベントをパラメータとして取り、DnDAction
のNONE
を返す必要があります。これは、panelDashboard
がその子コンポーネントの位置を処理するためです。
このハンドラ・メソッドは、dropEvent.getTransferable().getData(DataFlavor.UICOMPONENT_FLAVOR)
を使用して、transferable
オブジェクトとそのデータを取得します。メソッドがドロップを完了すると、org.apache.myfaces.trinidad.change.ReorderChildrenComponent
メソッドを使用して子の新しい順序を保存し、
ChangedropEvent.getDropSiteIndex()
メソッドを使用して、ドラッグしたコンポーネントの場所を取得できます。dashboardComponent.prepareOptimizedEncodingOfInsertedChild()
メソッドを使用して、コンポーネントのドロップにアニメーションを使用することもできます。
例34-8に、ADF Facesデモ・アプリケーションのJSFページdashboard
で使用されるマネージドBeanDemoDashboardBean.java
に対するイベント・ハンドラmove
とヘルパー・メソッドを示します。
例34-8 panelDashboardコンポーネントのDropListenerのハンドラ
public DnDAction move(DropEvent e) { UIComponent dropComponent = e.getDropComponent(); UIComponent movedComponent = e.getTransferable().getData(DataFlavor.UICOMPONENT_FLAVOR); UIComponent movedParent = movedComponent.getParent(); // Ensure that we are handling the re-order of a direct child of the panelDashboard: if (movedParent.equals(dropComponent) && dropComponent.equals(_dashboard)) { // Move the already rendered child and redraw the side bar since the insert indexes have // changed: _moveDashboardChild(e.getDropSiteIndex(), movedComponent.getId()); } else { // This isn't a re-order but rather the user dropped a minimized side bar item into the // dashboard, in which case that item should be restored at the specified drop location. String panelKey = _getAssociatedPanelKey(movedComponent); if (panelKey != null) { UIComponent panelBoxToShow = _dashboard.findComponent(panelKey); // Make this panelBox rendered: panelBoxToShow.setRendered(true); int insertIndex = e.getDropSiteIndex(); // Move the already rendered child and redraw the side bar since the insert indexes have // changed and because the side bar minimized states are out of date: _moveDashboardChild(insertIndex, panelKey); // Let the dashboard know that only the one child should be encoded during the render phase: _dashboard.prepareOptimizedEncodingOfInsertedChild( FacesContext.getCurrentInstance(), insertIndex); } } return DnDAction.NONE; // the client is already updated, so no need to redraw it again } private void _moveDashboardChild(int dropIndex, String movedId) { // Build the new list of IDs, placing the moved component at the drop index. List<String> reorderedIdList = new ArrayList<String>(_dashboard.getChildCount()); int index = 0; boolean added = false; for (UIComponent currChild : _dashboard.getChildren()) { if (currChild.isRendered()) { if (index == dropIndex) { reorderedIdList.add(movedId); added = true; } String currId = currChild.getId(); if (currId.equals(movedId) && index < dropIndex) { // component is moved later, need to shift the index by 1 dropIndex++; } if (!currId.equals(movedId)) { reorderedIdList.add(currId); } index++; } } if (!added) { // Added to the very end: reorderedIdList.add(movedId); } // Apply the change to the component tree immediately: ComponentChange change = new ReorderChildrenComponentChange(reorderedIdList); change.changeComponent(_dashboard); // Add the side bar as a partial target since we need to redraw the state of the side bar items // since their insert indexes are changed and possibly because the side bar minimized states // are out of date: RequestContext rc = RequestContext.getCurrentInstance(); rc.addPartialTarget(_sideBarContainer); }
コンポーネント・パレットの「操作」パネルで、「コンポーネント・ドラッグ元」をドラッグし、ソース・コンポーネントになるpanelBox
コンポーネントの子としてドロップします。
プロパティ・インスペクタで、識別値を、手順5のpanelDashboard
で識別値に入力した値に設定します。
panelDashboard
コンポーネントからのドラッグ・アンド・ドロップ機能の実装は、他のコンポーネントの標準ドラッグ・アンド・ドロップ機能と似ています。ただし、dataFlavor
タグと識別値を使用する必要がある点を除きます。
panelDashboardコンポーネントからのドラッグ・アンド・ドロップ機能の追加方法:
コンポーネント・パレットの「操作」パネルで、「ドロップ・ターゲット」をターゲット・コンポーネントの子としてドラッグ・アンド・ドロップします。
「ドロップ・ターゲットの挿入」ダイアログで、イベントを処理するマネージドBeanのメソッド(このコードは手順5で作成)に評価される式を入力し、FlavorClassにjavax.faces.component.UIComponentと入力します。
dropTarget
タグを選択した状態のまま、プロパティ・インスペクタでaction
属性の値にMOVEを選択します。
構造ウィンドウでdataFlavor
タグを選択し、プロパティ・インスペクタで、このコンポーネントにドラッグできるpanelBox
コンポーネント(dragOutOfDashboard
など)を識別する識別値を一意の名前に設定します。
ステップ2で作成したEL式で参照されるマネージドBeanに、ドラッグ・アンド・ドロップ機能を処理するイベント・ハンドラ・メソッドを(EL式での名前と同じ名前を使用して)dropListener
属性に対して作成します。
このハンドラ・メソッドは、DropEvent
イベントを使用してtransferable
オブジェクトとそのデータを取得してから、必要に応じてコンポーネントの移動や並替えを完了します。メソッドがドロップを完了すると、DnDAction
のNONEを返します。
dashboardComponent.
prepareOptimizedEncodingOfDeletedChild()
メソッドを使用して、panelBox
コンポーネントの削除にアニメーションを使用することができます。
例34-9に、デモ・アプリケーションのJSFページdashboard
で使用されるマネージドBeanDemoDashboardBean.java
に対するイベント・ハンドラhandleSideBarDrop
とヘルパー・メソッドを示します。
例34-9 panelDashboardコンポーネントからのpanelBoxの移動を処理するdropListenerのイベント・ハンドラ・コード
public DnDAction handleSideBarDrop(DropEvent e) { UIComponent movedComponent = e.getTransferable().getData(DataFlavor.UICOMPONENT_FLAVOR); UIComponent movedParent = movedComponent.getParent(); // Ensure that the drag source is one of the items from the dashboard: if (movedParent.equals(_dashboard)) { _minimize(movedComponent); } 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; 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; _switcher.setFacetName("restored"); rc.addPartialTarget(_switcher); } // Redraw the side bar so that we can update the colors of the opened items: rc.addPartialTarget(_sideBarContainer); }
コンポーネント・パレットの「操作」パネルで、「コンポーネント・ドラッグ元」を、panelDashboard
コンポーネント内のソース・コンポーネントpanelBox
の子としてドラッグ・アンド・ドロップします。
プロパティ・インスペクタで、識別値を、手順4のターゲット・コンポーネントのdataFlavor
タグで識別値に入力した値に設定します。
Calendarには、ユーザーがアクティビティのハンドルをドラッグして終了時間を変更できる機能が含まれています。ただし、ユーザーがアクティビティを別の開始時間、さらには別の日にドラッグ・アンド・ドロップできるようにする場合は、ドラッグ・アンド・ドロップ機能を実装します。ドラッグ・アンド・ドロップを使用すると、アクティビティを移動できるだけでなく、コピーすることもできます。
calendarDropTarget
タグを使用して、ドラッグ・アンド・ドロップ機能を追加します。コレクションのドラッグ・アンド・ドロップとは異なり、ソース・タグは必要ありません。ターゲット(アクティビティの移動先のオブジェクト、この場合はカレンダ)がアクティビティを移動します。ソース(移動またはコピーの対象となるアイテム)がカレンダ内のアクティビティの場合、calendarDropTargetタグのみを使用します。タグは、転送可能なものがcalendarActivity
オブジェクトであると予測します。
ただし、Calendarの外からオブジェクトをドラッグ・アンド・ドロップすることもできます。この操作を有効にする場合は、ソース・オブジェクト(calendarActivity
オブジェクト以外のオブジェクト)をドロップできるように構成されているdataFlavor
タグを使用します。
Calendarにドラッグ・アンド・ドロップ機能を追加する手順:
コンポーネント・パレットの「操作」パネルで、「カレンダ・ドロップ・ターゲット」をcalendar
コンポーネントの子としてドラッグ・アンド・ドロップします。
Calendarドロップ・ターゲットの挿入ダイアログで、イベントを処理するマネージドBeanのメソッドに対して評価されるdropListener
属性の式を入力します(このコードは手順4で作成)。
プロパティ・インスペクタで、「アクション」を設定します。この値で、アクティビティ(または他のソース)の移動、コピー、リンクとしてコピー、またはこの3つの任意の組合せを実行できるかどうかが決まります。アクションを指定しない場合、デフォルトはCOPY
です。
ステップ2でEL式に挿入されたマネージドBeanに、ドロップ・イベントのハンドラを実装します。
このメソッドは、パラメータにDropEvent
イベントを取り、DnDAction
を返す必要があります。DnDAction
は、ソースのドロップ時に実行されるアクションです。有効な戻り値は、COPY
、MOVE
、LINK
であり、これらは手順3でactions
属性を定義するときに設定されます。このメソッドでは、DropEvent
を使用してtransferable
オブジェクトを取得し、そこから、ドラッグしたデータのCalendarModel
オブジェクトにアクセスし、そこから実際のデータにアクセスします。リスナーは、ソースのモデルにそのデータを追加してから、実行されたDnDAction
(DnDAction.COPY
、DnDAction.MOVE
またはDnDAction.LINK
)を返します。それ以外の場合は、DnDAction.NONE
を返して、ドロップが拒否されたことを示します。
ドロップ・イベントのドロップ・サイトは、oracle.adf.view.rich.dnd.CalendarDropSite
クラスのインスタンスです。Calendarのドラッグ・アンド・ドロップ・ハンドラの例は、ADF Facesデモ・アプリケーションのoracle.adfdemo.view.calendar.rich.DemoCalendarBean
マネージドBeanのhandleDrop
メソッドを参照してください。
アクティビティのソースがカレンダの外部にある場合は、「データ・フレーバ」をドラッグし、calendarDropTarget
タグの子としてドロップします。このタグにより、ターゲットにドロップできるオブジェクトの型(String
やDate
オブジェクトなど)が決まります。1つのドロップ・ターゲットに複数のdataFlavor
タグを使用し、ドロップ・ターゲットでこれらの型のいずれも受け入れるようにすることができます。
「データ・フレーバの挿入」ダイアログで、ターゲットにドロップ可能なオブジェクトのクラス(java.lang.Object
など)を入力します。
ヒント:
|
Calendar内のドラッグ・アンド・ドロップ・アクティビティの場合、ユーザーは表示内でのみドラッグ・アンド・ドロップを行うことができます。つまり、ユーザーは、日表示内の1つの時間スロットから別の時間スロットにアクティビティをドラッグできますが、日表示からアクティビティを切り取り、月表示に貼り付けることはできません。
ユーザーが日表示または週表示でアクティビティをドラッグ・アンド・ドロップしている場合、Calendarでは30分ごとにドロップ・サイトがマークされます。日表示では、終日のアクティビティまたは複数日のアクティビティは移動できません。
週表示では、終日のアクティビティおよび複数日のアクティビティを移動できますが、その他の終日のスロットにのみドロップできます。つまり、終日のアクティビティを、開始時間と終了時間が設定されているアクティビティには変更できません。月表示では、終日のアクティビティおよび複数日のアクティビティを任意の日に移動できます。
DVTバブル・グラフと散布図のドラッグ・アンド・ドロップを構成できます。これにより、マーカーの値を再配置することでその値を変更できます。グラフでドラッグ・アンド・ドロップできるようにする場合、dragSource
タグとdropTarget
タグを使用します。また、DataFlavor
オブジェクトを使用して、ドロップ・ターゲットに対して有効なソースのJava型を決めます(この場合はGraphSelectioオブジェクト)。ドラッグ・アンド・ドロップ・アクションを受けて必要となる機能の実装も必要です。
たとえば、図34-6に示すように、scatterGraph
コンポーネントがあり、ユーザーが従業員の業績等級を調整する人材用散布図マーカーをドラッグできるようにするとします。
scatterGraph
コンポーネントには、dragSource
とdropTarget
タグがどちらも含まれています。また、dataFlavor
タグを使用して、ドロップするオブジェクトのタイプを決定します。
ドロップ・イベントのリスナーも実装する必要があります。ドロップ・イベントのオブジェクトはtransferable
と呼ばれ、ドロップのペイロードを含みます。リスナーはtransferable
オブジェクトにアクセスし、ここからDataFlavor
オブジェクトを使用してオブジェクトがドロップ可能なことを確認します。その後、ドロップ・イベントを使用してターゲット・コンポーネントを取得し、ドロップされたオブジェクトを使用してプロパティを更新します。
ドラッグ・アンド・ドロップ機能を追加するには、最初にソース・タグとターゲット・タグをグラフに追加します。次に、ドラッグ・アンド・ドロップ・アクションのロジックを処理するイベント・ハンドラ・メソッドを実装します。実行時の処理の詳細は、34.3.2項「実行時の処理」を参照してください。
ドラッグ・アンド・ドロップ機能を追加する手順:
コンポーネント・パレットの「操作」パネルで、「ドロップ・ターゲット」タグをドラッグし、グラフ・コンポーネントの子としてドロップします。
「ドロップ・ターゲットの挿入」ダイアログで、イベントを処理するマネージドBeanのメソッド(このコードはステップ6で作成)に評価される式を入力します。
「データ・フレーバの挿入」ダイアログで、oracle.adf.view.faces.bi.component.graph.GraphSelection
と入力します。これは、ターゲットにドロップできるオブジェクトのクラスです。このエントリを使用して、ターゲットにドロップできるオブジェクトのタイプを決めるdataFlavor
タグを作成します。
プロパティ・インスペクタで、必要に応じて識別値の値を設定します。識別値は、どのソースをターゲットにドロップできるかを決定する場合に使用される任意の文字列です。たとえば、GraphSelection
オブジェクトを受け入れるGraphAとGraphBの2つのグラフがあるとします。ソースも2つあるとします。どちらもGraphSelection
オブジェクトになります。GraphAにalpha
という値を使用して識別値を設定することにより、識別値alpha
を持つGraphSelection
ソースのみが受け入れられます。
構造ウィンドウで、dropTarget
タグを選択します。プロパティ・インスペクタで、「アクション」の値にMOVE
を選択します。
コンポーネント・パレットの「操作」パネルで、「ドラッグ元」をグラフ・コンポーネントの子としてドラッグ・アンド・ドロップします。
dragSource
タグを選択している場合、プロパティ・インスペクタで、dataFlavor
タグに構成されるように、許容アクションにMOVE
を設定し、必要な識別値を追加します。
ステップ2で作成したEL式で参照されるマネージドBeanに、ドラッグ・アンド・ドロップ機能を処理するイベント・ハンドラ・メソッドを(EL式での名前と同じ名前を使用して)作成します。
このメソッドは、DropEvent
イベントをパラメータとして取り、DnDAction
オブジェクトを返します。これは、ソースのドロップ時に実行されるアクションです。この場合はDnDAction.
MOVE
になります。このメソッドは、DropEvent
イベントをチェックして、それがドロップを受け入れるかどうかを判断します。メソッドがドロップを受け入れる場合、ドロップを実行して、実行されたDnDAction
オブジェクトを返します。それ以外の場合、ドロップが拒否されたことを示すDnDAction.NONE
を返します。このメソッドでは、dataFlavor
オブジェクト(この場合はoracle.adf.view.faces.bi.component.graph.GraphSelection
)の存在も確認する必要があります。
ガント・チャートとその他のコンポーネント間でドラッグ・アンド・ドロップできるようにする場合、dragSource
タグとdropTarget
タグを使用します。また、DataFlavor
オブジェクトを使用して、ドロップ・ターゲットに対して有効なソースのJava型を決めます。ドラッグ・アンド・ドロップ・アクションを受けて必要となる機能の実装も必要です。projectGantt
とschedulingGantt
のどちらのコンポーネントも、ドラッグ・アンド・ドロップ機能をサポートします。
たとえば、図34-6に示すように、projectGantt
コンポーネントがあり、ユーザーがtreeTable
コンポーネントに1つのタイムラインをドラッグできるようにし、タイムラインに関する情報がそのコンポーネントに表示されるとします。
projectGantt
コンポーネントには、dragSource
タグが含まれます。ユーザーは、表示される出力テキストのString
値のみではなくオブジェクト全体をドラッグするため、attributeDropTarget
タグのかわりにdropTarget
タグを使用します。
また、dataFlavor
タグを使用して、ドロップするオブジェクトのタイプを決定します。このタグでは、識別値を定義できます。同じオブジェクト型の2つのターゲットと2つのソースがある場合に、これは有用です。識別値を作成することで、各ターゲットで有効なソースのみが受け入れられることが保証されます。たとえば、TaskDragInfo
オブジェクトを受け入れるTargetAとTargetBの2つのターゲットがあるとします。ソースも2つあるとします。どちらもTaskDragInfo
オブジェクトになります。TargetAにalpha
という値を使用して識別値を設定することにより、識別値alpha
を持つTaskDragInfo
ソースのみが受け入れられます。
ドロップ・イベントのリスナーも実装する必要があります。ドロップ・イベントのオブジェクトはtransferable
と呼ばれ、ドロップのペイロードを含みます。リスナーはtransferable
オブジェクトにアクセスし、ここからDataFlavor
オブジェクトを使用してオブジェクトがドロップ可能なことを確認します。その後、ドロップ・イベントを使用してターゲット・コンポーネントを取得し、ドロップされたオブジェクトを使用してプロパティを更新します。
ドラッグ・アンド・ドロップ機能を追加するには、まず、コンポーネントをドラッグ・アンド・ドロップ・アクションのターゲットとして定義するタグをコンポーネントに追加します。次に、ドラッグ・アンド・ドロップ・アクションのロジックを処理するイベント・ハンドラ・メソッドを実装します。最後に、ドラッグ・アンド・ドロップのソースを定義します。実行時の処理の詳細は、34.3.2項「実行時の処理」を参照してください。clientDropListener
属性の使用の詳細は、34.3.3項「ClientDropListenerの使用について」を参照してください。
ドラッグ・アンド・ドロップ機能を追加する手順:
コンポーネント・パレットの「操作」パネルで、「ドロップ・ターゲット」タグをドラッグし、ターゲット・コンポーネントの子としてドロップします。
「ドロップ・ターゲットの挿入」ダイアログで、イベントを処理するマネージドBeanのメソッド(このコードはステップ6で作成)に評価される式を入力します。
ヒント:
|
「データ・フレーバの挿入」ダイアログで、ターゲットにドロップ可能なオブジェクトのクラス(java.lang.Object
など)を入力します。この選択を使用して、ターゲットにドロップできるオブジェクトのタイプを決めるdataFlavor
タグを作成します。1つのドロップ・ターゲットに複数のdataFlavor
タグを使用し、ドロップ・ターゲットでこれらの型のいずれも受け入れるようにすることができます。
ヒント:
|
プロパティ・インスペクタで、必要に応じて識別値の値を設定します。識別値は任意の文字列で、dataFlavorで指定されるどのタイプのソースがソースとして許容されるかを決める場合に使用されます。
構造ウィンドウで、dropTarget
タグを選択します。プロパティ・インスペクタで、「アクション」の値を選択します。これによって、ドロップ・ターゲットでサポートされるアクションが定義されます。有効な値は、COPY
(コピーして貼付け)、MOVE
(切り取って貼付け)およびLINK
(コピーしてリンクとして貼付け)です。
MOVE COPY
アクションが指定されない場合、デフォルトはCOPY
です。
例34-10に、TaskDragInfo
オブジェクトをドロップ・ソースにするdropTarget
コンポーネントのコードを示します。actions
属性の値にCOPYが設定されたため、COPYのみが許容されるアクションになることに注意してください。
例34-10 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>
ステップ2で作成したEL式で参照されるマネージドBeanに、ドラッグ・アンド・ドロップ機能を処理するイベント・ハンドラ・メソッドを(EL式での名前と同じ名前を使用して)作成します。
このメソッドは、DropEvent
イベントをパラメータとして取り、DnDAction
オブジェクトを返します。これは、ソースのドロップ時に実行されるアクションです。有効な戻り値は、DnDAction.COPY
、DnDAction.
MOVE
、and DnDAction.LINK
であり、これらは手順5でターゲット属性を定義したときに設定されています。このメソッドは、DropEvent
イベントをチェックして、それがドロップを受け入れるかどうかを判断します。メソッドがドロップを受け入れる場合、ドロップを実行して、実行されたDnDAction
オブジェクトを返します。それ以外の場合、ドロップが拒否されたことを示すDnDAction.NONE
を返します。
このメソッドでは、各dataFlavor
オブジェクトの存在も優先順に確認される必要があります。
ヒント: ターゲットに複数の |
DataFlavor
オブジェクトでは、ドロップされるデータの型(java.lang.Object
など)が定義されます。これは、手順3で作成したJSPのDataFlavor
タグでの定義と同じである必要があります。
ヒント:
ドラッグ・アンド・ドロップ・フレームワークで、サーバーの |
例34-11に、イベント・ペイロードからTaskDragInfo
オブジェクトをコピーして、イベントを開始したコンポーネントに割り当てるハンドラ・メソッドを示します。
例34-11 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; }
コンポーネント・パレットの「操作」パネルで、「ドラッグ元」をソース・コンポーネントの子としてドラッグ・アンド・ドロップします。
dragSource
タグを選択している場合、プロパティ・インスペクタで、ターゲットに構成される、許容アクションと必要な識別値を設定します。
階層ビューア、サンバースト、およびツリーマップを、ページ上でサポートされたコンポーネント間のドラッグ・アンド・ドロップ操作のドラッグ・ソース、およびドロップ・ターゲットとして構成できます。
階層ビューアは、次のドラッグ・アンド・ドロップ操作をサポートします。
階層ビューア内で、1つ以上のノードをドラッグ・アンド・ドロップします
階層ビューアから1つ以上のノードを別のコンポーネントにドラッグします
別のコンポーネントから階層ビューアに1つ以上のアイテムをドラッグします
図34-7に、その中でのドラッグ・アンド・ドロップを可能とするように構成した階層ビューアを示します。ノードをクリックし0.5秒を超えて保持すると、バックグラウンドにドラッグして階層内の別のルートにしたり、別のノードにドラッグしてそのノードの子として追加したりすることができます。
ノードを別のノードにドラッグすると、ドラッグされたノードとその子は、ターゲット・ノードの子となる。図34-8に、Nina Evansのデータを含むノードへのドラッグの結果を示します。Nancy Greenとその部下は、今はNina Evansの部下として示されます。
サンバーストは、1つ以上のノードの別コンポーネントへのドラッグをサポートします。ドラッグのペイロードは、org.apache.myfaces.trinidad.model.RowKeySet
です。サンバーストが別のオブジェクトからのドロップを受け入れるように構成することもできます。
図34-9に、それからaf:outputFormatted
コンポーネントへのドラッグを可能とするように構成されたサンバーストを示します。サンバーストが複数選択が可能なように構成されている場合、ユーザーは複数のノードをCtrl+D操作でドラッグできます。
ツリーマップは、1つ以上のノードの別コンポーネントへのドラッグをサポートします。ドラッグのペイロードは、org.apache.myfaces.trinidad.model.RowKeySet
です。ツリーマップが別のオブジェクトからのドロップを受け入れるように構成することもできます。
図34-10に、ドロップ・ターゲットとして構成されたツリーマップを示します。この例では、ドラッグ・ソースはaf:outputFormatted
コンポーネントです。
ドラッグ・アンド・ドロップの機能を追加するには、第一に、サポート対象のDVTコンポーネントに、ドラッグ・アンド・ドロップ・アクションのターゲットとしてそれを定義しているタグを追加します。次に、ドラッグ・アンド・ドロップ・アクションのロジックを処理するイベント・ハンドラ・メソッドを実装します。最後に、ドラッグ・アンド・ドロップのソースを定義します。実行時の処理の詳細は、34.3.2項「実行時の処理」を参照してください。clientDropListener
属性の使用の詳細は、34.3.3項「ClientDropListenerの使用について」を参照してください。
開始する前に:
ドラッグ・アンド・ドロップ機能について理解しておくと役立ちます。詳細は、34.1項「ドラッグ・アンド・ドロップ機能の概要」を参照してください。
次のタスクを実行する必要があります。
DVTコンポーネントをユーザーのページに加えます。
DVTコンポーネント作成時のヘルプについては、第23章「ADFデータ視覚化コンポーネントの概要」を参照してください。
DVTコンポーネントへのドロップを可能にする予定であれば、ドラッグ・ソースとするコンポーネントをページに加えます。
他のADF Facesコンポーネント追加の詳細は、第1.3項「ADF Facesコンポーネント」を参照してください。
DVTコンポーネントから別のコンポーネントヘのドラッグを可能にする予定であれば、ドロップ・ターゲットとするコンポーネントをページに加えます。
DVT階層ビューア、サンバースト、あるいはツリーマップ・コンポーネントにドラッグ・アンド・ドロップ機能を追加するには:
DVTコンポーネントをドロップ・ターゲットとして構成するには、次を実行します。
コンポーネント・パレットで、「操作」パネルから、「ドロップ・ターゲット」タグをドラッグし、ドラッグ・アンド・ドロップをサポートするDVTコンポーネントの子としてドロップします。
「ドロップ・ターゲットの挿入」ダイアログで、イベントを処理するマネージドBean上のドロップ・リスナー・メソッド(このコードはステップ6で作成)に評価される式を入力します。
ヒント:
|
「データ・フレーバの挿入」ダイアログで、ターゲットにドロップ可能なオブジェクトのクラス(java.lang.Object
など)を入力します。この選択を使用して、ターゲットにドロップできるオブジェクトのタイプを決めるdataFlavor
タグを作成します。1つのドロップ・ターゲットに複数のdataFlavor
タグを使用し、ドロップ・ターゲットでこれらの型のいずれも受け入れるようにすることができます。
ヒント:
|
プロパティ・インスペクタで、必要に応じて識別値の値を設定します。識別値は、どのソースをターゲットにドロップできるかを決定する場合に使用される任意の文字列です。たとえば、どちらもjava.lang.Object
を受け入れる2つのツリーマップ、ツリーマップAとツリーマップBがあるとします。ソースも2つあり、どちらもjava.lang.Object
オブジェクトです。GraphAにalpha
という値を使用して識別値を設定することにより、識別値alpha
を持つjava.lang.Object
ソースのみが受け入れられます。
構造ウィンドウで、dropTarget
タグを選択します。プロパティ・インスペクタにおいて、アクションの値を選択します。これによって、ドロップ・ターゲットでサポートされるアクションが定義されます。有効な値は、COPY
(コピーして貼付け)、MOVE
(切り取って貼付け)およびLINK
(コピーしてリンクとして貼付け)です。
MOVE COPY
アクションが指定されない場合、デフォルトはCOPY
です。
例34-12に、java.lang.Object
をドラッグ・ソースとして受け入れるツリーマップ・コンポーネントのコードを示します。actions
属性の値にCOPYが設定されたため、COPYのみが許容されるアクションになることに注意してください。
例34-12 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>
ステップ2で作成したEL式で参照されるマネージドBeanに、ドラッグ・アンド・ドロップ機能を処理するイベント・ハンドラ・メソッドを(EL式での名前と同じ名前を使用して)作成します。
このメソッドは、DropEvent
イベントをパラメータとして取り、DnDAction
オブジェクトを返します。これは、ソースのドロップ時に実行されるアクションです。有効な戻り値は、DnDAction.COPY
、DnDAction.
MOVE
、and DnDAction.LINK
であり、これらは手順5でターゲット属性を定義したときに設定されています。このメソッドは、DropEvent
イベントをチェックして、それがドロップを受け入れるかどうかを判断します。メソッドがドロップを受け入れる場合、ドロップを実行して、実行されたDnDAction
オブジェクトを返します。それ以外の場合、ドロップが拒否されたことを示すDnDAction.NONE
を返します。
このメソッドでは、各dataFlavor
オブジェクトの存在も優先順に確認される必要があります。
ヒント: ターゲットに複数の |
DataFlavor
オブジェクトでは、ドロップされるデータの型(java.lang.Object
など)が定義されます。これは、手順3で作成したJSPのDataFlavor
タグでの定義と同じである必要があります。
ヒント:
ドラッグ・アンド・ドロップ・フレームワークで、サーバーの |
例34-13に、イベント・ペイロードからjava.lang.Object
オブジェクトをコピーして、イベントを開始したコンポーネントに割り当てるハンドラ・メソッドを示します。
例34-13 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; }
DVTコンポーネントをドラッグ・ソースとして構成するには、次を実行します。
コンポーネント・パレットで、「操作」パネルから、「ドラッグ元」をDVTコンポーネントの子としてドラッグ・アンド・ドロップします。
dragSource
タグを選択している場合、プロパティ・インスペクタで、ターゲットに構成される、許容アクションと必要な識別値を設定します。
例34-14に、ドラッグ・ソースとして構成された、ツリーマップのJSPコードを示します。すべてのアクション(COPY
、MOVE
およびLINK
)が許されることに注意します。
例34-14 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>
DVTコンポーネントを別のコンポーネントからのドラッグを可能とするドロップ・ターゲットとして使用するには、コンポーネント・パレットで、Operationsパネルからドラッグ元を、ドラッグのソースとなるコンポーネントの子としてドラッグ・アンド・ドロップします。
たとえば、ドラッグ元をaf:outputFormatted
コンポーネントの子としてドラッグ・アンド・ドロップし、ツリーマップに関するノード情報を表示します。dragSource
タグを選択している場合、プロパティ・インスペクタで、許容アクションとターゲットに必要な識別値を設定します。
DVTコンポーネントを別のサポートされたDVTやADF Facesのコンポーネントのドラッグ・ソースとして追加するには、以下を実行します。
コンポーネント・パレットで、「Operations」パネルから、「ドロップ・ターゲット」を、ドロップを受け取るコンポーネント上にドラッグ・アンド・ドロップします。
たとえば、ドロップ・ターゲットをツリー表
コンポーネント上にドラッグ・アンド・ドロップします。
「ドロップ・ターゲットの挿入」ダイアログで、コンポーネントがDVTコンポーネントのドロップへの対応に使用するドロップ・リスナーの名前を入れます。
サンプルのリスナーについては、この章の例を参照してください。
「データ・フレーバの挿入」ダイアログで、ドロップ・ターゲットが受け入れるオブジェクトを入れます。または、ドロップダウン・メニューを使用してオブジェクトの階層をナビゲートし、希望するオブジェクトを選択します。
たとえば、ユーザーがツリーマップ・ノードをtreeTable
コンポーネントにドラッグし、そのコンポーネントにツリーマップについての情報を表示できるようにする場合、org.apache.myfaces.trinidad.model.RowKeySet
をデータ・フレーバに入れます。
構造ウィンドウでaf:dropTarget
コンポーネントを右クリックし、「プロパティに移動」を選択します。
プロパティ・インスペクタにおいて、「アクション」フィールドに、ドロップ・ターゲットが受け入れる操作のリストを、空白で区切って入力します。許容値は、COPY
、MOVE
またはLINK
です。I値を指定しない場合、ドロップ・ターゲットはCOPY
を使用します。
例34-15に、ツリーマップからのドラッグを可能なように構成したaf:outputFormatted
コンポーネントのサンプル・コードを示します。