| Oracle® Fusion Middleware Oracle Application Development Framework Webユーザー・インタフェース開発者ガイド 11gリリース1(11.1.1.9.0) B52029-12 |
|
![]() 前 |
![]() 次 |
この章では、ユーザーが属性やオブジェクトの値をコンポーネントから別のコンポーネントにドラッグしたり、コンポーネントをドラッグ・アンド・ドロップしたりできるようにするドラッグ・アンド・ドロップ機能を、ページに追加する方法について説明します。
この章では、次の項目について説明します。
ADF Facesフレームワークには、ページ上の場所から別の場所へアイテムをドラッグ・アンド・ドロップする機能があります。たとえばFile Explorerアプリケーションでは、ファイルを「表」タブからドラッグし、それを図35-1に示すように、別のディレクトリ・フォルダにドロップできます。
このシナリオでは、あるコレクション(Folder0)のオブジェクトを実際にドラッグして、別のコレクション(Folder3)にドロップします。これは、多数サポートされているドラッグ・アンド・ドロップ・シナリオの1つです。ADF Facesでは、次のシナリオがサポートされています。
属性値をコンポーネント・インスタンスからドラッグして、別のインスタンスへコピーします。たとえば、ユーザーはoutputTextコンポーネントをinputTextコンポーネントにドラッグでき、その結果、outputTextコンポーネントのvalue属性がinputTextコンポーネントのvalue属性になります。
オブジェクトの値をドラッグし、別のオブジェクトの値になるようにドロップします。たとえば、ユーザーはoutputTextコンポーネントを別のoutputTextコンポーネントにドラッグでき、その結果、Stringオブジェクトの配列になり、後者のoutputTextコンポーネントのtext属性に値が移入されます。
図35-1に示すように、あるコレクションのオブジェクトをドラッグして別のコレクションにドロップします。
コンポーネントをページ上の場所から別の場所にドラッグします。たとえば、ユーザーは既存のpanelBoxコンポーネントをpanelGridコンポーネント内の新規の場所にドラッグできます。
カレンダ内のアクティビティをある開始時刻または開始日から別の時刻または日付にドラッグします。
コンポーネントをpanelDashboardコンポーネントへ、または同コンポーネントからドラッグします。
別のコンポーネントからDVTパレートまたは株価チャートにオブジェクトをドロップします。
オブジェクトをDVTガント・チャートから別のコンポーネントにドラッグします。
DVTツリーマップとサンバースト・コンポーネントから1つ以上のノードをドラッグするか、DVTツリーマップとサンバースト・コンポーネントへオブジェクトをドロップします。
1つ以上のノードをDVT階層ビューア内でドラッグ・アンド・ドロップ、1つ以上のノードを階層ビューアから別のコンポーネントへドラッグ、あるいは1つ以上のコンポーネントから階層ビューアへドラッグします。
ユーザーがソースをクリックしてドラッグし始めると、ブラウザにはドラッグされている要素がマウス・ポインタにアタッチされたゴースト要素として表示されます。ゴースト要素が有効なターゲット上に移動すると、そのターゲット・コンポーネントにはなんらかのフィードバック(強調表示されるなど)が現れます。ユーザーがゴースト要素を無効なターゲットにドラッグすると、カーソルが変わり、そのターゲットが有効でないことを示します。
属性値をドラッグするとき、ユーザーはターゲットに対して値のコピーしかできません。他のドラッグ・アンド・ドロップ・シナリオの場合、ドロップでは、要素のコピー(コピーして貼付け)、移動(切り取って貼付け)、リンク(コピーしてリンクとして貼付け(テキストをコピーして実際のURLとして貼付けなど))が可能です。
ドラッグされ値を含むコンポーネントは、ソースと呼ばれます。ドロップを受け入れるコンポーネントは、ターゲットと呼ばれます。ソースおよびターゲット・コンポーネントに子として特定のタグを使用し、フレームワークにドロップを許可するように指示します。表35-1に、ドラッグ・アンド・ドロップの異なるシナリオ、有効なソースとターゲット、およびそのシナリオに使用する、関連付けられたタグを示します。
表35-1 ドラッグ・アンド・ドロップのシナリオ
| シナリオ | ソース | ターゲット |
|---|---|---|
|
属性値のドラッグ |
コンポーネント上の属性値 |
別のコンポーネント上の属性値(同じオブジェクト型である場合) |
|
タグ: |
タグ: |
|
|
オブジェクトをコンポーネントから別のコンポーネントへドラッグ |
すべてのコンポーネント |
すべてのコンポーネント |
|
タグ: |
タグ: |
|
|
アイテムをコレクションからドラッグして別のコレクションにドロップ |
|
|
|
タグ: |
タグ: |
|
|
コンポーネントをコンテナから別のコンテナへドラッグ |
すべてのコンポーネント |
すべてのコンポーネント |
|
タグ: |
タグ: |
|
|
カレンダ・アクティビティをある開始時刻または開始日から別の時刻または日付にドラッグ |
|
|
|
Tag: |
タグ: |
|
|
|
|
|
|
タグ: |
タグ: |
|
|
panelBoxコンポーネントを |
|
すべてのコンポーネント |
|
タグ: |
タグ: |
|
|
別のコンポーネントからパレートまたは株価チャートにオブジェクトをドロップします。 |
|
|
|
タグ: |
タグ: |
|
|
DVTガント・チャートからオブジェクトをドラッグし、別のコンポーネントにドロップ |
ガント・チャート |
すべてのコンポーネント |
|
タグ: |
タグ: |
|
|
DVT階層ビューア、サンバースト、またはツリーマップからノードをドラッグし、別のコンポーネントにドロップします |
|
すべてのコンポーネント |
|
タグ: |
タグ: |
ターゲットにドロップできるオブジェクトの型は、dataFlavorタグを追加することで制限でいます。これは、ターゲットでは1つのオブジェクト型しか受け入れられないのに、ソースが多数の異なる型の1つである場合に役立ちます。dataFlavorタグでは、ターゲットで複数のソースまたは複数の型を含む可能性のあるソースからオブジェクトを受け入れることができるよう、複数の型を設定することもできます。ドロップが成功するためには、ターゲットとソースの両方にdataFlavorタグがあり、dataFlavorが識別値とともにカプセル化するJavaタイプがソースとターゲットの間で同一でなければなりません。
|
注意: ドラッグ・アンド・ドロップ機能は、ウィンドウ間ではサポートされていません。ウィンドウ境界を越えるドラッグは取り消されます。ポップアップ・ウィンドウとポップアップのベース・ページとの間のドラッグ・アンド・ドロップ機能はサポートされています。また、ドラッグ・アンド・ドロップ機能はアクセスできないため、ドラッグ・アンド・ドロップを実行するために使用できるキーボード・ストロークがありません。したがって、アプリケーションですべての機能をアクセス可能にすることが求められる場合、このロジックを提供する必要があります。たとえば、ページでユーザーに、オブジェクトを選択する方法と、選択したオブジェクトを移動できるようにする「移動」ボタンまたはメニュー項目を提供する場合もあります。 |
属性のドラッグ・アンド・ドロップ機能は、あるコンポーネントの属性をターゲットとして定義し、別のコンポーネントの属性をソースとして定義して追加します。
|
注意: ターゲットとソースの属性値は同じデータ型である必要があります。 |
次の手順では、ターゲットとソースのコンポーネントはJSFページにすでにあるものとします。
属性のドラッグ・アンド・ドロップ機能を追加する手順:
「コンポーネント・パレット」で、「操作」パネルから、「属性ドロップ・ターゲット」を、このページのターゲット・コンポーネントに子としてドラッグ・アンド・ドロップします。
「属性ドロップ・ターゲットの挿入」ダイアログで「属性」ドロップダウンを使用して、ドラッグ・アンド・ドロップ・アクションによる移入先の属性を選択します。このドロップダウン・リストには、ターゲット・コンポーネントの有効な属性がすべて表示されます。
ターゲットへの値の代入元のコンポーネントの子として、属性ドラッグ・ソースをコンポーネント・パレットからドラッグ・アンド・ドロップします。
「属性ドラッグ元の挿入」ダイアログで、「属性」ドロップダウンを使用して、ターゲット属性への移入に使用される値の属性を選択します。このドロップダウン・リストには、ソース・コンポーネントの有効な属性がすべて表示されます。
ユーザーが属性値以外をドラッグできるようにする場合、またはあるコンポーネントから別のコンポーネントへ属性をコピーする以外の操作をユーザーができるようにする場合、dropTargetタグを使用します。また、DataFlavorオブジェクトを使用して、ドロップ・ターゲットに対して有効なソースのJava型を決めます。ドロップ・ターゲットとドラッグ・ソースが複数ある場合のために、識別値を使用して有効な組合せを制限できます。ドラッグ・アンド・ドロップ・アクションを受けて必要となる機能の実装も必要です。
たとえば、図35-5に示すように、Stringの配列を持つoutputTextコンポーネントがあり、ユーザーがoutputTextコンポーネントをpanelBoxコンポーネントにドラッグできるようにして、panelBoxにStringの配列を表示させるとします。
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オブジェクトを使用してオブジェクトがドロップ可能なことを確認します。その後、ドロップ・イベントを使用してターゲット・コンポーネントを取得し、ドロップされたオブジェクトを使用してプロパティを更新します。このリスナーの詳細は、35.9.1項「DVTコンポーネントのドラッグ・アンド・ドロップ機能の追加方法」の手順で説明します。
ドラッグ・アンド・ドロップ機能を追加するには、まず、コンポーネントをドラッグ・アンド・ドロップ・アクションのターゲットとして定義するタグをコンポーネントに追加します。次に、ドラッグ・アンド・ドロップ・アクションのロジックを処理するイベント・ハンドラ・メソッドを実装します。最後に、ドラッグ・アンド・ドロップのソースを定義します。
この手順では、ソースとターゲットのコンポーネントはすでにページあるものとします。
ドラッグ・アンド・ドロップ機能を追加する手順:
ターゲットを含むJSFページで、コンポーネント・パレットから(「操作」パネルにある)「ドロップ・ターゲット」タグをドラッグ・アンド・ドロップし、dropTargetタグをターゲット・コンポーネントの子として追加します。
「ドロップ・ターゲットの挿入」ダイアログで、イベントを処理するマネージドBeanのメソッド(このコードはステップ5で作成)に評価される式を入力します。
|
ヒント: clientDropListener属性を挿入して、クライアントでドロップを捕捉することもできます。詳細は、35.3.3項「ClientDropListenerの使用に関する必知事項」を参照してください。 |
「データ・フレーバの挿入」ダイアログで、ターゲットにドロップ可能なオブジェクトのクラス(java.lang.Objectなど)を入力します。この選択は、dataFlavorタグを作成するために使用され、このタグにより、ターゲットにドロップできるオブジェクトの型(StringやDateオブジェクトなど)が決まります。1つのドロップ・ターゲットに複数のdataFlavorタグを使用し、ドロップ・ターゲットでこれらの型のいずれも受け入れるようにすることができます。
|
ヒント: DataFlavorタグに型指定された配列を指定するには、java.lang.Object[]のようにクラス名に大カッコ([])を追加します。 |
構造ウィンドウで、dropTargetタグを選択します。プロパティ・インスペクタで、actions属性に値を選択します。これによって、ドロップ・ターゲットでサポートされるアクションが定義されます。有効な値は、COPY(コピーして貼付け)、MOVE(切り取って貼付け)およびLINK(コピーしてリンクとして貼付け)です。
MOVE COPY
アクションが指定されない場合、デフォルトはCOPYです。
例35-1に、panelBoxコンポーネントに挿入され、配列オブジェクトをドロップ・ソースとするdropTargetコンポーネントのコードを示します。アクションが定義されていないため、許可されるアクションはCOPYのみであることに注意してください。
ステップ2で作成したEL式で参照されるマネージドBeanに、ドラッグ・アンド・ドロップ機能を処理するイベント・ハンドラ・メソッドを(EL式での名前と同じ名前を使用して)作成します。
このメソッドは、DropEventイベントをパラメータとして取り、DnDActionオブジェクトを返します。このオブジェクトは、ソースのドロップ時に実行されるアクションです。有効な戻り値は、DnDAction.COPY、DnDAction.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[]のようにクラス名に大カッコ([])を追加します。
ドラッグ・アンド・ドロップ・フレームワークで、サーバーの |
例35-2に、イベント・ハンドラ・メソッドがコールするプライベート・メソッドを示します(イベント・ハンドラそのものは何もしませんが、このメソッドをコールします。このメソッドには、panelBoxコンポーネントでoutputTextコンポーネントの値となるStringパラメータも必要です)。このメソッドでは、イベント・ペイロードから配列オブジェクトをコピーし、そのイベントを開始したコンポーネントに割り当てます。
例35-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タグの値がソースのペイロードになります。例35-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がデフォルトであるため(順番の1番目)、アクションはCOPYになります。ユーザーが[Ctrl]キーを押している場合は、その修飾子はCOPYと一致し、その結果COPYが実行されます。ユーザーが[Ctrl]キーと[Shift]キーを押していた場合、その修飾子は許可されたアクションの論理積のセットにはないLINKアクションと一致するため、アクションはやはりCOPYになります。
|
注意: JavaとJavaScriptとの間のラウンドトリップで情報が失われるため、ドロップでのデータが見込みとは異なる型の場合があります。たとえば、すべての数値型はdoubleオブジェクトとして、charオブジェクトはStringオブジェクトとして、ListオブジェクトとArrayオブジェクトはListオブジェクトとして、その他の大部分のオブジェクトはMapオブジェクトとして表されます。詳細は、5.4.3項「データのマーシャリングとアンマーシャリングに関する必知事項」を参照してください。 |
dropTargetタグには、クライアントでドロップ・イベントを処理するJavaScriptを参照できるclientDropListner属性が含まれます。クライアント・ハンドラはパラメータをとることはなく、AdfDnDContextアクションを返します。たとえば、メソッドがAdfDnDContext.ACTION_NONEを返すと、ドロップ操作は取り消され、サーバーでコールされません。メソッドがAdfDnDContext.ACTION_COPYを返すと、コピー操作が許可され、dropListenerが存在する場合には、それを実行するコールがサーバーで発生します。
たとえば、ドロップ・イベントの起動時にメッセージをログ出力するとします。メッセージの出力を処理し、サーバー・リスナーが起動されるよう適切なアクションを返すクライアント・ハンドラを作成します。例35-4に、メッセージの出力にロガーを使用するクライアント・ハンドラを示します。
collectionDropTargetおよびdragSourceタグを使用して、ユーザーがコレクションからアイテム(表から行など)をドラッグし、ツリーなどの別のコレクション・コンポーネントにドロップできるドラッグ・アンド・ドロップ機能を追加します。たとえば、File Explorerアプリケーションでは、ユーザーは、ディレクトリの内容を表示する表からディレクトリ・ツリーのフォルダにファイルをドラッグできます。図35-3に、Folder0ディレクトリの内容を表示する表からFolder3ディレクトリにドラッグされるFile0.docオブジェクトを示します。ドロップが完了すると、オブジェクトはFolder3を構成するコレクションの一部になります。
単一オブジェクトのドラッグ・アンド・ドロップ同様、ドロップによってコピー、移動またはコピーしてリンクとして貼り付けたり(あるいは3つを組み合せたり)、dataFlavorタグを使用してターゲットでの受け入れ対象を限定できます。
ターゲット・ソースがコレクションで、移動動作がサポートされている場合、dragDropEndListener属性のメソッドを実装して、ソース・コンポーネントから参照し、ドラッグ・アンド・ドロップ操作後のコレクションのクリーン・アップに使用することもできます。詳細は、35.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を返して、ドロップが拒否されたことを示します。
例35-5に、2つの表の間での行のコピーを処理するcollectionDropTargetデモに使用されるCollectionDnd.javaマネージドBeanのイベント・ハンドラ・メソッドを示します。
例35-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属性が含まれます。
たとえば、ドラッグ・アンド・ドロップでオブジェクトを移動する場合、ドロップの正常終了後にソース・コンポーネントからオブジェクトを物理的に削除する必要があります。例35-6に、dragDropEndListener属性のハンドラを示します。
例35-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());
ある親から別の親へのコンポーネントの移動を可能にしたり、親コンポーネントの子コンポーネントの並替えを可能にしたりできます。例として、図35-4に、panelGridコンポーネントの最初の子で最後に移動される暗色のpanelBoxコンポーネントを示します。
|
注意: panelDashboardコンポーネントでのコンポーネントの出し入れを行う場合、そのコンポーネント固有のプロシージャを使用する必要があります。詳細は、35.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を返します。
例35-7に、デモ・アプリケーションのcomponentDragSource JSFページで使用されるDemoDropHandler.javaマネージドBeanのhandleComponentMoveイベント・ハンドラを示します。
例35-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の外にもう1つのコンポーネントを作成します。panelBoxコンポーネントの詳細は、8.10.3項「panelBoxコンポーネントの使用方法」を参照してください。
panelDashboardコンポーネントにドラッグ・アンド・ドロップ機能を追加する手順:
構造ウィンドウで、ターゲット・コンポーネントとなる「panelDashboard」コンポーネントを選択します。
プロパティ・インスペクタで、「DropListener」に、マネージドBean上でドロップ・イベントを処理するメソッド(このコードはステップ6で作成)として評価される式を入力します。
コンポーネント・パレットで、「操作」パネルから、「データ・フレーバ」をドラッグし、子として「panelDashboard」コンポーネントにドロップします。
「データ・フレーバの挿入」ダイアログで、javax.faces.component.UIComponentを入力します。
プロパティ・インスペクタで、Discriminantを、panelDashboardコンポーネントへのドラッグを許可されたコンポーネントを識別する一意の名前(dragIntoDashboardなど)に設定します。
ステップ2で作成したEL式で参照されるマネージドBeanに、ドラッグ・アンド・ドロップ機能を処理するイベント・ハンドラ・メソッドを(EL式での名前と同じ名前を使用して)dropListener属性に対して作成します。
panelDashboardではその子コンポーネントの配置が処理されるため、このメソッドでは、パラメータとしてDropEventイベントを使用し、NONEのDnDActionを返す必要があります。
このハンドラ・メソッドは、dropEvent.getTransferable().getData(DataFlavor.UICOMPONENT_FLAVOR)を使用して、Transferableオブジェクトとそのデータを取得します。メソッドによりドロップが完了すると、org.apache.myfaces.trinidad.change.ReorderChildrenComponentメソッドを使用して子の新規順序を保存し、
ChangedropEvent.getDropSiteIndex()メソッドを使用してユーザーがドラッグしたコンポーネントを置く場所を取得することができます。dashboardComponent.prepareOptimizedEncodingOfInsertedChild()メソッドを使用して、コンポーネントのドロップをアニメーション化することもできます。
例35-8に、ADF Facesデモ・アプリケーションでdashboard JSFページにより使用されるDemoDashboardBean.javaマネージドBeanでのmoveイベント・ハンドラおよびヘルパー・メソッドを示します。
例35-8 panelDashboard Component上の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」コンポーネントにドロップします。
プロパティ・インスペクタで、「Discriminant」をステップ5で「panelDashboard」上の「Discriminant」に入力したのと同じ値になるように設定します。
panelDashboardコンポーネントからのドラッグ・アンド・ドロップ機能の実装は、識別値付きのdataFlavorタグを使用する必要があることを除けば、その他のコンポーネントの標準のドラッグ・アンド・ドロップ機能と同様です。
panelDashboardコンポーネントからドラッグ・アンド・ドロップ機能を追加する方法:
コンポーネント・パレットで、「操作」パネルから、「ドロップ・ターゲット」をターゲット・コンポーネントに子としてドラッグ・アンド・ドロップします。
「ドロップ・ターゲットの挿入」ダイアログで、イベントを処理するマネージドBeanのメソッド(このコードはステップ5で作成)に評価される式を入力し、javax.faces.component.UIComponentを「FlavorClass」として入力します。
「dropTarget」タグを選択した状態のまま、プロパティ・インスペクタでaction属性の値として「MOVE」を選択します。
構造ウィンドウで、「dataFlavor」タグを選択し、プロパティ・インスペクタで、「Discriminant」をこのコンポーネントへのドラッグを許可されたpanelBoxコンポーネントを識別する一意の名前(dragOutOfDashboardなど)に設定します。
ステップ2で作成したEL式で参照されるマネージドBeanに、ドラッグ・アンド・ドロップ機能を処理するイベント・ハンドラ・メソッドを(EL式での名前と同じ名前を使用して)dropListener属性に対して作成します。
このハンドラ・メソッドでは、DropEventイベントを使用してTransferableオブジェクトとそのデータを取得し、移動を完了して、必要に応じてコンポーネントを並べ替えます。ドロップを完了したら、メソッドではNONEのDnDActionを返します。
dashboardComponent.prepareOptimizedEncodingOfDeletedChild()メソッドを使用して、panelBoxコンポーネントの削除をアニメーション化できます。
例35-9に、デモ・アプリケーションのJSFページdashboardで使用されるマネージドBeanDemoDashboardBean.javaに対するイベント・ハンドラhandleSideBarDropとヘルパー・メソッドを示します。
例35-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);
}
コンポーネント・パレットで、「操作」パネルから、「コンポーネント・ドラッグ元」をソースのpanelBoxコンポーネントの子として「panelDashboard」コンポーネントにドラッグ・アンド・ドロップします。
プロパティ・インスペクタで、「Discriminant」をステップ4でターゲット・コンポーネントのdataFlavorタグ上の「Discriminant」に入力したのと同じ値になるように設定します。
Calendarには、ユーザーがアクティビティのハンドルをドラッグして終了時間を変更できる機能が含まれています。ただし、ユーザーがアクティビティを別の開始時間、さらには別の日にドラッグ・アンド・ドロップできるようにする場合は、ドラッグ・アンド・ドロップ機能を実装します。ドラッグ・アンド・ドロップを使用すると、アクティビティを移動できるだけでなく、コピーすることもできます。
calendarDropTargetタグを使用して、ドラッグ・アンド・ドロップ機能を追加します。コレクションをドラッグ・アンド・ドロップするのと異なり、ソース・タグの必要はなく、アクティビティの移動はターゲット(アクティビティの移動先のオブジェクト、この場合はカレンダ)の役割です。ソース(移動またはコピーされるアイテム)がカレンダ内のアクティビティである場合、calendarDropTargetタグのみを使用します。タグは、転送可能なものがcalendarActivityオブジェクトであると予測します。
ただし、Calendarの外からオブジェクトをドラッグ・アンド・ドロップすることもできます。この操作を有効にする場合は、ソース・オブジェクト(calendarActivityオブジェクト以外のオブジェクト)をドロップできるように構成されているdataFlavorタグを使用します。
Calendarにドラッグ・アンド・ドロップ機能を追加する手順:
コンポーネント・パレットで、「操作」パネルから、「カレンダ・ドロップ・ターゲット」を子として「calendar」コンポーネントにドラッグ・アンド・ドロップします。
「Calendarドロップ・ターゲットの挿入」ダイアログで、イベントを処理するマネージドBeanのメソッドに対して評価されるdropListener属性の式を入力します(このコードは手順4で作成)。
プロパティ・インスペクタで、「Actions」を設定します。この値で、アクティビティ(または他のソース)の移動、コピー、リンクとしてコピー、またはこの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など)を入力します。
|
ヒント: dataFlavorタグに型指定された配列を指定するには、java.lang.Object[]のようにクラス名に大カッコ([])を追加します。 |
Calendar内のドラッグ・アンド・ドロップ・アクティビティの場合、ユーザーは表示内でのみドラッグ・アンド・ドロップを行うことができます。つまり、ユーザーは、日表示内の1つの時間スロットから別の時間スロットにアクティビティをドラッグできますが、日表示からアクティビティを切り取り、月表示に貼り付けることはできません。
ユーザーが日表示または週表示でアクティビティをドラッグ・アンド・ドロップしている場合、Calendarでは30分ごとにドロップ・サイトがマークされます。日表示では、終日のアクティビティまたは複数日のアクティビティは移動できません。
週表示では、終日のアクティビティおよび複数日のアクティビティを移動できますが、その他の終日のスロットにのみドロップできます。つまり、終日のアクティビティを、開始時間と終了時間が設定されているアクティビティには変更できません。月表示では、終日のアクティビティおよび複数日のアクティビティを任意の日に移動できます。
他のADFコンポーネントからドロップ可能なドロップ・ターゲットとして、パレートおよび株価チャートを構成できます。たとえば、ADF表セルからのドロップを可能にする株価チャートを構成できます。
パレートまたは株価チャートをドロップ・ターゲットとして構成するには、af:dropTargetタグをパレートまたは株価チャートの子として追加し、ドロップ・イベントに応答するマネージドBeanのメソッドを追加します。例35-10に、ADF表からドロップを受け取るように構成されたグラフのドロップ・リスナーのサンプルを示します。
例35-10 ドラッグ・アンド・ドロップ・ターゲットを処理するためのマネージドBeanのサンプル
public class dragAndDrop {
public DnDAction fromTableDropListener(DropEvent event) {
Transferable transferable = event.getTransferable();
DataFlavor<RowKeySet> dataFlavor = DataFlavor.getDataFlavor(RowKeySet.class, "fromTable");
RowKeySet set = transferable.getData(dataFlavor);
Employee emp = null;
if(set != null && !set.isEmpty()) {
int index = (Integer) set.iterator().next();
emp = m_tableModel.get(index);
}
if(emp == null)
return DnDAction.NONE;
DnDAction proposedAction = event.getProposedAction();
if(proposedAction == DnDAction.COPY) {
m_graphList.add(emp);
}
else if(proposedAction == DnDAction.LINK) {
m_graphList.add(emp);
}
else if(proposedAction == DnDAction.MOVE) {
m_graphList.add(emp);
m_tableModel.remove(emp);
}
else
return DnDAction.NONE;
RequestContext.getCurrentInstance().addPartialTarget(event.getDragComponent());
return event.getProposedAction();
}
ADF Facesコンポーネント、オブジェクトまたはコレクションもドラッグ・ソースとして構成し、ドラッグに応答するメソッドを定義する必要があります。
始める前に:
ドラッグ・アンド・ドロップ機能について理解しておくと役立ちます。詳細は、35.1項「ドラッグ・アンド・ドロップ機能の概要」を参照してください。
次のタスクを実行する必要があります。
パレートまたは株価チャートをページに追加します。詳細は、H.2.3項「ページへのグラフの追加方法」を参照してください。
DVTコンポーネントへのドロップを可能にする予定であれば、ドラッグ・ソースとするコンポーネントをページに加えます。
他のADF Facesコンポーネント追加の詳細は、第1.3項「ADF Facesコンポーネント」を参照してください。
グラフにドロップをリスニングするメソッドを作成します。マネージドBeanの使用の詳細は、2.6項「マネージドBeanの作成と使用」を参照してください。
パレートまたは株価チャートをドロップ・ターゲットとして構成する手順:
「構造」ウィンドウで、「dvt:paretoGraph」または「dvt:stockGraph」を右クリックし、「(dvt:paretoGraphまたはdvt:stockGraph)の中に挿入」→「af:dropTarget」を選択します。
「ドロップ・ターゲットの挿入」ダイアログで、コンポーネントでドロップが発生したときに呼び出されるoracle.adf.view.rich.event.DropEventメソッドへの参照を評価するEL式として「DropListener」を指定します。
例35-10で使用されているDropListenerを指定するには、#{dragAndDrop.fromTableDropListener}と入力します。
「データ・フレーバの挿入」ダイアログで、このdataFlavorの完全修飾Javaクラス名であるflavorClassを指定します。ドロップがこのdataFlavorを含むとき、ドロップ・ターゲットではdataFlavorを使用して、このJavaタイプを持つドロップからオブジェクトを取得することが保証されます。
たとえば、ADF表からドロップを可能にするように構成されたドロップ・ターゲットにflavorClassを指定するには、org.apache.myfaces.trinidad.model.RowKeySetと入力します。
ドロップ・イベントのリスナーも実装する必要があります。ドロップ・イベントのオブジェクトはTransferableと呼ばれ、ドロップのペイロードを含みます。リスナーはTransferableオブジェクトにアクセスし、ここからDataFlavorオブジェクトを使用してオブジェクトがドロップ可能なことを確認します。その後、ドロップ・イベントを使用してターゲット・コンポーネントを取得し、ドロップされたオブジェクトを使用してプロパティを更新します。
ユーザーがガント・チャートとその他のコンポーネントとの間でドラッグ・アンド・ドロップできるようにする場合、dragSourceタグとdropTargetタグを使用します。また、DataFlavorオブジェクトを使用して、ドロップ・ターゲットに対して有効なソースのJava型を決めます。ドラッグ・アンド・ドロップ・アクションを受けて必要となる機能の実装も必要です。projectGanttおよびschedulingGanttコンポーネントでは、ドラッグ・アンド・ドロップ機能がサポートされています。
たとえば、projectGanttコンポーネントがあり、ユーザーがタイムラインをtreeTableコンポーネントにドラッグできるようにし、そのコンポーネントにタイムラインに関する情報が図35-5のように表示されるとします。
projectGanttコンポーネントにはdragSourceタグが含まれます。ユーザーは、表示された出力テキストのString値のみでなく、オブジェクト全体をドラッグするため、attributeDropTargetタグのかわりにdropTargetタグを使用します。
また、dataFlavorタグを使用して、ドロップされるオブジェクトの型を決めます。このタグでは、識別値を定義できます。同じオブジェクト型の2つのターゲットと2つのソースがある場合に、これは有用です。識別値を作成することで、各ターゲットで有効なソースのみが受け入れられることが保証されます。たとえば、TaskDragInfoオブジェクトを受け入れるTargetAとTargetBの2つのターゲットがあるとします。TaskDragInfoブジェクトのソースも2つあるとします。TargetAにalphaという値を使用して識別値を設定することにより、識別値alphaを持つTaskDragInfoソースのみが受け入れられます。
ドロップ・イベントのリスナーも実装する必要があります。ドロップ・イベントのオブジェクトはTransferableと呼ばれ、ドロップのペイロードを含みます。リスナーはTransferableオブジェクトにアクセスし、ここからDataFlavorオブジェクトを使用してオブジェクトがドロップ可能なことを確認します。その後、ドロップ・イベントを使用してターゲット・コンポーネントを取得し、ドロップされたオブジェクトを使用してプロパティを更新します。
ドラッグ・アンド・ドロップ機能を追加するには、まず、コンポーネントをドラッグ・アンド・ドロップ・アクションのターゲットとして定義するタグをコンポーネントに追加します。次に、ドラッグ・アンド・ドロップ・アクションのロジックを処理するイベント・ハンドラ・メソッドを実装します。最後に、ドラッグ・アンド・ドロップのソースを定義します。実行時に行われる処理の詳細は、35.3.2項「実行時に行われる処理」を参照してください。clientDropListener属性の使用方法の詳細は、35.3.3項「ClientDropListenerの使用に関する必知事項」を参照してください。
ドラッグ・アンド・ドロップ機能を追加する手順:
コンポーネント・パレットで、「操作」パネルから、「ドロップ・ターゲット」タグをドラッグし、子としてターゲット・コンポーネントにドロップします。
ドロップ・ターゲットの挿入ダイアログで、イベントを処理するマネージドBeanのメソッド(このコードはステップ6で作成)に評価される式を入力します。
|
ヒント: clientDropListener属性を挿入して、クライアントでドロップを捕捉することもできます。詳細は、35.3.3項「ClientDropListenerの使用に関する必知事項」を参照してください。 |
「データ・フレーバの挿入」ダイアログで、ターゲットにドロップ可能なオブジェクトのクラス(java.lang.Objectなど)を入力します。この選択は、dataFlavorタグを作成するために使用され、このタグにより、ターゲットにドロップできるオブジェクトの型が決まります。1つのドロップ・ターゲットに複数のdataFlavorタグを使用し、ドロップ・ターゲットでこれらの型のいずれも受け入れるようにすることができます。
|
ヒント: DataFlavorタグに型指定された配列を指定するには、java.lang.Object[]のようにクラス名に大カッコ([])を追加します。 |
プロパティ・インスペクタで、必要に応じて、「Discriminant」の値を設定します。識別値は、dataFlavorで指定されたタイプのどのソースがソースとして受け入れられるかを判断するために使用される任意の文字列です。
構造ウィンドウで、dropTargetタグを選択します。プロパティ・インスペクタで、アクションの値を選択します。これによって、ドロップ・ターゲットでサポートされるアクションが定義されます。有効な値は、COPY(コピーして貼付け)、MOVE(切り取って貼付け)およびLINK(コピーしてリンクとして貼付け)です。
MOVE COPY
アクションが指定されない場合、デフォルトはCOPYです。
例35-11に、ドロップ・ソースとしてTaskDragInfoオブジェクトをとるdropTargetコンポーネントのコードを示します。actions属性の値としてCOPYが設定されているため、それが許可される唯一のアクションになります。
例35-11 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および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[]のようにクラス名に大カッコ([])を追加します。
ドラッグ・アンド・ドロップ・フレームワークで、サーバーの |
例35-12に、イベント・ペイロードからTaskDragInfoオブジェクトをコピーし、そのイベントを開始したコンポーネントに割り当てるハンドラ・メソッドを示します。
例35-12 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つ以上のアイテムをドラッグします
図35-6に、その中でのドラッグ・アンド・ドロップを可能とするように構成した階層ビューアを示します。ノードをクリックし0.5秒を超えて保持すると、バックグラウンドにドラッグして階層内の別のルートにしたり、別のノードにドラッグしてそのノードの子として追加したりすることができます。
ノードを別のノードにドラッグすると、ドラッグされたノードとその子は、ターゲット・ノードの子となる。図35-7に、Nina Evansのデータを含むノードへのドラッグの結果を示します。Nancy Greenとその部下は、今はNina Evansの部下として示されます。
サンバーストは、1つ以上のノードの別コンポーネントへのドラッグをサポートします。ドラッグのペイロードは、org.apache.myfaces.trinidad.model.RowKeySetです。サンバーストが別のオブジェクトからのドロップを受け入れるように構成することもできます。
図35-8に、それからaf:outputFormattedコンポーネントへのドラッグを可能とするように構成されたサンバーストを示します。サンバーストが複数選択が可能なように構成されている場合、ユーザーは複数のノードをCtrl+D操作でドラッグできます。
ツリーマップは、1つ以上のノードの別コンポーネントへのドラッグをサポートします。ドラッグのペイロードは、org.apache.myfaces.trinidad.model.RowKeySetです。ツリーマップが別のオブジェクトからのドロップを受け入れるように構成することもできます。
図35-9に、ドロップ・ターゲットとして構成されたツリーマップを示します。この例では、ドラッグ・ソースはaf:outputFormattedコンポーネントです。
ドラッグ・アンド・ドロップの機能を追加するには、第一に、サポート対象のDVTコンポーネントに、ドラッグ・アンド・ドロップ・アクションのターゲットとしてそれを定義しているタグを追加します。次に、ドラッグ・アンド・ドロップ・アクションのロジックを処理するイベント・ハンドラ・メソッドを実装します。最後に、ドラッグ・アンド・ドロップのソースを定義します。実行時に行われる処理の詳細は、35.3.2項「実行時に行われる処理」を参照してください。clientDropListener属性の使用方法の詳細は、35.3.3項「ClientDropListenerの使用に関する必知事項」を参照してください。
始める前に:
ドラッグ・アンド・ドロップ機能について理解しておくと役立ちます。詳細は、35.1項「ドラッグ・アンド・ドロップ機能の概要」を参照してください。
次のタスクを実行する必要があります。
DVTコンポーネントをユーザーのページに加えます。
DVTコンポーネント作成時のヘルプについては、第23章「ADFデータ視覚化コンポーネントの概要」を参照してください。
DVTコンポーネントへのドロップを可能にする予定であれば、ドラッグ・ソースとするコンポーネントをページに加えます。
他のADF Facesコンポーネント追加の詳細は、第1.3項「ADF Facesコンポーネント」を参照してください。
DVTコンポーネントから別のコンポーネントヘのドラッグを可能にする予定であれば、ドロップ・ターゲットとするコンポーネントをページに加えます。
DVT階層ビューア、サンバースト、あるいはツリーマップ・コンポーネントにドラッグ・アンド・ドロップ機能を追加するには:
DVTコンポーネントをドロップ・ターゲットとして構成するには、次を実行します。
コンポーネント・パレットで、「操作」パネルから、「ドロップ・ターゲット」タグをドラッグし、ドラッグ・アンド・ドロップをサポートするDVTコンポーネントの子としてドロップします。
「ドロップ・ターゲットの挿入」ダイアログで、イベントを処理するマネージドBean上のドロップ・リスナー・メソッド(このコードはステップ6で作成)に評価される式を入力します。
|
ヒント: clientDropListener属性を挿入して、クライアントでドロップを捕捉することもできます。詳細は、35.3.3項「ClientDropListenerの使用に関する必知事項」を参照してください。 |
「データ・フレーバの挿入」ダイアログで、ターゲットにドロップ可能なオブジェクトのクラス(java.lang.Objectなど)を入力します。この選択は、dataFlavorタグを作成するために使用され、このタグにより、ターゲットにドロップできるオブジェクトの型が決まります。1つのドロップ・ターゲットに複数のdataFlavorタグを使用し、ドロップ・ターゲットでこれらの型のいずれも受け入れるようにすることができます。
|
ヒント: DataFlavorタグに型指定された配列を指定するには、java.lang.Object[]のようにクラス名に大カッコ([])を追加します。 |
プロパティ・インスペクタで、必要に応じて、「Discriminant」の値を設定します。識別値は、ターゲットにドロップできるソースを判断するために使用される任意の文字列です。たとえば、どちらもjava.lang.Objectを受け入れる2つのツリーマップ、ツリーマップAとツリーマップBがあるとします。ソースも2つあり、どちらもjava.lang.Objectオブジェクトです。GraphAにalphaという値を使用して識別値を設定することにより、識別値alphaを持つjava.lang.Objectソースのみが受け入れられます。
構造ウィンドウで、dropTargetタグを選択します。プロパティ・インスペクタで、アクションの値を選択します。これによって、ドロップ・ターゲットでサポートされるアクションが定義されます。有効な値は、COPY(コピーして貼付け)、MOVE(切り取って貼付け)およびLINK(コピーしてリンクとして貼付け)です。
MOVE COPY
アクションが指定されない場合、デフォルトはCOPYです。
例35-13に、java.lang.Objectをドラッグ・ソースとして受け入れるツリーマップ・コンポーネントのコードを示します。actions属性の値としてCOPYが設定されているため、それが許可される唯一のアクションになります。
例35-13 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および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[]のようにクラス名に大カッコ([])を追加します。
ドラッグ・アンド・ドロップ・フレームワークで、サーバーの |
例35-14に、イベント・ペイロードからjava.lang.Objectオブジェクトをコピーして、イベントを開始したコンポーネントに割り当てるハンドラ・メソッドを示します。
例35-14 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タグを選択している場合、プロパティ・インスペクタで、ターゲットに構成される、許容アクションと必要な識別値を設定します。
例35-15に、ドラッグ・ソースとして構成された、ツリーマップのJSPコードを示します。すべてのアクション(COPY、MOVEおよびLINK)が許されることに注意します。
例35-15 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を使用します。
例35-16に、ツリーマップからのドラッグを可能なように構成したaf:outputFormattedコンポーネントのサンプル・コードを示します。