この章の内容は次のとおりです。
JDeveloperでは、オープン・アーキテクチャが使用されているため、特定のニーズがある場合、または開発チームが使用する外部のプロセスやツールにJDeveloperを統合する必要がある場合には、独自の拡張機能を作成できます。メニュー・アイテムの追加、コンテキスト・メニューの作成、JDeveloperツールバーへの機能の組込み、データ・オブジェクトのビューを表示するドッキング可能なウィンドウの作成などを行うことができます。
この項では一連のユースケースを説明します。拡張機能を計画するとき、または宣言トリガー・フックを使用したり遅延初期化をサポートするために以前のバージョンのJDeveloper用に作成された既存の拡張機能を変換する場合に、このようなユースケースに直面することがあります。ロードおよび実行が迅速に実行される拡張機能を作成するためには、次に示す推奨事項に従ってください。
拡張機能では、メニュー・アイテムに関連付けられたアクションの有効状態を設定することで、メニュー秘密度を制御します。これは、そのアクションに関連付けられたoracle.ide.controller.Controllers
の1つによって決定されます。アクションはトリガー・フックであるため、アクションに関連付けられたoracle.ide.controller.Controller
実装は、そのコントローラを所有する拡張機能が初期化されるまでは呼び出されません。単純なルールの設定例は、「単純なルールの定義方法」を参照してください。
次の一般的な状況について考えてください。メニュー・アイテムM1はアクションA1に関連付けられています。また、このアクションはいくつかのコントローラに関連付けられています。これらのコントローラは、所定のコンテキストでアクションA1を処理するかどうかを示すことができます。選択されているアクションを処理する最初のコントローラは、アクションの有効状態を設定します。
具体的な例では、EditCopyがaction IdeConstants.COPY_CMD_ID
に関連付けられており、これはテキストのコピー方法を認識するコントローラと、ビジュアル・オブジェクト(UIコンポーネントなど)のコピー方法を認識する別のコントローラに関連付けられています。
従来、このパターンのユースケースでは、メニューが表示されるときや、ツールバー・ボタンの有効状態が変化するときなど、JDeveloperによってコンテキストが変更される際に、パフォーマンスの問題が発生していました。たとえば、ユーザーが現在の選択の変更、現在のビューの変更、または現在のアクティブ・プロジェクトの変更を行う場合です。
こうした状況で処理に時間がかからないようにするには、ルールに基づくアクション秘密度制御を使用して拡張機能のメニューを開発します。コントローラは拡張機能のマニフェスト・ファイルで宣言によって定義されます。詳細は、「拡張機能マニフェストの操作」を参照してください。
コントローラ定義の中で、次のようなアクションの有効状態を制御するアクション更新ルールを指定します。
常に有効にする
アクティブなアプリケーションが存在するときに有効にする
アクティブなプロジェクトが存在するときに有効にする
コンテキストにノードがあるときに有効にする
コンテキストにタイプXのノードがあるときに有効にする
コンテキストに選択内容があるときに有効にする
コンテキストに1つの選択内容があるときに有効にする
コンテキストに複数の選択内容があるときに有効にする
コントローラでは複数のルールを定義できます。最も具体的なルールをルール定義の最初に指定する必要があります。
JDeveloperがコントローラのルールに基づく秘密度を分析した後で、そのコントローラを所有する拡張機能が初期化されます。拡張機能が初期化されると、拡張機能のController.update()
メソッドがアクションの有効状態を処理します。コントローラで処理が行われない場合、拡張機能の操作は定義されたルールに従います。GUIの応答に影響しないように、すべてのController.update()
メソッドがfalse
を返すことをお薦めします。
コントローラが指定するルールでは、アクションの有効状態が宣言によって決定されます。このとき、「ルール・ベースのメニュー秘密度について」で説明するアクション有効化ルールが使用されます。メニューが有効になり、ユーザーがそのメニューを実行すると、拡張機能が必要な処理を実行して、メニューの実行が正常に動作できるようにします。
Controller.update()
の以前の実装は、アクションの有効状態を判別するために複雑で時間のかかるコードを実行していました。現在のメニュー秘密度モデルを使用すると、アクションの有効状態は宣言で決定することができ、実行する適切なアクションの選択にかかる時間が短縮されます。
コントローラの動作を制御するルールを次に示します。
拡張機能が初期化される場合:
メニューがまもなく表示されます。
ルール・ベース・コントローラの場合、ルールが評価されます。false
であれば、フレームワークによってメニューがグレー表示されます。true
の場合またはルールベース・コントローラでない場合は、次の項目を参照してください。
Controller.update()
が呼び出されます。これでtrue
が返されると、他のコントローラは処理されません。コントローラは、アクションの有効状態または無効状態をupdate()
メソッド内で設定する必要があります。
ユーザーがアクティブ・アクションを選択します。Controller.update()
が呼び出されます。これでtrue
が返されると、他のコントローラは処理されません。コントローラは、アクションの有効状態または無効状態をupdate()
メソッド内で設定する必要があります。
拡張機能が初期化されない場合:
メニューがまもなく表示されます。コントローラのルールが評価されます。false
であれば、フレームワークによってメニューがグレー表示されます。true
の場合、フレームワークによってアクティブ化されます。
ユーザーが、初期化されていない拡張機能のアクティブ・メニューを選択した場合:
Controller.update()
が呼び出されます。update()
がfalse
を返すと例外がスローされます。コントローラのルールがtrue
に評価された場合はコントローラのupdate()
メソッドもtrue
を返す必要があることが通知され、注意を促すログ・メッセージが表示されます。update()
からtrue
が返された場合は、次の項目に進みます。
アクションが有効か無効かが確認されます。アクションが有効な場合は、Controller.handleEvent()
が呼び出されます。アクションが無効な場合は、次の項目に進みます。
コントローラがTriggerController
の場合、フレームワークによって、アクションが実行されない理由を知らせるメッセージがユーザーに表示されます。TriggerController
でない場合は、例外がスローされ、このコントローラがTriggerController
である必要があると通知されます。
つまり、1つ目または3つ目の条件が発生した場合は、宣言によって対処する必要があります。
図2-1 初期化されない拡張機能のフロー・ダイアグラム
動的なメニュー・ラベルおよびアイコンは、ユーザーが選択するアプリケーション、プロジェクトまたはノードによって変化するメニュー・アイテムです。拡張機能の内部では、動的メニュー・ラベルが選択されるとコードを実行します。これは、ユーザーがメニューを選択したときに表示されるメニュー・ラベル文字列またはアイコン(あるいは両方)を変更するためです。
ユーザーが動的メニューを選択すると、JDeveloperによって、選択された要素のショート・ラベルがメニュー・アイテム・ラベルに付加されます。これは次のように表示されます。
Run > Run myproject.jpr
一般的にこれらのメニューは、選択されたアプリケーション、プロジェクト、ノードまたは要素によって異なります。拡張機能は、コントローラ・フックを使用して、アクション更新ルールに基づいてラベルを更新するようにJDeveloperに要求できます。詳細は、「ルール・ベースのメニュー秘密度について」を参照してください。
メニュー・ラベルが更新され、ルールに指定されているように要素に関連付けられている短縮名が追加されます。この要素は、アプリケーション、プロジェクトまたはノードです。
ソース・トップ・レベル・メニューのような、動的トップ・レベル・メニューを構成するときは、トップ・レベル・メニューと同じトリガー・フックを使用して宣言的に定義します。詳細は、「メニューの作成および変更方法」を参照してください。
メニュー・アイテムが動的トップ・レベル・メニューに含まれるかどうかを決定するものとして、次の2つがあげられます。
エディタ・タイプ
メニュー・タイプ
これら2つの条件が満たされると、アクティブ・エディタや開いているノードに対して宣言的に定義された動的メニューが、トップ・レベル・メニューとして表示されます。拡張機能のユーザーがこのメニューを選択するとき、メニュー・アイテム秘密度は、メニュー・アイテムに関連付けられたアクションの有効状態を設定することで処理されます。詳細は、「ルール・ベースのメニュー秘密度について」を参照してください。
ノード・レコグナイザが、特定のURLによってポイントされたリソースに関連付けられているoracle.ide.model.Node
サブクラスを認識します。
JDeveloperでは次の2つの標準レコグナイザが提供されます。
URLそのもので提供される情報に基づいてファイル拡張子などのノード・タイプを認識できるレコグナイザ。
XMLファイルの内容に基づいてXMLノード・タイプを認識できるレコグナイザ。
以前のバージョンのJDeveloperでは、カスタム・レコグナイザ実装を登録することもできました。現在、この方法は非推奨になっています。
Addin.initialize()
メソッドは、次のいずれかのメソッドを使用してoracle.ide.mode.Recognizerクラスのカスタム実装を登録します。
Recognizer.registerRecognizer(String, Recognizer)
Recognizer.registerRecognizer(String[], Recognizer)
Recognizer.registerLowPriorityRecognizer(Recognizer)
カスタム・レコグナイザを提供する拡張機能は、JDeveloperのレコグナイザが処理できるように、ノード認識を調整する必要があります。
以前のJDeveloperバージョン用に開発した拡張機能(IDE標準レコグナイザ使用)を作成し直している場合は、Addin.initialize()
メソッドからレコグナイザ登録コードを削除し、レコグナイザ・トリガー・フックを使用して、拡張機能マニフェスト・ファイルextension.xml
に認識ルールを登録する必要があります。詳細は、Oracle Fusion Middleware Oracle Extension SDK Java APIリファレンスのRecognizer
、および拡張機能マニフェストの操作を参照してください。
JDeveloperはコンテンツ・セットを使用して、「アプリケーション」ウィンドウにノードとして表示されるカテゴリを定義します。JDeveloperに組み込まれているカテゴリは次のとおりです。
アプリケーション・ソース
Webソース
リソース
コンテンツ・セットは宣言によって登録されますが、そのコンテンツ・セットを導入した拡張機能の初期化をトリガーすることはありません。コンテンツ・セットではカスタム動作は必要ないためです。拡張機能のどこにコンテンツがあるかを示すために、コンテンツ・セットのID、ラベルおよびデフォルトURLを指定する必要があります。
ContentLevelFilter
のインスタンスがクライアント動作を指定し、これによりコンテンツ・セットに何が表示されるかが制御されます。
ContentLevelFilter
は、ContentLevel
クラスによって実装される横型トラバースをフィルタリングし、物理表現と異なる各レベルの仮想表現を提供します。ContentLevelFilter
では次の処理を行うことができます。
表示に新しい要素を追加します。
表示から要素を削除します。
表示からサブディレクトリを削除します。
サブディレクトリを表示します(空の場合も)。
ContentLevelFilter
のインスタンスは、クラスContentLevel
の静的メソッドaddContentLevelFilter(ContentLevelFilter)
によって静的に登録されます。
「アプリケーション」ウィンドウで新しいアプリケーションが作成されるか開かれた後、拡張機能ユーザーがプロジェクトのトップレベル・フォルダを展開すると、そのプロジェクトのすべてのフォルダやファイルが追加される前に(BaseTreeExplorer
のopen
メソッドが使用される)、クラスContentLevel
のメソッドapplyContentLevelFilters(Context, List, List)
が呼び出されます。このメソッドは次のように機能します。
すべてのソース・ルート・ディレクトリを取得します。
登録されているContentLevelFilter
のインスタンスごとに、所定のContext
にフィルタを適用できるかどうかをチェックします。適用できる場合は、メソッドupdateDir(URLPath, String, List, List, Context context)
を呼び出します。このメソッドは、要素やサブディレクトリが表示される前に各レベルの要素やサブディレクトリのリストを変更できます。同じレベルに変更を適用するContentLevelFilter
のインスタンスが複数ある場合、後のフィルタは前のフィルタの効果を認識して、適切ならば、さらにフィルタリングします。
AsynchronousContentLevelFilter
、ContentLevel
のインスタンスについても前の手順と同じ処理をします。また、そのようなフィルタからCallable
を取得します。これは、追加要素を取得するために非同期リクエストを実行します。
注意:
ContentLevelFilter
をContext
に適用できるかどうかを判別するために、ContentLevel
がすべてのコンテンツ・セット・キーをそのフィルタから取り出し、コンテキストにプロパティとして少なくとも1つのキーが含まれるかどうかを確認します。
ContentLevelFilter
には、宣言登録は必要ありません。フィルタリングが行われる前に、NodeFactory
を使用してノードが作成されます。これは、レコグナイザを使用してURLからノードを作成します。レコグナイザはトリガー・フックであるため、フィルタリングが発生するまでには、関連する拡張機能がすでに初期化されます。
一般的に、コンテンツ・レベル・フィルタを登録する拡張機能はレコグナイザ・ルールも登録します。したがって、登録したレコグナイザ・ルールによってノード・タイプが認識されると、拡張機能は常に初期化されます。たとえば、「アプリケーション」ウィンドウの場合、ユーザーが「アプリケーション」ウィンドウでフォルダを展開すると、そのフォルダの下にあるすべてのファイルに対するノードのインスタンスが作成され、それによって拡張機能の初期化がトリガーされるようになります。その時点で、JDeveloperがコンテンツ・レベル・フィルタを呼び出します。これで、フィルタによりノードの除外や、展開するフォルダ内に表示する他のノードの追加を行えるようになります。
多様な機能を提供し、依存ツリーの階層が深い拡張機能は、大規模拡張機能とみなされます。通常、大規模拡張機能は依存ツリーの階層が深いため、他の多くの拡張機能の事前初期化を引き起こします。多くのケースで、拡張機能ユーザーは大規模拡張機能で提供される多様な機能の一部しか利用しませんが、このタイプの拡張機能の一体化された構造のために、意図せずに必要以上の機能を得ることがあります。
大規模拡張機能のパフォーマンスを改善するためには、次のいずれかのモデルに従い大規模拡張機能をリファクタすることをお薦めします。
拡張機能の主要な機能分野を識別して、特徴的な分野を個別の拡張機能としてリファクタします。
概念的な機能分野を、依存ツリーの階層が浅い1つの拡張機能に含めるようにし、機能実装の詳細部分を別の拡張機能に移します。
1つ目のモデルに適しているのは、機能分野の間に単純な依存関係がある場合です。たとえば、2つの機能分野XとYを含む拡張機能E1について考えます。単純な依存関係とは、拡張機能E1を拡張機能E2とE3にリファクタしても、E2とE3の間に双方向依存関係が生じないことを意味します。依存関係が発生する場合は、サポート・モジュール(たとえばモジュールM1)を導入して解決できます。このモジュールでは、E2とE3の両方が必要な機能が提供されます。M1の依存ツリーはE1と同じでないことが重要です。同じであれば、E1の機能を実行するために事前初期化する必要がある拡張機能の数を減らすというリファクタの目的に合いません。E2とE3が互いに依存せず、拡張機能E1の元の依存ツリーが拡張機能E2とE3で均等に分割されるのが、理想的な状態です。
2つ目のモデルでは、拡張機能E1のバージョンが維持されます。これには階層が非常に浅い依存ツリーが含まれます。依存ツリーを縮小するために、リファクタ処理によって、機能分野E2とE3の実装を拡張機能E2implとE3implに移す必要があります。このパターンが機能するためには、E1が拡張機能E2implまたはE3impl (あるいは両方)に依存しないことが非常に重要です。このパターンをサポートするには、正しい実装が保証するsingleton-service-hook
を使用します。つまり、拡張機能E1で機能E2がアクセスされるとE2impl拡張機能が初期化されます。singleton-service-hook
を使用することにより、E1が拡張機能E2implに依存していなくてもE2implが初期化されます。詳細は、「トリガー・フックの定義および使用」のシングルトン登録の項を参照してください。
ユーザーがテクノロジ・スコープを選択すると、そのテクノロジ・スコープを導入した拡張機能が、依存している他のすべての拡張機能と一緒に初期化されます。デプロイメント依存は、プロジェクトのデプロイメント・プロファイルに記述されます。詳細は、Oracle Fusion Middleware Oracle JDeveloperによるアプリケーションの開発のデプロイメント・プロファイルを参照してください。
ユーザーの選択により、そのテクノロジ・スコープを導入している拡張機能の依存ツリーの外部で拡張機能を初期化する必要が生じた場合、お薦めする対処方法としては、拡張機能の初期化をトリガーする拡張機能内の機能をユーザーが使用するのを待機します。機能セットという概念を回避できます。機能セットのすべてのメンバーの初期化が必要になると、遅延初期化の目的に反します。
この項のガイドラインに従うと、JDeveloperにシームレスに溶け込む拡張機能を開発できます。たとえば、oracle.javatools.ui.LayoutConstants
で公開されているUI定数を使用すると、共通のコンポーネントに関して標準の間隔や位置合せを使用でき、推奨の間隔を実現できます。間隔は、コンポーネントがダイアログ、ウィザードまたはモードレス概要エディタのどれに含まれるかにかかわらず、すべてのコンポーネントで使用できます。
図2-2に、JDeveloperダイアログの要素で使用される標準の間隔を示します。
図2-2 JDeveloperダイアログでの間隔表示
図2-3は、JDeveloperの概要エディタで使用される間隔を示します。
図2-3 概要エディタでの間隔表示
この項では、様々なJDeveloper要素の使用方法と開発方法について説明します。
メニュー
ウィンドウおよびビュー
「新規ギャラリ」または「ツール」メニューから呼び出すことができるウィザード
JDeveloperコマンド
ソース・エディタ
エクスプローラ
ファイル・タイプ
「コンポーネント」ウィンドウ
JDeveloperプリファレンス
変更のUNDO可能化
Extension SDKには、これらの要素だけでなくその他の要素の例も用意されています。 詳細は、「Extension SDKを使用した開発」を参照してください。
次のJDeveloper要素は「新規ギャラリ」ですぐに作成できます。
アクション。拡張機能ユーザーがIDEで呼び出すことができる処理です。アクションの詳細は、「アクションの定義方法」を参照してください。
アドイン。JDeveloperの起動中に拡張機能の初期化と登録をプログラミングによって実行できます。アドインの詳細は、「Addinインタフェースの実装方法」を参照してください。
データ・モデル。サブクラスHashStructureAdapter
が、プリファレンスまたはプロジェクト・プロパティの永続データ・モデルを格納します。データ・モデルの詳細は、「データ・モデルの実装方法」を参照してください。
ウィザードは「新規ギャラリ」または「ツール」メニューから呼び出すことができます。ウィザードの詳細は、「ウィザードの開発方法」を参照してください。
「プリファレンス」ダイアログの新しいパネル。「プリファレンス」ダイアログの使用方法の詳細は、「プリファレンスについて」を参照してください。
「プロジェクト・プロパティ」ダイアログの新しいパネル。プロジェクト・プロパティの詳細は、「プロジェクト・プロパティについて」を参照してください。
拡張機能フック定義ファイル・テンプレートで使用できるFreemarkerファイル・テンプレート。
「新規ギャラリ」ですぐにJDeveloper要素を作成するには、次の手順を実行します。
JDeveloperに対するユーザーの操作の多くはメニューを介して行われるため、JDeveloperでは既存のメニューを変更して新しいメニューを作成できます。JDeveloperのメニュー・バーのアイテムに選択したアイテムを追加するだけでなく、コンテキスト・メニューを追加して、拡張機能が提供する機能に対するユーザーの操作を細かく制御することもできます。
メニューが対話するコマンド拡張機能は、Addin
インタフェースに依存します。詳細は、「コマンドの開発方法」を参照してください。
メニューは、拡張機能をJDeveloperに統合する重要な手段です。バージョニング・システムの選択や内部コード・スニペット・データベースへのアクセスなど、主要な機能をJDeveloperのメニュー・システムに追加して、メニューまたはツールバーで選択することで、拡張機能を利用または制御できるようにします。一方、拡張機能の一部の機能(社内のバージョニング・ソフトウェアでのファイルのチェックアウトや、社内でよく使用されるツールでのコードの確認)は、コンテキスト・メニューに含めることをお薦めします。コンテキスト・メニューは、該当する場所でユーザーがマウスの右ボタンをクリックすると表示されます。JDeveloperの拡張機能システムではどちらの方法も可能です。詳細は、「ポップアップ・メニューの作成方法」を参照してください。
JDeveloperには、コンテキスト・メニューの宣言的作成をサポートするクラスが含まれています。作成されたコンテキスト・メニューは、一連のリスナーやコントローラによってJDeveloperのメイン機能にフックできます。この方法で、JDeveloperの構造とユーザー・インタフェースに適合するメニューベースの拡張機能を作成すると同時に、基本的なIDEを超えた機能を追加できます。詳細は、「コンテキスト・メニューからアドインを呼び出す方法」を参照してください。
あるいは、拡張機能の機能はすでにJDeveloperの既存のメニュー構造に組み込まれていて、その現在の各メニューに対して、拡張機能によって特有の機能を付け加える場合もあります。この場合は、拡張機能によって、既存のメニューに固有の新オプションを追加する必要があります。詳細は、「既存のメニューにメニュー・アイテムを追加する方法」を参照してください。
これに似た方法を使用して、ツールバーに新しい選択肢を追加することもできます。詳細は、「ツールバーにドロップダウン・ボタンを追加する方法」を参照してください。
コンテキスト・メニュー・リスナー・クラスを使用したメニューの宣言的な作成では、標準クラスを使用できます。これにより、拡張機能の更新が容易になり、すべてのメニューに一貫性が加わり、拡張機能を迅速にロードできるようになります。また、カスタム・コードを開発する必要はありません。既存のコンテキスト・メニューのリスナー・クラスを使用できます。リスナー・クラスを登録し、拡張機能のメニューを追加できるコールバック・インタフェースを使用し、メニューが作成される特定のビューに関連付けられているコントローラを最後に使用します。詳細は、「コンテキスト・メニューからアドインを呼び出す方法」を参照してください。
複数の選択肢を含むメニューを作成するには、次の手順を実行します。
次のサンプル・コードを使用して、コンテキスト・メニューのリスナー・クラスを拡張機能マニフェストに登録します。
<extension xmlns="http://jcp.org/jsr/198/extension-manifest" ... <!-- Define an action that will be used in various menus and toolbars. You can set any Swing action property on the action. The controller class implements oracle.ide.controller.Controller and determines when the action is enabled and what it does. You can use an ampersand (escaped as &) in the Name property to specify the mnemonic for any menu items containing the action. --> <actions xmlns="http://xmlns.oracle.com/jdeveloper/1013/extension"> <action id="oracle.ide.extsamples.first.invokeAction"> <properties> <property name="Name">&Extension SDK First Sample</property> <!-- use an icon, stealing this one from predefined icons make sure you have oracle.icon as a required bundle to pick up this icon at run time from the icons module --> <property name="SmallIcon">${OracleIcons.LABEL}</property> </properties> </action> </actions> <controllers xmlns="http://xmlns.oracle.com/ide/extension"> <controller class="oracle.ide.extsamples.firstsample.SimpleController"> <update-rules> <update-rule rule="always-enabled"> <action id="oracle.ide.extsamples.first.invokeAction"> <label>ESDK Sample Action</label> </action> </update-rule> </update-rules> </controller> </controllers> <!-- Install context menus in the navigator, editor, and structure pane (explorer) which use the same action defined above. --> <context-menu-hook rule="always-enabled"> <site idref="navigator, editor, explorer"/> <menu> <!-- 'weight' is used to control where the section appears in the menu. Weights are sorted in ascending order, each unique value is its own section. --> <!-- section element must be in namespace http://jcp.org/jsr/198/extension-manifest. --> <section xmlns="http://jcp.org/jsr/198/extension-manifest" id="MY_CUSTOM_MENU_SECTION_ONE" weight="1.0"> <!-- For menu items and submenus, weight determines the order within a menu section. Items are sorted in ascending order or in the order they are added if the weight is not unique. --> <item action-ref="oracle.ide.extsamples.first.invokeAction"></item> </section> </menu> </context-menu-hook> <menu-hook xmlns="http://jcp.org/jsr/198/extension-manifest"> <!-- Add the action in its own separator group at the top of the File menu. --> <menus> <menubar id="javax.ide.view.MAIN_WINDOW_MENUBAR_ID"> <menu id="javax.ide.FILE_MENU_ID"> <section id="esdksample.customsection" before="javax.ide.NEW_SECTION_ID"> <item action-ref="oracle.ide.extsamples.first.invokeAction"></item> </section> </menu> </menubar> </menus> <!-- Add the action as toolbar button in its own separator group immediately after the existing "save" toolbar buttons. --> <toolbars> <toolbar id="javax.ide.view.MAIN_WINDOW_TOOLBAR_ID"> <!-- Add a new section after the first section in the toolbar. --> <section id="javax.ide.tck.toolbar.testsection" after="javax.ide.NEW_SECTION_ID"> <item action-ref="oracle.ide.extsamples.first.invokeAction"></item> </section> </toolbar> </toolbars> </menu-hook> </triggers> </trigger-hooks> <hooks> <!-- The feature hook controls the display of the extension on the Extensions page of preferences. --> <feature-hook> <description>Demonstrates installing menu, toolbar and gallery items.</description> <optional>true</optional> <part-of>oracle.ide.extsamples.allsamples</part-of> </feature-hook> </hooks> </extension>
コンテキスト・メニュー・リスナーを登録すると、コンテキスト・メニューが迅速にポップアップ表示されるようになります。
コンテキスト・メニュー・リスナーは、コンテキスト・メニューのポップアップを遅延させないように最小限の処理を実行する必要があります。現在、「アプリケーション」ウィンドウのコンテキスト・メニューには250近いメニュー・リスナーがあります。したがって、コンテキスト・メニューのポップアップに1秒かからないようにするには、リスナーが平均してかけられる時間は4ミリ秒未満です。
パフォーマンスの向上に関するヒントを次に示します。
拡張機能が特定のノードだけに関係する場合は、その特定のノード・タイプに対してコンテキスト・メニュー・リスナーを登録する必要があります。拡張機能のユーザーがそのタイプのノードをクリックしたときだけ、リスナーが呼び出されるようになります。
リスナーのmenuWillShow
メソッドが呼び出されるとき、アクションはメニュー・アイテムの追加のみにする必要があります。メニュー・アイテムのアクションが実行されるときに、該当しないコンテキストから保護します。
リスナーのmenuWillHide
メソッドが処理を行わないようにする必要があります。
コンテキスト・メニューのパフォーマンスが悪影響を受けるものは次のとおりです。
ファイルI/O処理。
ファイルの内容の解析。
検索のためのリストの繰返し処理。
ファイル・システムでの検索。
コンテキスト・メニューに追加済のメニューの繰返し処理およびメニュー名変更やメニュー削除の試行。
拡張機能について、1つのアイテムまたはアイテムのグループを既存のJDeveloperメニューまたはツールバーに追加するのみでよい場合もあります。
メニューを追加するには:
場合によっては、拡張機能がウィンドウで作動し、拡張機能に固有のオプションまたは拡張機能のウィンドウに表示される特定のデータ・オブジェクトに固有のオプションで構成されるツールバーが、そのウィンドウ自体に含まれることがあります。詳細は、「メイン・ウィンドウ・メニューからアドインを呼び出す方法」を参照してください。
ツールバーにドロップダウン・ボタンを追加するには、次の手順を実行します。
拡張機能に固有のウィンドウに、この次の例のコードをメソッドとして組み込むと、3つのアクションを含むドロップダウン・ボタンがツールバーに追加されます。ユーザーがこのボタンをクリックすると、表示されるメニューには3つのアクションが含まれます。
void doit(Toolbar toolbar, IdeAction dropDownIdeAction, IdeAction ideAction1, IdeAction ideAction2, IdeAction ideAction3) { ActionMenuToolButton actionMenuToolButton = toolbar.addActionMenuButton(dropDownIdeAction); Action[] actions = new Action[] { ideAction1, ideAction2, ideAction3, }; actionMenuToolButton.setMenuActions(actions); }
JDeveloperデータ・モデルでは、扱っている情報の内容を表示および監視するために2つの重要な概念、ウィンドウとビューを使用します。ウィンドウ(多くの場合、IDEフレームワークの特定の場所に表示されるドッキング可能ウィンドウ)は、情報を表示し、コマンド入力を受け取ります。ビューでは、拡張機能によって生成、処理または表示される情報オブジェクト(ファイルまたはデータベース・レコードなど)にJDeveloperがアクセスする方法が定義されます。
ドッキング可能ウィンドウを使用すると、JDeveloperの指定の場所に拡張機能専用の領域を作成できます。ドッキング可能ウィンドウを使用するときは主に次の2つの手順を実行します。
ドッキング可能ウィンドウを作成します。
ドッキング可能ウィンドウを配置します。
拡張機能で使用するウィンドウを作成して配置したら、拡張機能がそのウィンドウを認識するようにします。特に、ユーザーが入力のためにウィンドウを選択したときに認識されるようにする必要があります。JDeveloperが使用するメカニズムはIDEリスナーです。ウィンドウにIDEリスナーを追加すると、拡張機能と作成したウィンドウが結び付けられます。詳細は、「IDEリスナーをビューに追加する方法」を参照してください。
ドッキング可能ウィンドウを作成して配置し、IDEリスナーの割当てを行ったところで、ユーザーによるウィンドウの選択を拡張機能が認識するように設定できます。ウィンドウは、選択されるとアクティブ・ビューを保持します。アクティブ・ビューをリスニングするように追加したIDEリスナーに指示できます。詳細は、「アクティブ・ビューのリスニング方法」を参照してください。
ドッキング可能ウィンドウの作成は3つの手順で行います。DockableFactory
を作成し、クラスMyDockableWindow
を使用してドッキング可能ウィンドウを作成し、アドインの初期化時にDockableFactory
をインストールします。
ドッキング可能ウィンドウを作成するには、次の手順を実行します。
次の例は、ドッキング可能ウィンドウを「アプリケーション」ウィンドウの中央に配置する方法を示します。「アプリケーション」ウィンドウ拡張機能がロードされない場合、ウィンドウは左側(WEST)にドッキングされます。
dockingParam = new DockingParam(); final NavigatorManager applicationNavigatorManager = NavigatorManager.getApplicationNavigatorManager(); final NavigatorWindow navigatorWindow = applicationNavigatorManager.getNavigatorWindow(); dockingParam.setPosition( navigatorWindow, IdeConstants.CENTER, IdeConstants.WEST );
選択リスナーをアクティブ・ビューに追加するには、アクティブ・ビューの変更をリスニングする必要があります。リスナーを追加したビューがアクティブでなくなると、リスナーをそのビューから削除する必要があります。
アクティブ・リスナーを追加するには、次の手順を実行します。
次の例に基づいてコードを作成します。
import oracle.ide.view.ActiveViewListener; import oracle.ide.view.ActiveViewEvent; import oracle.ide.view.ViewSelectionListener; class MyActiveViewListener implements ActiveViewListener { private ViewSelectionListener _selectionListener = new ViewSelectionListener() { public void viewSelectionChanged(ViewSelectionEvent e) { //Your code responding to view selection changes goes here. { };
アクティブ・リスナーを変更するには、次の手順を実行します。
次の例に基づいてコードを作成します。
public void activeViewChanged(ActiveViewEvent e) { View view = e.getOldView(); if (view != null) view.removeViewListener(_selectionListener); view = e.getNewView(); //While this example adds a ViewSelectionListener to any active view, //it is strongly recommended that you add your view selection listener //to views your extension is interested in only. view.addViewListener(_selectionListener); } }
JDeveloper IDEアーキテクチャのモデル/ビュー/コントローラ・モデルでは、どのビューがアクティブか(つまり、所定のウィンドウにどのデータ表現が表示されているか)が拡張機能によって把握されていることが必要です。(ウィンドウ・システムでは入力フォーカスがあるアクティブ・ビューが参照されます。)JDeveloper IDEアーキテクチャでは、拡張機能がアクティブ・ビューをリスニングする必要があります。これは、ビューによって実行されるコマンドが適切なデータに確実に適用されるようにする仕組みです。
アクティブ・ビューをリスニングするには、次の手順を実行します。
次の例に基づいてコードを作成します。
Ide.getMainWindow().addActiveViewListener(new ActiveViewListener() { public void activeViewChanged(ActiveViewEvent e) { final View view = e.getNewView(); System.out.println(view.getId() + " has been activated"); } });
ウィザードは、タスクを実行するために呼び出される拡張機能です。典型的なウィザードはUIから呼び出され、1つまたは一連のダイアログ・ボックスで構成されるユーザー・インタフェースを開きます。ユーザーがこのインタフェースでタスクのパラメータを指定します。一般的なタスクは、ドキュメントまたは他のデータ・オブジェクトの作成です。「新規ギャラリ」またはツール・メニューにインストールされるウィザードのために、特別な起動メカニズムが提供されています。このようなケースでは、ウィザード・マネージャが起動の詳細を管理します。
ウィザード・プロジェクトのプロパティによって、ウィザード・プロジェクトのパス、ライブラリおよび他の設定が指定されます。プロジェクトをすでに設定している場合は、ソース・ファイルを追加してから、ウィザードをデバッグおよびデプロイできます。
ウィザード・プロジェクトには通常3つの主要コンポーネントがあります。
ウィザード・クラス。このクラスは、ユーザー・インタフェースでのウィザードの外観および起動方法を処理します。このクラスはWizard
インタフェースを実装する必要があります。
モーダル・ダイアログ。このダイアログはユーザーと対話して、ウィザードの機能に必要なデータを収集します。
データ・オブジェクト。ウィザードは、データ・オブジェクトを作成または変更するために、ダイアログによって収集されたデータを適用します。
Extension SDKに含まれるサンプル・プロジェクトであるHelloX
は、直接ウィザードを実装し、そのユーザー・インタフェースとしてJDialogを使用します。JDeveloperのルック・アンド・フィールに準拠するウィザードは、JEWTウィザード・フレームワークを使用します。
Extension SDKの詳細は、「Extension SDKを使用した開発」を参照してください。
モーダル・タスクを実行するためにユーザー・インタフェースから呼び出される拡張機能は、oracle.ide.wizard.Wizard
インタフェースを実装する必要があります。このインタフェースは拡張機能のインストールに対応し、JDeveloperのユーザー・インタフェースにインストールを統合します。
ウィザード・インタフェースを実装するには、次の手順を実行します。
invoke
メソッドの定義
getIcon
メソッドの定義
拡張機能マニフェストでのウィザードの定義
このメソッドによってウィザードの機能が具体化されます。通常、ウィザードはダイアログを開いてユーザーからパラメータを取得します。その後、それらのパラメータを使用してドキュメントや他のデータ・オブジェクトを作成または変更します。
このメソッドが呼び出されるのは、「新規ギャラリ」または「ツール」メニューでウィザードのUI要素がユーザーによって選択されたときです。ウィザードが影響を与える可能性がある、現在選択されているオブジェクトが、context
パラメータによって識別されます。
invokeメソッドを定義するには、次の手順を実行します。
次の例に基づいてコードを作成します。
public boolean invoke(Context ctx) { if (!isAvailable(ctx)) return false; String greetee = null; greetee = JOptionPane.showInputDialog(Ide.getMainWindow(), "Enter your name:", WIZARD_NAME, JOptionPane.OK_CANCEL_OPTION);] if (greetee == null) // User canceled return false; JOptionPane.showMessageDialog(Ide.getMainWindow(), "Hello " + greetee + "!", WIZARD_NAME, JOptionPane.INFORMATION_MESSAGE); return true; }
このメソッドが呼び出されるのは、ウィザードの「新規ギャラリ」または「ツール」メニュー・アイコンを取得するためです。ウィザードでアイコンが必要ない場合、このメソッドはnull
を返します。
getIconメソッドを定義するには、次の手順を実行します。
次の例に基づいてコードを作成します。
public Icon getIcon() { if(image == null) { image = new ImageIcon(HelloX.class.getResource(ICON_NAME)); } return image; }
ウィザードは、拡張機能マニフェスト・ファイルにギャラリ・ウィザードの説明を指定すると、「新規ギャラリ」にインストールできます。ウィザードの登録やイベント処理の詳細すべては、ウィザード・マネージャによって処理されます。
ウィザードが呼び出されるのが「新規ギャラリ」だけの場合、ウィザード・クラスのコンストラクタは、拡張機能ユーザーがそのカテゴリを最初に開くまで呼び出されません。ギャラリ・マネージャは、カテゴリが最初に開かれるときに説明ファイルを読み取ります。次に、ウィザードをインスタンス化し、インスタンスから導出したアイコンとラベルを使用してアイテムを構成します。
拡張機能マニフェストでは、定義することが多数あります。次の例を参照してください。
<trigger-hooks xmlns="http://xmlns.oracle.com/ide/extension"> <triggers> <gallery xmlns="http://xmlns.oracle.com/jdeveloper/1013/extension"> <folders> <name label="ESDK-Gallery Example">ESDK-Gallery Example</name> <category>General</category> </folders> <item rule="always-enabled"> <!-- name is the fully-qualified name of an oracle.ide.wizard.Invokable --> <name>oracle.ide.extsamples.hellox.HelloX</name> <!-- id is optional, and if specified will be stored in the Context so it can be retrieved when the wizard is invoked. --> <id>oracle.ide.extsamples.hellox</id> <!-- description is the short label of the gallery item --> <description>Say Hello Wizard</description> <!-- help is the long label for the gallery item --> <help>Prompts the user to enter his name, and repeats it. Part of the Extension SDK, this is a trivial example.</help> <icon>/oracle/ide/extsamples/hellox/HelloX.gif</icon> <category>General</category> <folder>ESDK-Gallery Example</folder> </item> </gallery> </triggers> </trigger-hooks>
<gallery>
には、「新規ギャラリ」のウィザードに関する情報が含まれています。
<name>
は、ウィザードの解読可能な名前を提供します。
<category>
は、ウィザードの「新規ギャラリ」カテゴリを指定します。カテゴリ内のエントリは、アルファベット順になっています。
<folder>
は、カテゴリ内のフォルダを指定します。
rule
は、ウィザードが使用可能な時期を指定します。
ウィザード・クラスは、<id>
で識別されます。
<description>
は、「新規ギャラリ」のウィザードの短い説明です。
<help>
は、アイテムを選択した場合、または「新規ギャラリ」の「すべての説明を表示」を選択した場合に表示されるエントリの長い説明です。
<icon>
は、「新規ギャラリ」内のアイコンを指定します。
拡張機能アプリケーションextensionsdk
を実行することで、前の例のコードが、「新規ギャラリ」に表示される内容にどのように影響を与えるかを確認できます。
図2-4 「新規ギャラリ」のHelloXウィザード
メニュー・アイテムまたはツールバー・アイコンとしてユーザー・インタフェース要素を追加する拡張機能や、新たな目的のために既存の要素をカスタマイズする拡張機能は、機能をコマンド拡張機能にカプセル化する必要があります。
ほとんどの拡張機能はAddin
インタフェースを実装する必要があります。このインタフェースは、JDeveloperの起動時に拡張機能のインストールに対応します。
Addin
インタフェースを実装するためには、最初にコンストラクタを定義します。コンストラクタはできるだけ何もしないようにしてください。初期化タスクはinitializeメソッドで実行します。
次に、initialize
メソッドを定義します。このメソッドは、インスタンスが作成された後でアドイン・マネージャによって呼び出されます。初期化時に実行する必要があるタスクは次のとおりです。
UI要素とコントローラを作成します。
マネージャに登録します。
アドインが呼び出されるまで必要のない他のタスク(データ構造の作成など)は延期して、JDeveloperの起動が不必要に遅くならないようにします。
拡張機能がメニュー・アイテムまたはツールバー・アイコンを追加する場合は、その機能をコマンドとして実装する必要があります。
既存のコントロールに特別な動作を定義する拡張機能は、カスタム・アクションを定義したり、カスタム・コマンド・クラスを実装したりするのではなく、そのコントロールにすでに用意されているアクションとコマンド・クラスを使用する必要があります。Ide
クラスに定義されているフィールドは、IDEの標準コマンドのクラス名とIDを提供します。
拡張機能のコマンドには、次のタスクが必要です。
イベントの処理
undoメソッドの定義
その他のメソッドの定義
この項のコード例は、Extension SDKに含まれるFirstSample
サンプル・プロジェクトのものです。詳細は、「Extension SDKを使用した開発」を参照してください。
次の例のコードは、コマンドを呼び出したときにトリガーされるイベントの処理方法を示します。
/** * ContextMenuListeners add items to context menus. */ public final class SimpleContextMenuListener implements ContextMenuListener { public void menuWillShow(ContextMenu contextMenu) { // First, retrieve our action using the ID we specified in the // extension manifest. IdeAction action = IdeAction.find(SimpleController.SAMPLE_CMD_ID); // Then add it to the context menu. contextMenu.add(contextMenu.createMenuItem(action)); } public boolean handleDefaultAction(Context context) { // You can implement this method if you want to handle the default // action (usually double click) for some context. return false; } }
コードのブロックが長くなる場合は、doIt
メソッドを使用できます。
このメソッドを定義する必要があるのは、コンストラクタによってコントローラがNORMAL
タイプと指定される場合のみです。undo
メソッドには通常次の2つのタスクが含まれます。
doit
メソッドの処理結果を元に戻します。getData
メソッドから取得した値でチェックポイントの状態に復元するか、doit
メソッドの処理を逆に実行します。
変更が行われたことをオブザーバに通知します。
コマンドが正常に終了するとOK
を返します。それ以外の場合は、CANCEL
または0以外の値を返します。デフォルト実装はCANCEL
を返し、悪影響はありません。
次のメソッドのデフォルト実装はオーバーライドできます。
getId
は、コンストラクタに渡されるコマンドIDを返します。
getType
は、コンストラクタに渡されるコマンド・タイプ定数を返します。または、この引数が指定されない場合はNO_CHANGE
を返します。
getName
は、コンストラクタに渡される名前文字列を返します。または、この引数が指定されない場合は空の文字列を返します。
getAffectedNodes
はデフォルトではnull
を返します。
setContext
とgetContext
は、保護されたContext
変数の書込みと読取りをそれぞれ行います。デフォルト値はnull
です。
setData
とgetData
は、プライベートObject
変数の書込みと読取りをそれぞれ行います。デフォルト値はnull
です。
新しいコマンド・クラスを実装する拡張機能は、それらを含むアクションを定義する必要があります。アクションは、メニュー・アイテム(または他のユーザー・インタフェース・コントロール)と、そのメニュー・アイテムが選択されたときに実行されるコマンドのリンクになります。アクションはIdeAction
のインスタンスです。
既存のUI要素に特別な動作を定義する拡張機能は、カスタム・アクションを定義するのではなく、その要素にすでに用意されているアクションを使用する必要があります。Ide
クラスに定義されているフィールドは、標準コマンドのクラス名とIDを提供します。たとえば、保存処理を提供するすべてのエディタは、事前定義済のIde.SAVE_CMD
値およびIde.CUT_SAVE_ID
値と、それらに関連付けられたアクションを使用する必要があります。
通常、アクションは、アクションに関連するメニュー・アイテムまたはツールバー・アイコンをインストールするAddinクラスのフィールドとして定義されます。拡張機能の初期化においてアクションを作成して構成します。
この項のコード例は、Extension SDKに含まれるFirstSample
サンプル・プロジェクトのものです。詳細は、「Extension SDKを使用した開発」を参照してください。
アクションはコマンドID別にキャッシュされます。必要なコマンドのアクションがすでに存在する場合、通常は、新しいアクションを作成するかわりに既存のアクションを使用する必要があります。
アクションを作成するためにIdeAction
コンストラクタを使用しないでください。かわりに、次の静的メソッドを使用して、キャッシュされたアクションを取り出すか、新しいアクションを作成します。
find
メソッドは、該当するアクションがキャッシュ済の場合、指定されたコマンドIDを含むアクションを返します。
様々なget
メソッドは、該当するアクションがキャッシュ済の場合、指定されたコマンドIDと一致するアクションを返します。ただし、そのアクションのプロパティは、指定されたパラメータと一致する場合としない場合があります。コマンドIDに対応するアクションが見つからない場合は、指定されたパラメータに基づいて新しいアクションが作成され、キャッシュ、そして返されます。
create
メソッドは、新しいアクションを作成し、それをキャッシュせずに返します。createで取得されるアクションは、後でロードされる拡張機能では使用できません。
アクションには、外観を決定するものなど様々なプロパティが含まれることがあります。これらには、putValue
メソッドやgetValue
メソッドで文字列キーを使用してアクセスします。一部のプロパティは、アクションが静的メソッドcreateまたはgetによって作成されるときに設定されます。IDEによって認識されるキーはToggleActionスーパークラスに定義されます。詳細は、Oracle Fusion Middleware Oracle Extension SDK Java APIリファレンスのToggleAction
に関する項を参照してください。
ビューに依存しないアクション(openなど)は、アクションを更新してイベントを処理するためにコントローラを指定する必要があります。ビューのコンテキストで呼び出されるアクションには、アクション・コントローラは必要ありません。
コマンドの動作を拡張すると、そのコマンドを使用するすべてのIDE機能で、カスタム操作を実行できます。これには、コマンドのアクションのコントローラを置き換えるか、アクションにまだコントローラがない場合にはコントローラを設定します。ただし、デフォルトの動作を損ねないように注意する必要があります。
既存のコントローラを置き換えるには、次の手順を実行します。
古いクラスを拡張して、新しいコントローラ・クラスを実装します。
新しいコントローラが拡張するコマンドを処理する際に、custom
処理を実行し、そのコマンドに対して古いコントローラのhandleEvent
メソッドを呼び出します。こうすることで、元の動作が保持されます。
コントローラのないアクションにコントローラを追加するには、次の手順を実行します。
新しいコントローラ・クラスを実装します。
新しいコントローラが拡張するコマンドを処理する際に、custom
処理を実行し、そのコマンドに対してスーパーバイザのhandleEvent
メソッドを呼び出します。こうすることで、元の動作が保持されます。
getController
メソッドとaddController
メソッドを使用してアクションのコントローラにアクセスします。
メイン・ウィンドウ・メニューからアドインを呼び出せるようにするには、アドインのメニュー・アイテムをメイン・ウィンドウ・メニューのいずれかに追加します。アイテムはどのメニューにも追加できますが、拡張機能を「ツール」メニューから呼び出す場合は、アドインとしてインストールするかわりに(または、アドインとしてのインストールに加えて)ウィザードとしてインストールする必要があります。「ツール」メニューでのメニュー・アイテムの追加と処理は、ウィザード・マネージャによって行われます。
IDEメニューは、Menubar
のシングルトン・インスタンスによって表示されます。これはgetMenubar
メソッドを使用してアクセスできます。
拡張機能は、IDEメニューにメニュー、サブメニューおよびメニュー・アイテムを追加できます。呼び出される拡張機能(ウィザードなど)は、インストール時に独自のアイテムをメニューに追加します。または、拡張機能が標準メニュー・アイテムの独自の動作を定義できます。たとえば、「編集」メニューのアイテムの処理内容は使用されるエディタによって異なります。
「アプリケーション」ウィンドウやソース・エディタなどの一部のビューには、ユーザーがウィンドウを右クリックするとポップアップ表示されるコンテキスト・メニューがあります。拡張機能はコンテキスト・メニューにアイテムを追加できます。
ユーザーが右クリックすると、コンテキスト・メニューが再構成されます。選択されたコンテキスト・メニュー・リスナー(右クリックの対象に関連付けられているリスナー)がポーリングされ、コンテキスト・メニューにアイテムまたはサブメニューを付加する機会が与えられます。たとえば、ドキュメントを表すノードが右クリックされると、そのドキュメント・タイプのビューアとして登録されているエディタやデザイナのメニュー・アイテムをコンテキスト・メニューに追加できます。
次の例は、「アプリケーション」ウィンドウなどのウィンドウ内にコンテキスト・メニューをインストールする方法を示しています。このコードは、Oracle IDE Extension SDKの一部としてインストールされる拡張機能サンプル内のClassBrowserプロジェクトのものです。
<!-- Install context menus in the navigator, editor which use the same action defined above. --> <context-menu-hook rule="always-enabled"> <site idref="navigator,editor"/> <menu> <!-- 'weight' is used to control where the section appears in the menu. Weights are sorted in ascending order, each unique value is its own section. --> <!-- section element must be in namespace http://jcp.org/jsr/198/extension-manifest. --> <section xmlns="http://jcp.org/jsr/198/extension-manifest" id="MY_CUSTOM_MENU_SECTION_ONE" weight="1.0"> <!-- For menu items and submenus, weight determines the order within a menu section. Items are sorted in ascending order or in the order they are added if the weight is not unique. --> <item action-ref="esdksample.showClassBrowser"></item> </section> </menu> </context-menu-hook>
エディタは、ユーザーが変更できるようにオブジェクトを表示するビューです。通常、エディタにはテキストが表示されます。デザイナはテキスト以外のエディタです。エディタは、ドキュメントのノードのコンテキスト・メニューまたは「表示」メニューを介して開かれます。ドキュメントで使用できるエディタは、そのドキュメントのタイプについてIDEのエディタ・マネージャに登録されたエディタです。エディタは、通常は構造エクスプローラと組み合せて使用されますが、これは必須ではありません。
Extension SDK内のCustomEditor
プロジェクトは、oracle.ide.editor.Editor
の拡張およびjava.beans.PropertyChangeListener
の実装を行う、カスタムのXMLQueryEditor
を実装することでこれを実行する方法を示します。詳細は、「Extension SDKを使用した開発」を参照してください。
非同期エディタは、UIスレッド(Swingのイベント・ディスパッチ・スレッド)の外部のワーカー・スレッドにコンテンツをロードするため、ユーザーが操作する際の応答性が向上します。非同期エディタのコンテンツをロードするとき、エディタ・フレームワークでは次の処理が行われます。
「エディタのロード中」というメッセージとアニメーションを含むパネルを表示します。両方とも構成できます。
「コンポーネント」ウィンドウがUIをロードおよびブロックをしないようにします。
エディタのロードが開始するのはContext
が設定されたときです。このアクションにより、エディタのUIがUIスレッドで必要とするモデルのロードがトリガーされます。このために、非同期エディタはワーカー・スレッドを作成してロードを実行します。モデルのロードが行われている間に、IDEはエディタのGUIコンポーネントを確認します。エディタの実際のUIがまだロードされていない場合、メッセージ(たとえば、「エディタのロード中」)を含むパネルが表示され、「コンポーネント」ウィンドウはロードされません。エディタの実際のUIが作成されると、非同期エディタが自動的に入れ替わります。
エディタ・フレームワークにより、エディタの実装方法の柔軟性が高くなります。詳細は、Oracle Fusion Middleware Oracle Extension SDK Java APIリファレンスのAsynchronousEditor
に関する項を参照してください。
最初の手順としては、たとえばユーザーが「アプリケーション」ウィンドウでノードをダブルクリックすると、EditorManager
がエディタを作成して開きます。
EditorState
が新しい非同期エディタ(oracle.ide.editor.AsynchronousEditor
のサブクラス)を作成します。
非同期エディタは作成されるとプロパティを設定します。そのプロパティによって、エディタが非同期であり、実際のエディタはまだロードされていないことを、IDEの他のビューが認識します。このプロパティに関心を持つビューの例としては、「コンポーネント」ウィンドウがあります。「コンポーネント」ウィンドウは、エディタが完全にロードされた場合にのみそのコンテンツをロードします。
EditorState
によって、新しい非同期エディタ内のコンテキストが設定されます。
非同期エディタは、コンテンツがまだロードされていないことが適切なフラグによって示されるのを待機し、その後で非同期エディタ・コンテンツ・モデルをロードします。これは非同期に実行されます(UIイベント・スレッド外)。
EditorManager
は、エディタの優先レイアウトを設定します。
EditorState
がエディタを開きます。これによって、getGUI
の呼出しが行われます。
これを図2-5に示します。
図2-5 エディタのオープン
エディタがいったん開くと、エディタのメソッドgetGUI
が呼び出されます。このとき、非同期エディタで「エディタのロード中」というメッセージが表示され、図2-6に示すように、コンテンツ・モデルを非同期にロードするタスクがUIイベント・スレッド外でスケジュールされます。
図2-6 エディタのGUIの取得
この時点でコンテンツ・モデルは非同期にロードされており、次の処理が行われます。
AsynchronousEditor
は、メソッドopenImpl
、showImpl
およびactivateImpl
を呼び出して、エディタのGUIのロード、表示およびアクティブ化します。
AsynchronousEditor
は待機中ページを実際のエディタGUIと切り替えます。
AsynchronousEditor
は、完全にロードされたことを「コンポーネント」ウィンドウなどのリスナーに通知します。リスナーはそれぞれのコンテンツをロードできるようになります。
通常のエディタを非同期エディタにするには、次の手順を実行します。
oracle.ide.editor.Editor
ではなくoracle.ide.editor.AsynchronousEditor
を拡張します。
抽象メソッドgetEditorContext(Context)
を実装します。このメソッドは、エディタのUIが所定のContext
で必要とするモデルをロードします。
抽象メソッドdoSetContext(Context)
を実装します。このメソッドは、Editor
で元のメソッドsetContext(Context)
と同じ機能を持つと想定されます。setContext(Context)
はfinalになります(非同期機能の正しい動作を保証します)。
抽象メソッドisContentModelLoaded()
を実装します。このメソッドは、エディタによって使用されるモデルがロードされるかどうかにかかわらず、非同期エディタ・フレームワークを指定します。
抽象メソッドopenImpl(boolean)
を実装します。非同期エディタの正しい動作を保証するために、Editor
の抽象メソッドopen()
がfinalになります。openImpl
は、エディタのUIのモデルがロードされたかどうかを示すブール引数を渡します。ほとんどのケースで、与えられた引数がtrue
の場合、必要となるのは既存のopen()
の実装をopenImpl
に移すことだけです。
Editor
ライフサイクル・イベントのすべてのコードを新しいメソッドに移動します。非同期コンテンツのロードが正しく作動することを保証するために、AsynchronousEditor
はエディタのライフサイクルをfinalにして、impl
メソッドでそれらを実装するサブクラスを提供します。
finalにするライフサイクル・メソッドは次のとおりです。
open
close
editorShown
editorHidden
activate
deactivate
AsynchronousEditorのサブクラスは次のメソッドを実装する必要があります。
openImpl(boolean)
closeImpl(boolean)
editorShownImpl(boolean)
editorHiddenImpl(boolean)
activateImpl(boolean)
deactivateImpl(boolean)
この場合、ブール引数はエディタのコンテンツ・モデルがロードされたかどうかを示します。
このタスクの複雑さは、特定のエディタのクラス階層の数のレベルに比例します(特にライフサイクル・メソッドをオーバーライドする場合)。一連のクラスがclose()
をオーバーライドする場合、それらすべてがかわりにcloseImpl(boolean)
をオーバーライドする必要があります。
構造エクスプローラでは、ドキュメントの編成が通常はツリーとして表示されます。JDeveloperでは、一般的な様々なドキュメント・タイプに対してエクスプローラが提供されます。カスタム・エクスプローラをインストールして、エクスプローラ・マネージャに登録することもできます。
構造エクスプローラでは、ドキュメントの編成が通常はツリーとして表示されます。
構造エクスプローラは、Document
のView
です。エディタまたはデザイナにフォーカスが移ると、そのエクスプローラが構造ウィンドウに表示されます。エクスプローラは、本質的にはドキュメントの索引または目次です。ユーザーはエクスプローラを使用して、ドキュメント・ビューに表示されるコンテンツをナビゲートします。ドキュメントの階層は「構造」ウィンドウに表示され、ドキュメントが編集されると更新されます。
JDeveloperでは、一般的な様々なドキュメント・タイプに対してエクスプローラが提供されます。カスタム・エクスプローラをインストールして、エクスプローラ・マネージャに登録することもできます。ドキュメントがJDeveloperで開かれると、対応するエクスプローラがエクスプローラ・マネージャによって提供されます。エクスプローラはドキュメントを解析して、生成される構造を表示します。
エクスプローラ・アドインには次のコンポーネントが含まれます。
登録を実行するクラス。このクラスがAddin
を実装します。JDeveloperが起動されると、このクラスの1つのインスタンスがアドイン・マネージャによって作成され、このインスタンスが登録を実行します。アドイン・クラスには他の目的は必要ありません。
エクスプローラのユーザー・インタフェースを提供するクラス。このクラスは特別なビューアです。ドキュメントの構造がツリーで表示されるとき、必要な機能のほとんどは、TreeExplorer
またはそのサブクラスの1つを拡張することで提供されます。このクラスは、要素でのマウスのクリックを処理し、エディタでの変更を追跡し、必要な場合にツリーを再構築するパーサーを呼び出します。
Element
の1つ以上のインスタンスを含む要素モデル。このモデルは、ドキュメントのエクスプローラ・ビューの構造表現です。要素は、ドキュメントのコンテンツの特定の場所に関連付けられています。選択されると、ビューアがその場所までスクロールします。
ドキュメントの要素の構造を生成するパーサー。パーサーは、ドキュメントを、ビューア座標にマッピングされる要素の階層に単純化します。
エクスプローラを設計するときは次の点に注意してください。
Explorer
は、Document
に含まれるデータの構造化された視覚的表現を提供するビューです。
1つのドキュメントに対して複数のエクスプローラの実装が存在することが可能です。
Explorer
インタフェースを実装して、構造エクスプローラを作成します。
ChildFilter
は、TreeExplorer
と組み合せて使用するオプション・インタフェースです。これは、ユーザーがコンテナ・ノードを展開したときに表示される子をフィルタリングします。
エクスプローラは、IDEのExplorerManager
に登録する必要があります。登録すると、エクスプローラがノード・クラスまたはノードとビューアのペアに関連付けられます。
ユーザーがノードについてビューアを選択するとき、IDEは、ノードとビューアに最適なエクスプローラのリクエストをExplorerManager
に送ります。ビューアは、そのノードとビューアについて登録されているものか、ノードのみについて登録されているものです。該当する登録が行われていない場合、ExplorerManagerは、リクエストのノード・クラスに互換されるノード・クラスに登録されているビューアを見つけようとします。
登録処理は、次の例に示すようにアドイン・クラスのinitializeメソッドで実行する必要があります。このコード例は、Extension SDKに含まれるサンプル・プロジェクトの1つ、StructurePaneプロジェクトのものです。詳細は、「Extension SDKを使用した開発」を参照してください。
public void initialize() { Class editorClass = PropFileEditor.class; ExplorerManager.getExplorerManager().register(PropFileSourceNode.class, PropFileExplorer.class, PropFileEditor.class ); }
エクスプローラの要素モデルは、所定のドキュメントのデータを視覚的に示す構造表現です。
各モデルは、Element
の1つ以上のインスタンスで構成されます。通常、モデルはエクスプローラ内でツリーとしてレンダリングされますが、これは必須ではありません。要素モデルはビジュアル・オブジェクトではありませんが、グラフィカル・コントロールを使用して視覚的にレンダリングされます。たとえば、javax.swing.JTree
によってレンダリングされるjavax.swing.tree.TreeModel
です。
エクスプローラの実装により、そのモデルと、さらにはそのモデルの視覚表現が、任意の方法でドキュメントのデータに加えられた変更を確実に受け取ります(たとえば、ソース・エディタ、プロパティ・インスペクタでは、JDeveloperの外部でドキュメントを編集します)。これはJDeveloperのイベント・メッセージング・メカニズムを使用して実現されます。
コンポーネント・マネージャを使用すると、個々のページを「コンポーネント」ウィンドウに追加できます。拡張機能のユーザーは、一貫性のあるユーザー・インタフェースの構築や、他の標準化されたタスクの実行のために、これらのページを利用できます。「コンポーネント」ウィンドウでは、コンポーネントのページが提供されます。ユーザーはここからコンポーネントを選択して、拡張機能を使用して構築しているコンテンツまたは拡張機能のために構築しているコンテンツに追加できます。
コンポーネント・ページの作成と管理の機能は、PaletteManager
インスタンスのメソッドを使用して、プログラミングで実行することもできます。詳細は、Oracle Fusion Middleware Oracle Extension SDK Java APIリファレンスのPaletteManager
に関する項を参照してください。
この項では、静的および動的コンポーネントを「コンポーネント」ウィンドウに宣言的に追加する例、追加のヘルプを提供する例、個々のコンポーネント・ページ内でユーザーが特定のアイテムを検索する機能を補強する例を示します。
「コンポーネント」ウィンドウでは、ユーザーは、よく使用されるデータ構造をJDeveloperのプロジェクト、アプリケーションまたは他のコンテンツに追加できます。「コンポーネント」ウィンドウではページが提供されます。ユーザーはここから個別のコンポーネントを選択して、拡張機能を使用して構築しているコンテンツまたは拡張機能のために構築しているコンテンツに追加できます。具体的なコンポーネントには、著作権宣言文のように単純なものもあれば、リモート・リポジトリに接続するための設定のように複雑なものもあります。さらに、JDeveloperでは、所定の「コンポーネント」ウィンドウのページから使用できるコンポーネントは、選択されているファイルのタイプによって異なります。たとえば、HTMLファイルを編集している場合、「コンポーネント」ウィンドウのページには、アンカー、電子メール・リンク、他のよく使用されるHTMLコンポーネントなど、使用可能なHTMLコンポーネントのリストが表示されます。Javaページを編集している場合は、これとはまったく異なるコンポーネントが表示されます。
「コンポーネント」ウィンドウを表示するには、「表示」→「コンポーネント」を選択します。
拡張機能開発者のレベルでは、「コンポーネント」ウィンドウは、ページを宣言的に「コンポーネント」ウィンドウに追加する方法を提供します。これにより、拡張機能のユーザーが特定のコンポーネントを使用できるようになります。そのようなページで、提供を予定している標準コンポーネント(静的と動的の両方)をすべて表示できます。たとえば、一貫性のあるユーザー・インタフェースのユーザーによる構築を支援するために、またはJDeveloperのコンポーネント・マネージャで管理されるコンポーネントを利用する標準化タスクを実行するために、コンポーネント・マネージャを使用して、コンポーネントの1つ以上のページを「コンポーネント」ウィンドウに追加できます。
拡張機能を開発するとき、コンポーネント・ページ、静的コンポーネントと動的コンポーネントおよびそれらのサポートを、拡張機能に宣言によって組み込むことができます。次のことが可能です。
「コンポーネント」ウィンドウで静的コンポーネントを宣言します。
動的コンポーネントを宣言し、「コンポーネント」ウィンドウがロードされたときに組み込みます。
ユーザーがコンポーネントを使用できるようにするのに役立ちます。
ユーザーがコンポーネントを簡単に検索できるようにします。
このような宣言ツールを使用すると、拡張機能ユーザーが、よく使用される要素を拡張機能を使用してユーザー自身のプロジェクトやアプリケーションに追加できます。さらに、ヘルプや検索の機能により、ユーザーがそのような「コンポーネント」ウィンドウを簡単に見つけて適用できるようになります。
コンポーネント・マネージャを使用すると、コンポーネント・ページをプログラミングで追加することもできます。
多くのケースで、「コンポーネント」ウィンドウのコンテンツは変化しません。ソース・リポジトリに対する一連の接続パラメータまたは拡張機能での使用場所にかかわらず変化しない他の固定データです。このようなケースでは、この次の例に示すようにpalette-hook
を使用して拡張機能マニフェスト・ファイルに静的コンテンツを定義できます。
「コンポーネント」ウィンドウの形状は、単純な4層の分類として定義されます。
最も上のレベルはページです。Swing、AWT、ADF Swing、ADF Faces、Java Server Faces (JSF)、JavaServer Pages (JSP)など、テクノロジに応じてコンポーネントをグループ化します。UIでページが表示されるのは、「コンポーネント」ウィンドウの最も上にあるコンボ・ボックスの選択肢です。
各ページにはグループがあります。グループには少数の機能カテゴリが含まれます。たとえば、ページSwingには、Common ControlsとLayoutというグループが含まれることがあります。グループは、「コンポーネント」ウィンドウのドッキング可能ウィンドウです。
各グループにはセクションがあります。セクションは、共通のコンポーネントをまとめて、メニュー・セパレータに似た区切り線をUIに表示し、コンポーネントを名前のアルファベット順に並べます。
最後は、各セクションにアイテム(またはコンポーネント)があります。アイテムは、「コンポーネント」ウィンドウにコンポーネントを表示するための属性(たとえば、名前、説明、アイコンなど)で構成されます。
次の例は、Extension SDKのCPPageProvider
プロジェクトのものであり、1つのコンポーネントを含む「コンポーネント」ウィンドウ・ページを宣言する方法を示しています。Extension SDKの詳細は、「Extension SDKを使用した開発」を参照してください。
<?xml version="1.0" encoding="UTF-8" ?> <extension xmlns="http://jcp.org/jsr/198/extension-manifest" id="oracle.ide.extsamples.cppageprovider" version="11.1.1" esdk-version="1.0"> <name>ESDK Sample - Component Palette Page Provider</name> <owner>Oracle</owner> <feature-member id="esdk-samples" xmlns="http://xmlns.oracle.com/ide/extension"/> <hooks> <palette-hook xmlns="http://xmlns.oracle.com/jdeveloper/1013/extension"> <pageProvider> <providerClassName>oracle.ide.extsamples.pageprovider.SamplePageProvider</provider ClassName> </pageProvider> <page> <name>Sample Components (ESDK Sample)</name> <pageId>SampleStatic</pageId> <showForTypes> <type>java</type> </showForTypes> <technologyScopes> <technologyScope>Java</technologyScope> </technologyScopes> <type>java</type> <group> <name>Components</name> <groupId>SampleStatic-Components</groupId> <showForTypes> <type>java</type> </showForTypes> <technologyScopes> <technologyScope>Java</technologyScope> </technologyScopes> <type>java</type> <section> <sectionId>SampleStatic-Components-Section1</sectionId> <name/> <item> <name>Table</name> <description>Sample Table</description> <icon>${OracleIcons.TABLE}</icon> <info/> <type>JavaBean</type> <itemId>SampleStatic-Components-Section1-Item1</itemId> <technologyScopes> <technologyScope>Java</technologyScope> </technologyScopes> </item> </section> </group> </page> </palette-hook> <feature-hook> <part-of>oracle.ide.extsamples.allsamples</part-of> <description>Demonstrates how to integrate a component palette page provider into the IDE.</description> <optional>true</optional> </feature-hook> </hooks> </extension>
ロードする前に「コンポーネント」ウィンドウのコンテンツを識別できないことがあります。「コンポーネント」ウィンドウのコンテンツを事前に定義できない場合は、「コンポーネント」ウィンドウ・ページ・プロバイダを定義する必要があります。この方法によりクライアント開発の柔軟性が高くなります。つまり、「コンポーネント」ウィンドウが表示コンテキストをプロバイダに提供すると、プロバイダが、「コンポーネント」ウィンドウに表示するコンポーネントを返します。
「コンポーネント」ウィンドウ・ページ・プロバイダは、公開されている「コンポーネント」ウィンドウAPIを使用してクライアントの開発者によって開発され、ページ・プロバイダのクラス名は、拡張機能マニフェスト・ファイルの「コンポーネント」ウィンドウに提供されます。
「コンポーネント」ウィンドウAPIの詳細は、Oracle Fusion Middleware Oracle Extension SDK Java APIリファレンスのoracle.ide.palette2
を参照してください。
拡張機能マニフェストのエントリはフックのelement pageProvider
を使用します。
次の例は、「コンポーネント」ウィンドウ・ページ・プロバイダのクラス名を指定する拡張機能マニフェストです。
<?xml version="1.0" encoding="windows-1252" ?> <extension xmlns="http://jcp.org/jsr/198/extension-manifest" id="oracle.ide.samples.pageprovider" version="1.0" esdk-version="1.0"> <name>Component Palette Page Provider Sample</name> <owner>Oracle</owner> <dependencies> <import>oracle.ide.palette2 </dependencies> <hooks> <palette-hook xmlns="http://xmlns.oracle.com/jdeveloper/1013/extension"> <pageProvider> <providerClassName>oracle.ide.samples.pageprovider.SamplePageProvider</providerClassName> </pageProvider> </palette-hook> </hooks> </extension>
次の例は、「コンポーネント」ウィンドウに「コンポーネント」ウィンドウ・ページを追加する、「コンポーネント」ウィンドウ・ページ・プロバイダを示しています。このクラスはPalettePageProvider
を拡張します。
extension.xml
の要素pageProvider.providerClassName
は、このクラスをページ・プロバイダとして「コンポーネント」ウィンドウに登録します。「コンポーネント」ウィンドウは、現在のコンテキストを使用してcreatePalettePages()
を呼び出します。
PalettePages
を拡張するクラスSamplePages
は、現在のコンテキストで構成されます。つまり、このクラスがパレット・ページのリストを編成するために十分な情報を得るのは、getPages()
が「コンポーネント」ウィンドウから呼び出されるときです。
package oracle.ide.samples.pageprovider; SamplePageProvider.java import oracle.ide.Context; import oracle.ide.palette2.PalettePageProvider; import oracle.ide.palette2.PalettePages; /** * SamplePageProvider * <p> * This is an example of a PalettePageProvider that adds a palette page to the * Component Palette(CP). As required this class extends PalettePageProvider. * </p> * <p> * Element pageProvider.providerClassName in extension.xml registers * this class with the CP as a page provider. * </p> * <p> * The CP will call method createPalettePages() with the current Context. * Class SamplePages which extends PalettePages is constructed with the current context. * Using the current context SamplePages should have sufficient information to * assemble a list of palette pages when method getPages() is called by the CP. * </p> * * @see SamplePages * @see SamplePalettePage * @see SamplePaletteGroup * @see SamplePaletteItem */ public class SamplePageProvider extends PalettePageProvider { /** * Default constructor. * */ public SamplePageProvider() { } /** * Override the default, returns SamplePages if context applies. * * @param context * @return PalettePages if context is relevant, otherwise null. */ public PalettePages createPalettePages(Context context) { if ( checkRelevantContext( context ) ) { SamplePages pages = SamplePages.getInstance(); pages.initialize(context); return pages; } else return null; // no pages to provide for this context. } }
次の例は、SamplePages.java
のインスタンスを示しています。このクラスは、pageType
がjava
の場合に、1つのアイテムと1つのセクションを含む1つのグループで「コンポーネント」ウィンドウ・ページを作成します。必要に応じてこのクラスはPalettePages
を拡張します。
package oracle.ide.samples.pageprovider; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import oracle.ide.Context; import oracle.ide.net.URLFileSystem; import oracle.ide.palette2.DefaultPaletteSection; import oracle.ide.palette2.PaletteItem; import oracle.ide.palette2.PalettePage; import oracle.ide.palette2.PalettePages; import oracle.ide.palette2.PalettePagesListener; /** * SamplePages * <p> * This class creates a palette page with a single group that contains a * single section that contains a single item when the pageType is "java". * As required this class extends PalettePages. * </p> * <p> * TODO: palettePagesListener * </p> */ public class SamplePages extends PalettePages { private final static String SAMPLEPROVIDER_ID =SamplePageProvider.class.getName(); /** * Singleton */ private static SamplePages _singleton = new SamplePages(); /** * Composite for PalettePagesListener */ protected List<PalettePagesListener> palettePagesListeners; /** * Composite for PalettePage */ protected List<PalettePage> palettePages; // Default constructor public SamplePages() { } /** * Returns the singleton instance of SamplePages. * @return the singleton instance of SamplePages */ public static SamplePages getInstance() { return _singleton; } /** * Initialize palettePages. * @param context */ public void initialize(Context context) { URL url = context.getNode().getURL(); final String pageType = getSuffix( url ); // Only interested in java. if( pageType.equals("java") ) { if( palettePages != null ) { palettePages.clear(); } // create a PalettePage SamplePalettePage page = new SamplePalettePage "oracle.ide.samples.pageprovider.SampPage01" // pageId , "My Sample Page Component" // description , null // icon , "java" // type , "java" // showForTypes , "Java;JavaBeans" ); // technologyScope // create a PaletteGroup SamplePaletteGroup group = new SamplePaletteGroup "oracle.ide.samples.pageprovider.SampGroup01" // groupId , "My Sample Group" // name , "My Sample Group Component" // description , "java" ); // type // add group to page page.addGroup(group); // create a section. Make the name null since a separator is not neeeded. DefaultPaletteSection section = new DefaultPaletteSection "oracle.ide.samples.pageprovider.SampSection01" // sectionId // add section to group group.addSection(section); // create an item. TODO: use SampleBean.java SamplePaletteItem item = new SamplePaletteItem ("oracle.ide.samples.pageprovider.SampItem01" // itemId , SAMPLEPROVIDER_ID // provider id , "My Sample Bean" // name , "My Sample Bean Description" // description , "/oracle/ide/samples/pageprovider/snapshot.png" // icon , "java"); // type // add item to section section.addItem(item); // add item to section // add page addPage(page); } else { palettePages.clear(); } } /** * getPages */ public Collection<PalettePage> getPages() { return Collections.unmodifiableList(palettePages); } /** * Returns the PaletteItem identified by itemId. providerId is used to * determine whether this item is owned by this page provider. * The provider returns the matching PaletteItem only if the PaletteItem * is within the current context. Null is returned if the PaletteItem is * within the current context or not recognized by this provider. * </p> * @return PaletteItem */ public PaletteItem getItem( String providerId, String itemId ) { if( providerId == null || providerId.length() == 0 || itemId == null || itemId.length() == 0 ) { return null; } PaletteItem paletteItem = null; if( providerId.equals(SAMPLEPROVIDER_ID)) { for( PalettePage palettePage : palettePages ) { SamplePalettePage sampPage = (SamplePalettePage) palettePag paletteItem = sampPage.getItem(itemId); if( paletteItem != null ) { break; } } // end of for } return paletteItem; } /** * addPalettePagesListener public void addPalettePagesListener(PalettePagesListener listener) { if( palettePagesListeners == null ) { palettePagesListeners = new ArrayList<PalettePagesListener>(); } palettePagesListeners.add(listener) } /* * add pages to palettePages. /* private void addPage( SamplePalettePage sampPage ) { if (palettePages == null ) { palettePages = new ArrayList<PalettePage>(); } palettePages.add(sampPage); } */ * Return suffix * @param title Title of EditorFrame */ private String getSuffix( URL url ) ( final String suffix = URLFileSystem.getSuffix( url ); int period = suffix.lastIndexOf( "." ); if( period != -1 ) { // Is a selected file return suffix.substring( period + 1 ); } return ""; } }
次の例は、SamplePalettePage.java
のインスタンスを示しています。
package oracle.ide.samples.pageprovider; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; import oracle.ide.palette2.DefaultPalettePage; /** * SamplePalettePage * <p> * This class extends DefaultPalettePage. DefaultPalettePage comprises * the attributes and methods that this example requires. A constructor is added * to accomodate the data values for this sample. * </p> */ public class SamplePalettePage extends DefaultPalettePage { public SamplePalettePage(String pageId, String pageName, String pageDescription , String pageIcon, String pageType, String pageShowForTypes , String pageTechnologyScope) { setName( pageName ); setDescription( pageDescription ); setIcon( pageIcon ); setData(PAGE_PAGEID, pageId ); setData(PAGE_TYPE, pageType); // make delimited string into a List of strings List<String> showForTypes = new ArrayList<String>(); final StringTokenizer tknTypes = new StringTokenizer pageShowForTypes, ";" ); //NOTRANS while( tknTypes.hasMoreTokens() ) { String token = (String)tknScopes.nextToken(); technologyScope.add(token); } setData(PAGE_TECHNOLOGYSCOPES, technologyScope ); } }
package oracle.ide.samples.pageprovider; import oracle.ide.palette2.DefaultPaletteGroup; /** * SamplePaletteGroup * <p> * This sample extends DefaultPaletteGroup.DefaultPaletteGroup comprises the * attributes and methods that this example requires. A constructor is added to * accomodate the data values for this sample. * </p> * */ public class SamplePaletteGroup extends DefaultPaletteGroup { public SamplePaletteGroup(String groupId, String groupName, String groupDescription, String groupType) { setName( groupName ); setDescription( groupDescription ); setData(GROUP_GROUPID, groupId); setData(GROUP_TYPE, groupType); } }
次の例は、SamplePaletteItem.java
のインスタンスを示しています。
package oracle.ide.samples.pageprovider; import oracle.ide.palette2.DefaultPaletteItem; * SamplePaletteItem * <p> * This example extends DefaultPaletteItem. DefaultPaletteItem comprises * the attributes and methods that this example requires. A constructor is * added to accommodate the data values for this sample. * </p> * */ public class SamplePaletteItem extends DefaultPaletteItem { public SamplePaletteItem(String itemId, String itemProviderId, String itemName, String itemDescription, String itemIcon, String itemType) { setName( itemName ); setDescription( itemDescription ); setIcon( itemIcon ); setItemId( itemId ); setProviderId(itemProviderId); setData(ITEM_TYPE, itemType); ) )
コンポーネントにヘルプを用意する方法は2つあります。
「コンポーネント」ウィンドウ・アイテムの説明は、コンポーネントのツール・チップとして表示され、ユーザーが「コンポーネント」ウィンドウのコンポーネントの上にマウスを重ねると表示できます。説明を複数の行に分けるには改行文字\nを使用します。
ユーザーは「コンポーネント」ウィンドウ・コンポーネントを右クリックして、コンテキスト・メニューからヘルプを選択できます。「ヘルプ」オプションがコンポーネントのコンテキスト・メニューに表示されるのは、そのコンポーネントにHelpableがある場合のみです。helpableクラスをインスタンス化できない場合は、その文字列がIDEヘルプ・システムのhelpIdとして使用されます。
次の例は、その方法を示しています。
<item> <name>Table</name> <description>Sample Table</description> <icon>/oracle/ide/samples/pageprovider/table.png</icon <info/> <type>JavaBean</type> <itemId>SampleStatic-Components-Section1-Item1</itemId> <technologyScopes> <technologyScopes> <technologyScope>JavaBeans</technologyScope> </technologyScopes> <helpable>oracle.samples.SampleHelpable</helpable> </item>
または、次の例のようにhelpidを直接指定できます。
<item> <name>Table</name> <description>Sample Table</description> <icon>/oracle/ide/samples/pageprovider/table.png</icon> <info/> <type>JavaBean</type> <itemId>SampleStatic-Components-Section1-Item1</itemId> <technologyScopes> <technologyScope>Java</technologyScope> <technologyScope>JavaBeans</technologyScope> </technologyScopes> <helpable>help_topic_id</helpable> </item>
これと同じ処理をプログラミングで行うには、getHelpable()
をPaletteItem
インタフェースに実装します。
デフォルトでは、ユーザーが「コンポーネント」ウィンドウの検索ボックスに語または語句を入力すると、JDeveloperは、名前か説明に検索文字列が含まれるアイテムを検索します。
ユーザーに対して表示されない他の埋込みデータ(タグ属性など)を「コンポーネント」ウィンドウによって検索するために、アイテムと一緒にsearchTextContext
を指定できます。
次の例に示すように、「コンポーネント」ウィンドウの拡張機能フックでこれを宣言的に指定できます。
<item> <name>Table</name> <description>Sample Table</description> <icon>/oracle/ide/samples/pageprovider/table.png</icon> <info/> <type>JavaBean</type> <itemId>SampleStatic-Components-Section1-Item1</itemId> <technologyScopes> <technologyScope>Java</technologyScope> <technologyScope>JavaBeans</technologyScope> </technologyScopes> <searchTextContext>MySearchContext</searchTextContext> </item>
次の例に示すように、SearchContext
がPaletteSearch
インタフェースを実装します。
class MySearchContext implements PaletteSearch { boolean searchItemContainsText(String itemId, String searchString) { boolean found = false; // Search internal data return found; } }
ユーザーが自らのプリファレンスを変更および保存できるようにすると、JDeveloperの拡張機能を使用するプロセスに生産性と柔軟性が付加されます。
製品レベルのプリファレンスはPreferences
クラスで管理します。詳細は、Oracle Fusion Middleware Oracle Extension SDK Java APIリファレンスのPreferences
に関する項を参照してください。
プリファレンスを保存するために使用されるデータ構造はHashStructure
です。これもOracle Fusion Middleware Oracle Extension SDK Java APIリファレンスで説明されています。Preferences
クラスは、1つの拡張機能ディレクトリ(製品全体を表す拡張機能)のみにプリファレンスを保存します。たとえば、JDeveloperでは製品ディレクトリの形式はjdev-user-directory/system/oracle.JDeveloper.12.1.3.x.y
となります。12.1.3はバージョン番号、x.yはビルド番号です。プリファレンスを含むファイルの名前はpreferences.xml
です。
一連の新しいプリファレンスをIDEに組み込むには、次の手順を実行します。
プリファレンス・データを表すクラスは、HashStructureAdapter
のサブクラスである必要があります。詳細は、Oracle Fusion Middleware Oracle Extension SDK Java APIリファレンスのHashStructureAdapter
に関する項を参照してください。
次の例には、詳細なコメントが付いた、標準的な実装パターンが含まれます。
package oracle.killerapp.coolfeature; import oracle.javatools.data.HashStructure; import oracle.javatools.data.; import oracle.javatools.data.PropertyStorage; // Start with class being final. You can always remove final if subclassing ever // proves useful. In many cases, subclassing is actually unnecessary and may get // you into an instanceof/typecast mess. Consider defining a separate (not // subclass) adapter class instead. public final class CoolFeaturePrefs extends { // The DATA_KEY should be a hard-coded String to guarantee that its value stays // constant across releases. Specifically, do NOT // constant across releases. Specifically, do NOT use CoolFeaturePrefs.class.getName(). // The reason is that if CoolFeaturePrefs is ever renamed or moved, // CoolFeaturePrefs.class.getName() will cause the DATA_KEY String to change,which // introduces a preferences migration issue (since this key is used in the persisted // XML) that will require more code and testing to accommodate and open up your code to // annoying little bugs. Unknowing developers have been trapped by this problem before, // so eliminate this cause of bugs by using a hard-coded String for DATA_KEY. // // By convention, DATA_KEY should be the fully qualified class name of the // . This helps ensure against name collisions. This also makes it // easier to identify what piece of code is responsible for a preference when you're // looking at the XML in the product-preferences.xml file. Of course, that only works // as long as the adapter class itself is never renamed or moved, so avoid renaming or // moving this class once it's been released in production. private static final String DATA_KEY = "oracle.killerapp.coolfeature.CoolFeaturePrefs"; // Private constructor enforces use of the public factory method below. private CoolFeaturePrefs(HashStructure hash) { super(hash); } // Factory method should take a PropertyStorage (instead of HashStructure directly). // This decouples the origin of the HashStructure and allows the future possibility // of resolving preferences through multiple layers of HashStructure. Classes/methods // that currently implement/return PropertyStorage: // - oracle.ide.config.Preferences // - oracle.ide.model.Project // - oracle.ide.model.Workspace // - oracle.ide.panels.TraversableContext.getPropertyStorage() public static CoolFeaturePrefs getInstance(PropertyStorage prefs) { // findOrCreate makes sure the HashStructure is not null. If it is null, a // new empty HashStructure is created and the default property values will // be determined by the getters below. return new CoolFeaturePrefs(findOrCreate(prefs, DATA_KEY)); } ----------------------- // Like DATA_KEY, all other keys also appear in the XML, so they should not be // changed once released into production, or else you'll have some migration issues // to fix private static final String MAX_NUMBER_OF_THINGIES = "maxNumberOfThingies"; //NOTRANS private static final int DEFAULT_MAX_NUMBER_OF_THINGIES = 17; public int getMaxNumberOfThingies() { // Specify default in the getInt call to take advantage of HashStructure's // placeholder mechanism. See HashStructure javadoc for details on placeholders. return _hash.getInt(MAX_NUMBER_OF_THINGIES, DEFAULT_MAX_NUMBER_OF_THINGIES); } public void setMaxNumberOfThingies(int maxNumberOfThingies) { _hash.putInt(MAX_NUMBER_OF_THINGIES, maxNumberOfThingies); } //--------------------------------------------- private static final String THINGIE_NAME = "thingieName"; //NOTRANS private static final String DEFAULT_THINGIE_NAME = "widget"; //NOTRANS public String getThingieName() { return _hash.getString(THINGIE_NAME, DEFAULT_THINGIE_NAME); } public void setThingieName(String thingieName) { return _hash.putString(THINGIE_NAME, thingieName); } // etc.. }
プリファレンス・パネルを実装するクラスは、DefaultTraversablePanel
のサブクラスである必要があります。詳細は、Oracle Fusion Middleware Oracle Extension SDK Java APIリファレンスのDefaultTraversablePanel
に関する項を参照してください。
次の例は、標準的な実装パターンを示します。
package oracle.killerapp.coolfeature; import oracle.ide.panels.DefaultTraversablePanel; // You should keep the panel class package-private and final unless there // is a good reason to open it up. In general, preferences panels are not // supposed to be part of a published API, so the class modifiers should // enforce that. final class CoolFeaturePrefsPanel extends DefaultTraversablePanel { // But, the no-arg constructor still needs to be public. public CoolFeaturePrefsPanel() { // Layout the controls on this panel. } public void onEntry(TraversableContext tc) { final CoolFeaturePrefs prefs = getCoolFeaturePrefs(tc); // Load prefs into the panel controls' states. } public void onExit(TraversableContext tc) { final CoolFeaturePrefs prefs = getCoolFeaturePrefs(tc); // Save the panel controls' states to prefs. } private static CoolFeaturePrefs getCoolFeaturePrefs(TraversableContext tc) { // If you've implemented CoolFeaturePrefs according to the typica // implementation pattern given above, this is how you attach the // adapter class to the defensive copy of the preferences being // edited by the Tools->Preferences dialog. return CoolFeaturePrefs.getInstance(tc.getPropertyStorage()); } }
次の例は、拡張機能マニフェスト(extension.xml)のXMLフラグメントです。これは、前に説明したパネルを「プリファレンス」ダイアログ(「ツール」メニューから選択可能)に登録します。
<extension ...> <hooks> <settings-ui-hook xmlns="http://xmlns.oracle.com/ide/extension"> <page id="CoolFeaturePrefs" parent-idref="/preferences"> <label>${SOME_RES_KEY}</label> <traversable-class>oracle.killerapp.coolfeature.CoolFeaturePrefsPanel </traversable-class> </page> </settings-ui-hook> </hooks> </extension>
プリファレンス・ダイアログ・コード以外のコードでプリファレンスの読取りと書込みを行う必要がある場合は、oracle.ide.config.Preferences
クラスを使用してプリファレンスを取得します。この方法はプリファレンス・ページでは使用しないでください。このコードを使用してプリファレンス・オブジェクトに変更を加えると、すぐに有効になります。このため、常に取り消せるようにする必要がある「プリファレンス」ダイアログには適していません。
Preferences p = oracle.ide.config.Preferences.getPreferences(); CoolFeaturePrefs myPrefs = CoolFeaturePrefs.getInstance( p );
プリファレンス・モデル・オブジェクトの基礎になっているハッシュ構造にoracle.javatools.data.StructureChangeListener
をアタッチすると、プリファレンスの変更をリスニングできます。通常、適切な方法は、次の例に示すようにリスナーをモデル・オブジェクトにアタッチするためのメソッドを公開することです。
public final class CoolFeaturePrefs extends { //... public void addStructureChangeListener( StructureChangeListener l ) { _hash.addStructureChangeListener( l ); } public void removeStructureChangeListener( StructureChangeListener l ) { _hash.removeStructureChangeListener( l ); } //... }
プロジェクト・プロパティはプロジェクト・プリファレンスに似ています。「プリファレンスについて」を参照してください。
プロジェクト・プロパティはProject
クラスを使用して管理します。詳細は、Oracle Fusion Middleware Oracle Extension SDK Java APIリファレンスのProject
に関する項を参照してください。
アプリケーションの作業をする際、アプリケーション内のプロジェクトがプロパティ設定を共有していると役立ちます。プロジェクト・プロパティの共有は、実行/デバッグ構成から設定するか、プロジェクト・テンプレートをカスタマイズしてプロジェクト作成リスナーを追加し、そのテンプレートで新規プロジェクトを作成するたびに呼び出されるように設定します。これは、拡張機能のライターがプロジェクトの実行構成やその他のプロパティを変更することを許可します。この項では、実行/デバッグ構成を設定して、アプリケーション内のプロジェクト間で共通する設定を使用できるようにする方法を説明します。テンプレートにプロジェクト作成リスナーを追加する方法の説明は、TBDを参照してください。
次のいずれかの時点で、共有された実行構成を使用するようにプロジェクトを構成できます。
プロジェクトがプロジェクト・テンプレートを使用して作成される際に呼び出される作成リスナーを使用してプロジェクトを作成するとき。
テクノロジがプロジェクトに追加されたとき
プロジェクトの移行時
JDeveloperではSharedProjectPropertiesManager
APIを提供しており、これを実行構成ファイルに追加して、実行構成プロパティの共有を有効化できます。
SharedPropertiesManager
: 共有プロパティを管理します。
SharedPropertiesManager getInstance()
: 共有プロパティのインスタンスを取得します。
HashStructure getProperties(Project
project、String
propertyDataKey)
: ワークスペースまたはプロジェクトの適切なプロパティ・ハッシュを返します。
propertiesAreShareable(String)
: 共有するプロジェクト・プロパティを指定します。
isUsingSharedProperties(Project, String)
: プロジェクトで指定された共有プロパティが使用されているかを検証します。
setUsesSharedProperties(Project, String, boolean)
: 共有されたプロパティがプロジェクトで使用されるかどうかを設定します。
次の例に示すように、SharedProjectPropertiesManager
を使用して、プロジェクトで共有実行構成プロパティを使用するように構成します。
if (SharedProjectPropertiesManager.getInstance().propertiesAreShareable( RunConfigurations.DATA_KEY )) { Project project = ...; SharedProjectPropertiesManager.getInstance().setUsesSharedProperty( project, RunConfigurations.DATA_KEY, true ); }
または、IDEから、実行構成プロパティを使用するようプロジェクトを設定できます。
共有実行構成を使用するには:
急速に繰り返されるモデルに基づいてアプリケーション開発を進めるユーザーにとっては、ソリューションからソリューションへと移動する際に、変更を簡単に取り消すための機能が重要です。変更内容をUNDO可能にする機能を追加すると、ユーザーにこの機能が提供されます。
拡張機能でなんらかの形式のテキスト入力が使用される場合、たとえば、会社で使用される特定の機能を備えたカスタム・テキスト・エディタを実装する場合、ユーザーは、テキストを入力しているときに行った変更を元に戻せることを期待します。次の例に示すように、UndoableEdit
を使用すると、ユーザーがテキストに対して加えた変更が拡張機能による実行または取消しが可能になります。
import javax.swing.undo.UndoableEdit; import oracle.ide.Context; import oracle.ide.controller.Command; import oracle.ide.controller.CommandProcessor; import oracle.ide.model.TextNode; import oracle.javatools.buffer.TextBuffer; public class MyCommand extends Command { private UndoableEdit _undoableEdit; public MyCommand(Context context) { super(-1, Command.NORMAL, "Insert Hello"); setContext(context); } public int doit() throws Exception { if (_undoableEdit == null) { final TextNode textNode = (TextNode) context.getNode(); final TextBuffer textBuffer = textNode.acquireTextBuffer(); textBuffer.beginEdit(); textBuffer.insert(0, "Hello World".toCharArray()); _undoableEdit = textBuffer.endEdit(); textNode.releaseTextBuffer(); } else { _undoableEdit.redo(); } return OK; } public int undo() throws Exception { _undoableEdit.undo(); return OK; } }
UNDO可能な変更をドキュメントに加える場合は、次の例に示すように、変更内容を実行する方法と元に戻す方法を認識しているコマンドを実装する必要があります。
import oracle.ide.controller.Command; import oracle.ide.Context; import oracle.ide.model.Node; public class MyCommand extends Command { public MyCommand(Context context, Node affectedNode) { super(-1, Command.NORMAL, "My Changes"); // The context usually already contains the node so this would not be necessary final Context contextCopy = new Context(context); contextCopy.setNode(affectedNode); setContext(contextCopy); } public int doit() throws Exception { final Node affectedNode = context.getNode(); // Do the changes to the node here return OK; } public int undo() throws Exception final Node affectedNode = context.getNode(); // Undo the changes to the node here return OK; } }
<trigger-hooks>
要素はhttp://xmlns.oracle.com/ide/extension
ネームスペースにあります。
<trigger-hooks>
要素には次の3つの子要素が含まれます。
<registry>
- トリガー・フック・ハンドラを登録するために使用されます。
<triggers>
- ここにすべてのトリガー・フックが配置されます。
<rules>
- 一連のトリガーを条件付きで実行するときに使用できる条件を定義します。
IDEで提供されるトリガー・フックを次に示します。
アクション
コントローラ
メニュー
コンテキスト・メニュー
機能フック
エディタ・メニュー
アクセラレータ/ショートカット・キー
ギャラリ・アイテム
テクノロジ・スコープ
エディタ
NodeFactoryレコグナイザ
IDEプリファレンス/設定
アプリケーション・プリファレンス/設定
プロジェクト・プリファレンス/設定
コンテンツ・セット・プロバイダ
シングルトン登録
アプリケーションおよびプロジェクト・マイグレータ
URLFileSystemフック
ImportExportフック
メニュー・カスタマイズ・フック
ブリッジ拡張機能フック
オン・プロジェクト・オープン・フック
ヘルプ・コールバック・フック
ヘルプ・フック
ドッキング可能フック
ヒストリアン・フック
外部ツール・フック
独自のトリガー・フックを定義するには、次の例に示すようにトリガー・フック・ハンドラを登録します。
<trigger-hooks xmlns="http//xmlns.oracle.com/ide/extension/myExtension"> <registry> <trigger-hook-handler tag-name="my-hook" handler-class="oracle.ide.extension.HashStructureHook" namespace="http://xmlns.oracle.com/ide/extension" schema-location="my-hook.xsd" register-as-hook="true"/> </registry> </trigger-hooks>
register-as-hook
属性は、拡張機能のフックを<hooks>
セクションにも指定できるかどうかを制御します。デフォルト値はfalse
です。同じ要素を<hooks>
でサポートする意味がある場合だけtrue
に設定します。
既存の宣言型フックがあり、それをトリガー・フックにする場合は、現在のフック・ハンドラの登録を削除して、かわりのトリガー・フック・ハンドラを登録する必要があります。
JDeveloperで使用されていた以前の標準に対して構築された既存の拡張機能を更新する場合は、下位互換性のために、前と同じネームスペースを使用できます。既存のフックが古いjdeveloper-hook
の子で、これもトリガー・フックとしてサポートする場合は、属性register-as-jdeveloper-hook
をtrue
に設定します。
コアIDEの外部にある拡張機能は、コアIDEに含まれるhook-handler
クラスを使用する必要があります。次の2つの方法があります。
ハンドラ・クラスとしてのoracle.ide.extension.HashStructureHook
。トリガー・フックも<hooks>
にある場合またはトリガー・フックが条件トリガー・セクションで使用できる場合、HashStructure
を監視した後で新しい要素はHashStructureHook
によって処理されます。この状況では、コードはHashStructureHook
イベントをリスニングする必要があります。
DeferredElementVisitorHook
を使用すると、フックのXMLデータを処理するためにカスタムElementVisitor
クラスを使用できます。したがって、すでにカスタム・フック・ハンドラを作成した場合は、コードを再利用できます。
トリガー・フックを使用するには、次の例のような構文を使用します。
<triggers> <singleton-provider-hook> <singleton base-class="oracle.bali.xml.addin.JDevXmlContextFactory" impl-class="oracle.bali.xml.addin.JDevJavaXmlContextFactory" /> </singleton-provider-hook> </triggers> </trigger-hooks>
要素名にtrigger-hook-handler
を定義すると、そのExtensionHook
ハンドラ・クラスの1つのインスタンスが作成され、そのトリガー・フックが使用されるときは常に処理します。
ExtensionHook
インスタンスを取得するには、ExtensionRegistry.getHook(elementName)
を呼び出します。以前のバージョンのJDeveloperの拡張機能開発では、通常の宣言フックのExtensionHook
を取得するためにこのAPIが使用されていました。処理されたすべてのトリガー・フックと、現在ロードされているすべてのフック・セクションは、ExtensionHook
インスタンスの同じバケットに加えられます。
trigger-hook-handler
がHashStructureHook
の場合、返されるHashStructureHook
インスタンスからHashStructure
を取得できます。これには、HashStructure
での要素名のすべての使用箇所のXML情報や、HashStructure
の異なるセクションがどの拡張機能のものかを示す格納情報が含まれます。HashStructureAdapter
サブクラスを使用すると、HashStructure
から情報を抽出できます。
この項では、拡張機能マニフェストでルールや条件を定義する方法について説明します。
ルールやルールのタイプが、拡張機能マニフェストextension.xml
の<trigger-hooks>
の<rules>
セクションで定義されます。
rule-type
は、Javaに実装されるルール関数を表し、関数が受け取るパラメータを指定します(メソッドのシグネチャなど)。IDEによって提供される組込みのルール・タイプのセットがあります。
ルールは、パラメータの特定の値を渡す、ルール関数の呼出しを表します。各ルールにはグローバルに一意のIDが付けられ、ルールをサポートするフックからIDで参照されます。
ルール・フレームワークは、IDEモジュールのoracle.ide.extension.rules
です。
ルール・タイプを定義するには、次の項目を指定する必要があります。
参照のためのID
oracle.ide.extension.rules.RuleFunction
のサブクラスであり、サポートされるパラメータをリストする実装クラス。パラメータがオプションと必須のどちらかを指定できます。
IDEモジュールのextension.xml
によって、次の例に示すようにいくつかの組込みルール・タイプが定義されます。
<trigger-hooks xmlns="http://xmlns.oracle.com/ide/extension"> <rules> <rule-type id="always-enabled" class="oracle.ide.extension.rules.functions.AlwaysEnabled" /> <rule-type id="any-selection-has-attribute" class="oracle.ide.extension.rules.functions.AnySelectionHasAttribute"> <supported-parameters> <param name="element-attribute" required="true"/> </supported-parameters> </rule-type> <rule-type id="context-has-element" class="oracle.ide.extension.rules.functions.ContextHasElement"> <supported-parameters> <param name="element-class" required="true"/> </supported-parameters> </rule-type> <rule-type id="context-has-node" class="oracle.ide.extension.rules.functions.ContextHasNode"> <supported-parameters> <param name="node-class" required="true"/> </supported-parameters> </rule-type> <rule-type id="context-has-project" class="oracle.ide.extension.rules.functions.ContextHasProject" /> <rule-type id="context-has-view" class="oracle.ide.extension.rules.functions.ContextHasView"> <supported-parameters> <param name="view-class" required="true"/> </supported-parameters> </rule-type> <rule-type id="context-has-workspace" class="oracle.ide.extension.rules.functions.ContextHasWorkspace" /> <rule-type id="element-has-attribute" class="oracle.ide.extension.rules.functions.ElementHasAttribute"> <supported-parameters> <param name="element-attribute" required="true"/> </supported-parameters> </rule-type> <rule-type id="on-extension-init" class="oracle.ide.extension.rules.functions.ExtensionInitialized"> <supported-parameters> <param name="extension-id" required="true"/> </supported-parameters> </rule-type> <rule-type id="extension-is-enabled" class="oracle.ide.extension.rules.functions.ExtensionEnabled"> <supported-parameters> <param name="extension-id" required="true"/> </supported-parameters> </rule-type> <rule-type id="on-single-selection" class="oracle.ide.extension.rules.functions.SingleSelection"> <supported-parameters> <param name="element-class" required="false"/> </supported-parameters> </rule-type> <rule-type id="on-multiple-selection" class="oracle.ide.extension.rules.functions.MultipleSelection"> <supported-parameters> <param name="element-class" required="false"/> </supported-parameters> </rule-type> <rule-type id="node-is-dirty" class="oracle.ide.extension.rules.functions.NodeIsDirty" /> <rule-type id="project-has-techscope" class="oracle.ide.extension.rules.functions.ProjectHasTechScope"> <supported-parameters> <!-- Comma-separated list of technology keys --> <param name="technology-keys" required="true" /> <!-- Specify 'all' or 'any' for match, to specify if all keys should exist or any one key suffices --> <param name="match" required="false" /> </supported-parameters> </rule-type> </rules> </trigger-hooks>
<rule-type>
のハンドラは、<rule>
の解析中に使用するために、またルールの実行時評価のためにこの情報を保存します。ルール・クラスは、ルールを評価する必要が生じる最後の瞬間までロードされません。
独自のルール・タイプを導入できますが、いくつかの制限事項を理解することが重要です。
IDEは、完全にロードされていない拡張機能からはルール・タイプ・クラスをロードしません。
ルール評価は、拡張期のロードをトリガーしません。
拡張機能E1がR1-rule-typeとT1-trigger-hookを導入するケースについて考えてみます。T1-trigger-hookではルールの使用がサポートされるとします。拡張機能E1が完全にロードされたときだけ、T1-trigger-hookのデータを使用して、そこで参照されているルールを評価します。したがって、R1-rule-typeのルールをT1-trigger-hookで使用するのは適切です。
ただし、R1-rule-typeのルールをide-coreトリガー・フック(galleryなど)で使用しようとすると、そのルールが評価されるときに拡張機能E1がロードされている保証はありません。その場合にはエラーが記録されます。
ルールは、<trigger-hooks>
の<rules>
セクションで定義されます。ルール・タイプを定義するには、参照のためのID、ルール・タイプを特定するタイプ属性およびルール・タイプで必要なパラメータの値を指定する必要があります。
この次の例に示すように、<rule>
のハンドラによって次の項目が確認されます。
IDが一意かどうか。
タイプの値が、extension.xml(または依存関係のextension.xml)に定義されたルール・タイプのIDと一致するか。
必須パラメータのすべてに値があるか。
指定されているすべてのパラメータが、ルール・タイプに定義されたパラメータ名と一致するか。
<rules> <rule id="context-has-text-node" type="context-has-node"> <parameters> <param name="node-class" value="oracle.ide.model.TextNode" /> </parameters> </rule> <rule id="context-has-source-node-1" type="context-has-node"> <parameters> <param name="node-class" value="org.product.SourceNode1" /> </parameters> </rule> <rule id="context-has-source-node-2" type="context-has-node"> <parameters> <param name="node-class" value="org.product.SourceNode2" /> </parameters> </rule> <rule id="on-xxx-init" type="on-extension-init"> <parameters> <param name="extension-id" value="org.product.MyXxxExtension"/> </parameters> </rule> <rule id="on-yyy-init" type="on-extension-init"> <parameters> <param name="extension-id" value="org.product.MyYyyExtension"/> </parameters> </rule> <rule id="on-text-node-single-selection" type="on-single-selection"> <parameters> <param name="element-class" value="oracle.ide.model.TextNode" /> </parameters> </rule> </rules> </trigger-hooks>
必須パラメータのない各ルール・タイプは、自動的にルールとして登録されます(ルール・タイプIDがルールIDとして使用されます)。たとえば、context-has-project
とnode-is-dirty
は、必須パラメータのないルール・タイプの例です。これらのIDは、ルールが参照される場所であればどこでも使用できます。<rule>
をextension.xml
に明示的に追加する必要はありません。
ルールを含めるextension.xml
とルール名を注意深く選択することにより、IDの重複を回避して、最大限に再利用できます。
経験則としては、パラメータとして渡すクラス名を含む拡張機能を見つけて、ルールをその拡張機能のextension.xml
に含めます。たとえば、「単純なルールの定義方法」の例の中のcontext-has-source-node-1
ルールを定義するには、SourceNode1
クラスを含む拡張機能を探して、ニーズを満たす既存のルールがあるかどうかを確認します。存在しない場合は、ルールをそのextension.xml
に追加します。
IDは、次のように、わかりやすく、ルール・タイプIDに基づくように設定する必要があります。
context-has-xxx-node
context-has-xxx-node
context-has-xxx-element
context-has-xxx-view
on-xxx-single-selection
on-xxx-init
他のルールとブール演算子で構成されるルールを定義できます。サポートされるブール演算子は、<or>、<and>および<not>です。<and>および<or>ブール演算子要素は、任意の数の子を受け入れます。<not>要素は1つの子を受け入れます。ブール演算子の子のそれぞれは、次の例に示すように、ルールの参照か別のブール演算子である必要があります。
<trigger-hooks xmlns="http://xmlns.oracle.com/ide/extension"> <rules> <composite-rule id="context-has-xxx-or-yyy-node"> <or> <rule-reference id="context-has-jsp-node" /> <rule-reference id="context-has-zzz-node" /> </or> </composite-rule> <composite-rule id="on-aaa-and-bbb-init"> <and> <rule-reference id="on-aaa-init" /> <rule-reference id="on-bbb-init /"> </and> </composite-rule> <composite-rule id="more-complicated-composite-rule"> <or> <rule-reference id="rule-a" /> <and> <rule-reference id="rule-b" /> <not> <rule-reference id="rule-c" /> </not> </and> </or> </composite-rule> </rules> </trigger-hooks>
すべてのルールはextension.xml
の<rules>
セクションに定義され、ルールをサポートするフックでIDによって参照されます。
トリガー・フックでルールをサポートする場合に必要となるのは、ルールのIDを受け入れるための構文の変更だけです。規約では、ルールIDをruleという名前の属性に指定する必要があります。これらを、この次の3つの例に示します。
例1
... <item rule="always-enabled"> <name>oracle.jdeveloper.template.wizard.TemplateWizard</name> <id>Application</id> <description>${NEW_APPLICATION_TEMPLATE_GALLERY_ITEM}</description> <help>${MANAGE_TEMPLATES_WIZARD_DESCRIPTION}</help> <folder>Applications</folder> <technologyKey>General</technologyKey> <icon>/oracle/javatools/icons/apptemplate.jpg</icon> </item> </gallery>
例2
<controllers xmlns="http://xmlns.oracle.com/ide/extension"> <controller class="com.random.FooController"> <update-rules> <update-rule rule="on-text-node-selected"> <action id="some.action.id1"> <label>Perform Action on {0}</label> <label-param>${node.name}</label-param> </action> </update-rule> </update-rules> </controller> <controller class="com.random.BarController"> <update-rules> <update-rule rule="on-jsp-node-selected"> <action id="some.action.id3" /> <action id="some.action.id4" /> <action id="some.action.id5" /> </update-rule> </update-rules> </controller> </controllers>
例3
<context-menu-hook rule="context-has-xxx-or-yyy-node"> <site ref-id="navigator"/> <menu> <section xmlns="http://jcp.org/jsr/198/extension-manifest" id="MY_CUSTOM_MENU_SECTION_ONE" weight="1.0"> <item action-ref="myTriggerActionId" weight="1.0" /> <item action-ref="myOtherTriggerActionId" weight="2.0" /> </section> </menu> </context-menu-hook>
トリガー・フックを実装しているときに、フックでルールをサポートする場合は、ルールのIDを受け入れるルール属性をXML構文に追加します(ルール属性のXMLスキーマ・タイプはxsd:NCName
にする必要があります)。
フック・ハンドラの実装で、ルール属性の値を取得するときは、次のメソッドをRuleEngineで呼び出して、ルール参照の解析時評価を実行します。
public static boolean validateRuleReference(String id, Set<String> expectedRuleTypes, ElementContext referenceContext
このメソッドは、そのIDの既知のルールが(同一extension.xml
または依存関係に)存在することを検証します。また、オプションのexpectedRuleTypes
を渡すと、ルールがそれらのタイプの1つかどうかを検証します(複合ルールの場合は、すべてのパーティクルが予期されるタイプであることが必要です)。オプションのreferenceContext
パラメータが渡されると、すべての問題はElementContext
のロガーでログをとります。
ルールを実際に評価するときには、ルール・エンジンでルールIDをIDEコンテキスト(ある場合)と一緒にメソッドに渡します。ルール・エンジンは、ルール・タイプ・クラスをインスタンス化し、ルール定義のパラメータをコンテキストと一緒に渡して、trueまたはfalseを返します。
public static boolean evaluateRule(String id, Context ideContext)
最初のメソッドは、ルール評価時に発生する例外のログをとり、ルールの評価に問題がある場合はfalseを返します。後のメソッドは、すべての例外のログをとりますが、呼出し元に例外をスローします(呼出し元が別のアクションを実行する場合)。
JDeveloperによって使用されるヘルプ・システムでは、コンテキスト依存の[F1]キーのトピックをIDEの構造に統合して提供しています。ユーザーがヘルプにアクセスするには、ウィザード・パネルまたはダイアログの「ヘルプ」ボタンをクリックするか、[F1]キーを押します。
拡張機能でもコンテキスト依存の[F1]ヘルプ・トピックを提供すると、拡張機能のユーザーが拡張機能を理解して効果的に使用できるようになります。
ヘルプ・システムを作成するにはhelpsetを用意します。これは多数のHTMLヘルプ・トピックを含むJavaアーカイブです。
ヘルプ・システムの作成の詳細は、次を参照してください。その他の資料およびOracle Help for Java Developer's Kitのダウンロードは、http://www.oracle.com/technetwork/developer-tools/help/index-083946.html
を参照してください。
ヘルプ・システムを作成するには、次の手順を実行します。
拡張機能のヘルプ・システムは、拡張機能がロードされる前にユーザーが使用する必要があります。これは、ユーザーが機能分野を把握できるようにするためです。このため、次の例に示すようにヘルプ・システムを登録する必要があります。
<trigger-hooks xmlns="http://xmlns.oracle.com/ide/extension"> <triggers> <help xmlns="http://xmlns.oracle.com/jdeveloper/1013/extension"> <item> <helpName>ejb</helpName> <helpURL>../doc/$edition/ohj/helpset.jar!/helpset.hs</helpURL> <relativeTo>using_diagrams</relativeTo> <relativePosition>after</relativePosition> </item> </help> </triggers> </trigger-hooks>
JDeveloperでは、Component
またはTextNode
に基づいてPageable
オブジェクトを作成できるDocumentPrintFactory
のデフォルト実装が提供されます。
次の例に示すように、DocumentPrintFactory
をextension.xmlに宣言的に登録することで印刷がサポートされます。
<hooks> <print-hook xmlns="http://xmlns.oracle.com/ide/extension"> <documentPrintFactory id="oracle.jdevimpl.help.HelpTopicDocumentPrintFactory" class="oracle.jdevimpl.help.HelpTopicDocumentPrintFactory" /> </print-hook> </hooks>
ビューから印刷できるようにするには、ビュー・クラスと、印刷がビューで呼び出されたときにPageable
オブジェクトを作成するDocumentPrintFactory
を登録する必要があります。
次の例は、oracle.ide.navigator.NavigatorWindow
のprintHelper
を登録する方法を示し、oracle.ide.print.DocumentPrintFactory
というIDで登録されたDocumentPrintFactory
を、Pageable
オブジェクトの作成で使用することを指定します。
<hooks> <print-hook xmlns="http://xmlns.oracle.com/ide/extension"> <printHelper documentPrintFactoryId="oracle.ideri.navigator.NavigatorPrintFactory" view-class="oracle.ide.navigator.NavigatorWindow" /> </print-hook> </hooks>
別のものを印刷するか、デフォルトの印刷機能を拡張する場合は、DocumentPrintFactory
を拡張して、ビューのPageable
オブジェクトを作成し、DocumentPrintFactory
の実装を登録します。次の例は、複数のビューで同じDocumentPrintFactory
を使用する方法を示します。
<print-hook xmlns="http://xmlns.oracle.com/ide/extension"> <documentPrintFactory id="oracle.jdevimpl.help.HelpTopicDocumentPrintFactory" class="oracle.jdevimpl.help.HelpTopicDocumentPrintFactory" /> <printHelper documentPrintFactoryId="oracle.jdevimpl.help.HelpTopicDocumentPrintFactory" view-class="oracle.jdevimpl.help.HelpTopicEditor" /> <printHelper documentPrintFactoryId="oracle.jdevimpl.help.HelpTopicDocumentPrintFactory" view-class="oracle.jdevimpl.help.HelpWindow" /> <printHelper documentPrintFactoryId="oracle.jdevimpl.help.HelpTopicDocumentPrintFactory" view-class="oracle.jdevimpl.help.HelpContentPanel" /> <printHelper documentPrintFactoryId="oracle.jdevimpl.help.HelpTopicDocumentPrintFactory" view-class="oracle.jdevimpl.help.HelpCenterWindow$HelpCenterView" /> </print-hook> </hooks>
JDeveloperでは、印刷するTextNode
データを扱うためにデフォルトのPageableFactory実装が提供されます。
場合によっては、必要な出力が提供される実装で標準のPageableFactory
実装をオーバーライドします。たとえば、NavigatorWindow
に登録されているDocumentPrintFactory
はNavigatorPrintFactory
です。印刷するためにPageable
オブジェクトを作成する必要がある場合は、PrintManager.createPageableForObject()
を呼び出します。これが、選択された要素に最適なPageableFactory
を見つけようとします。ノード・クラスの処理に使用されるPageableFactory
を登録できます。
<print-hook xmlns="http://xmlns.oracle.com/ide/extension"> <textNodePageableFactory node-class="oracle.mypackage.MyNodeClass" weight="0.5">oracle.mypackage.MyPageableFactory</textNodePageableFactory> </print-hook>
次の例では、ノード・クラスは、指定されたPageableFactory
で処理する必要があるノード(この場合はoracle.mypackage.MyPageableFactory
)を指定します。現在の要素との一致をチェックするとき、登録されたPageableFactory
実装のリストを順序付けるために重みが使用されます。
JDeveloper付属のアプリケーションまたはプロジェクト・テンプレートが自分の独自のニーズを満たさない場合は、自分でアプリケーションまたはプロジェクト・テンプレートを定義できます。アプリケーションおよびプロジェクト・テンプレートは、モジュールのextension.xml
ファイル内で宣言によって定義され、それぞれ自動的に「一般」 > 「アプリケーション」および「一般」 > 「プロジェクト」内の新規ギャラリにロードされます。テンプレート定義から動的ウィザードが生成され、アプリケーションまたはプロジェクトの定義ページと、オプションでプロジェクトのテクノロジごとに1つの追加構成ページが表示されます。
アプリケーションまたはプロジェクト・ギャラリ・テンプレートは、extension.xml
ファイル内のテンプレート・フックを使用して定義します。
テンプレート・フックを使用して、プロジェクトおよびアプリケーション・テンプレートを作成します。<template-hook>
要素には子要素<projectTemplate>
および<applicationTemplate>
が含まれ、http://xmlns.oracle.com/ide/extension
ネームスペースにあります。
<projectTemplate>
要素を使用してプロジェクト・ギャラリに表示されるプロジェクト・テンプレートを定義します。<projectTemplate>
には次の子要素が含まれます。
<name>
- ギャラリに表示されるプロジェクト名を指定します。
<templateId>
- 一意のプロジェクトIDを指定します。
<unsorted>
- (オプション)ギャラリのリストでこのアイテムを先頭にしてテンプレート・リストをソートします。この要素は、デフォルト・テンプレートをリストの先頭に置くために使用するよう意図されているため、推奨しません。
<galleryFolder>
- プロジェクトに加え、フォルダにギャラリ・アイテムを追加します。
<description>
- プロジェクトの簡潔な説明。
<packageName>
- デフォルトのパッケージ名を表示します。
<toolTip>
- (オプション)IDEのプロジェクト・ウィンドウで、カーソルがプロジェクト名またはアイコンの上に置かれたときに、プロジェクトのパスを表示します。
<icon>
- (オプション)ギャラリ内のプロジェクトのアイコンを指定します。
<projectName>
- プロジェクトのファイル名を指定します。名前が指定されなかった場合は、デフォルト名(Project1
、Project2
、...)が使用されます。
<creationListener>
- 作成リスナー要素を指定します。
<excludeFromGallery>
- このプロジェクト・テンプレートが、そのアプリケーション・テンプレートのコンテキストのみで使用されるかどうかを指定します。この要素をtrue
に設定すると、ギャラリ内の使用可能なプロジェクトのリストにこのプロジェクトが表示されません。
<applicationTemplate>
要素を使用して、アプリケーション・ギャラリに表示されるアプリケーション・テンプレートを定義します。<applicationTemplate>
には、次の子要素が含まれます。
<name>
- ギャラリに表示されるアプリケーション名を指定します。
<templateId>
- 一意のアプリケーションIDを指定します。
<unsorted>
- (オプション)ギャラリのリストでこのアイテムを先頭にしてテンプレート・リストをソートします。この要素は、デフォルト・テンプレートをリストの先頭に置くために使用するよう意図されているため、推奨しません。
<galleryFolder>
- アプリケーションに加え、フォルダにギャラリ・アイテムを追加します。
<description>
- アプリケーションの簡潔な説明。
<packageName>
- デフォルトのパッケージ名を表示します。
<toolTip>
- (オプション)IDEのアプリケーション・ウィンドウで、カーソルがアプリケーション名またはアイコンの上に置かれたときに、アプリケーションのパスを表示します。
<icon>
- (オプション)ギャラリ内のアプリケーションのアイコンを指定します。
<applicationName>
- アプリケーションのファイル名を指定します。名前が指定されなかった場合は、デフォルト名(Application1
、Application2
、...)が使用されます。
<projectTemplates>
- アプリケーション内のプロジェクトを指定する<projectTemplate>
要素が含まれます。
プロジェクト・テンプレートは、モジュールのextension.xml
ファイル内で宣言によって定義します。テンプレートは自動的に「一般」 > 「アプリケーション」または「一般」 > 「プロジェクト」内の新規ギャラリにロードされます。テンプレート定義から動的ウィザードが生成され、プロジェクトの定義ページと、オプションでプロジェクトのテクノロジごとに1つの追加構成ページが表示されます。
次の例に、Javaプロジェクト・テンプレートのテンプレート定義を示します。
<projectTemplate> <name>${TEMPLATE_JAVA_PROJECT}</name> <description>${TEMPLATE_JAVA_PROJECT_DESC}</description> <packageName>${TEMPLATE_JAVA_PROJECT_PACKAGE}</packageName> <projectName>${TEMPLATE_JAVA_PROJECT_JPR_NAME}</projectName> <templateId>javaProjectTemplate</templateId> <technologyScope> <technologyKey>Java</technologyKey> <technologyKey>Swing/AWT</technologyKey> <technologyKey>JavaBeans</technologyKey> </technologyScope> </projectTemplate>
同様に、アプリケーション・テンプレートは、モジュールのextension.xml
ファイル内で宣言によって定義します。アプリケーション・テンプレートも、自動的に新規ギャラリにロードされます。テンプレート定義から動的ウィザードが生成され、アプリケーションの定義ページが表示されます。
次の例に、Javaアプリケーション・テンプレートのテンプレート定義を示します。
<applicationTemplate> <name>${TEMPLATE_JAVA_APP}</name> <templateId>javaAppTemplate</templateId> <unsorted>true</unsorted> <galleryFolder>General</galleryFolder> <description>${TEMPLATE_JAVA_APP_DESC}</description> <projectTemplates> <projectTemplate> <templateId>javaProjectTemplate</templateId> </projectTemplate> </projectTemplates> </applicationTemplate>
一部の拡張機能を使用する場合、プロジェクトにすでに含まれているテクノロジから独立して、プロジェクトがあるテクノロジをサポートするようカスタマイズする必要がある場合があります。プロジェクトをカスタマイズするには、プロジェクト・テンプレートを変更して作成リスナーを登録し、変更されたテンプレートからプロジェクトが作成されると通知を受けるようにできます。
creationListener
要素を登録すると、リスナーが定義されているテンプレート(IDによって識別)からプロジェクトが作成されると、作成リスナーが呼び出されます。
creationListener
要素はオプションです。リスナーはテンプレートに登録されていなければ、呼び出されません。呼び出される場合、次の例に示すように、リスナーはプロジェクトの作成後に呼び出されます。
<template-hook> <projectTemplate> <templateId>testCallbackProjectTemplate</templateId> <name>Creation Listener Test Project</name> <description>A project for testing creation listener callbacks.</description> <projectName>sylvia</projectName> <creationListener>oracle.myfeature.wizard.MyWizardCallback</creationListener> <excludeFromGallery>true</excludeFromGallery> </projectTemplate> <applicationTemplate> <templateId>testCallbackAppTemplate</templateId> <name>Creation Listener Test App</name> <description>Creates an application for testing wizard creation listener implementation.</description> <applicationName>WizardCallbackApp</applicationName> <projectTemplates> <projectTemplate> <templateId>testCallbackProjectTemplate</templateId> </projectTemplate> </projectTemplates> </applicationTemplate> </template-hook>
プロジェクト・テンプレートには、ユーザーがプロジェクトに特定のテクノロジを含められるようにするページを使用できます。オプションで、これらの各テクノロジにつき、テンプレート作成ウィザードに表示される構成ページを定義できます。
特定のテクノロジ・スコープのウィザード・ページを定義するには、そのページをテクノロジ・スコープの宣言に追加する必要があります。次の例に、Javaテクノロジ・スコープの定義を示します。このテクノロジ・スコープにより、ページがプロジェクト作成ウィザードに追加されます。これらのウィザード・ページは、oracle.ide.panels.DefaultTraversablePanel
を拡張し、oracle.jdeveloper.wizard.template.WizardTraversable
を実装する必要があります。
<technology-hook xmlns="http://xmlns.oracle.com/ide/extension"> <technology> <key>Java</key> <name>${JAVA_TECH}</name> <description>${JAVA_TECH_DESC}</description> <wizard-pages> <page> <traversable-class>oracle.jdevimpl.wizard.project.JavaTechnologyPanel </traversable-class> </page> </wizard-pages> </technology> </technology-hook>
アプリケーション・テンプレートを作成した後、ページを追加する必要がある場合があります。たとえば、ユーザーがビルド構成を指定できるページを提供するよう、テンプレートにページを追加する場合があります。アプリケーションの作成ウィザードにページを追加するには、<applicationAddonPage>
要素をテンプレート定義に含めます。
アプリケーション・テンプレートでは、サブスクライブしているアドオン・ページ・グループのリストを定義する必要があります。複数のグループにサブスクライブすることが可能です。アドオン・ページは、公開先のアドオン・ページ・グループを定義する必要があります。これは1つのグループである必要があります。複数のアドオン・ページが同じグループに公開できます。同じページを複数のグループに公開する必要がある場合、アドオン・ページ・テンプレート・フックをもう1つ作成し、同じクラス名を返します。
アドオン・ページは、アプリケーション・テンプレートAPIの強化機能です。その機能は次のとおりです。
パネルをすべてのアプリケーション・テンプレートまたは特定のアプリケーション・テンプレートに追加する機能
アプリケーション・テンプレートがアドオン・ページの使用を選択できるようにする機能
パネルを既存のアプリケーション・テンプレートの最初、アプリケーション定義の直後に追加する機能
パネルを既存のアプリケーション・テンプレートの最後に追加する機能
注意:
アドオン・ページは、どうしても必要で、任意の理由でアプリケーション・テンプレートを変更できない場合のみ使用してください。
次の例では、アプリケーション・テンプレートを定義するextension.xml
ファイルにある、テンプレートがアドオン・ページ・グループの使用を選択できるようにする<addonPageGroups>
フィールドが含まれている既存のテンプレート・フックを示しています。
<applicationTemplate> <name>${TEMPLATE_JAVA_APP}</name> <templateId>javaAppTemplate</templateId> <unsorted>true</unsorted> <galleryFolder>General</galleryFolder> <description>${TEMPLATE_JAVA_APP_DESC}</description> <projectTemplates> <projectTemplate> <templateId>javaProjectTemplate</templateId> </projectTemplate> </projectTemplates> <addonPageGroups> <addonPageGroup>testGroup</addonPageGroup> </addonPageGroups> </applicationTemplate>
<addonPage>
要素は、次の例で示されている、アドオン・ページを定義するテンプレート・フックのextension.xml
の一部です。
<template-hook> <applicationAddonPage> <name>${TEMPLATE_TEST_ADDON_PAGE_NAME}</name> <pageId>testPage</pageId> <label>${TEMPLATE_TEST_ADDON_PAGE_LABEL}</label> Needs to be translated so reference a key in a resource bundle.--> <title>${TEMPLATE_TEST_ADDON_PAGE_TITLE}</title> <class>oracle.jdeveloper.MyPanel</class> <location>beginning</location> <addonPageGroup>testGroup</addonPageGroup> </applicationAddonPage> </template-hook>
<applicationAddonPage>
要素には、次の子要素が含まれます。
<name>
- ページ名を指定します。
<pageID>
- ページの一意のIDを指定します。
<label>
- ウィザードでの進行状態を示す、ウィザード・ダイアログの左側に表示される名前を指定します。
<title>
- ウィザード・ページの詳細を説明する、ウィザード上部に表示される内容を指定します。
<class>
- インスタンスを作成するパネルを宣言します。WizardTraversable
およびTraversable
を実装する必要があります。
<location>
- (オプション)ページを挿入する位置を、ウィザードの最初または最初と指定します。この要素が指定されていない場合、デフォルトの値はend
です。
<addonPageGroup>
- このアドオン・ページ・テンプレートが追加されるアドオン・ページ・グループを指定します。
ページをアプリケーション・テンプレートに追加するには、次の基本手順に従ってください。