- 追加された行はこの色です。
- 削除された行はこの色です。
#topicpath
----
//ここにコンテンツを記述します。
-このサイト内の、Eclipseプラグイン開発のコンテンツ一覧
#ls2
----
#include(Eclipse/プラグイン開発のTIPS集/GooglePlugin)
*** [[Google Web APIs>Webサービス/Google Web APIs]] でプラグインを作る [#v5867095]
Eclipseプラグイン開発の練習として、[[Google Web APIs>Webサービス/Google Web APIs]]を使ったプラグインを作ってみました。要件としては
-Eclipseでコーディング中に、Googleにアクセスしたい。
-エディタ上のテキストを選択して、ポップアップメニューからGoogle検索
-検索結果一覧から、ダブルクリックとかポップアップメニューでブラウザを起動して、そのサイトを表示する。
-結果一覧からドラッグ&ドロップでURLを作りたい
といった感じですかね。
#ref(shortcut.png)
~
#ref(shortcut2.png)
Eclipse自体を見ていると、プラグイン開発はGUI部分とビジネスロジックのCore部分を分けて作るのが基本みたいです。なので今回作成するプラグイン構成は
-nu.mine.kino.plugin.google.core
-nu.mine.kino.plugin.google.ui
な感じにしました。
-[[まずはCoreをつくる>Eclipse/プラグイン開発のTIPS集/GooglePlugin/まずはCoreをつくる]]
-[[UI部のロジックをつくる>Eclipse/プラグイン開発のTIPS集/GooglePlugin/UI部のロジックをつくる]]
-[[設定を保持するIPreferenceStoreを使う>Eclipse/プラグイン開発のTIPS集/GooglePlugin/設定を保持するIPreferenceStoreを使う]]
-[[検索結果一覧を表示するビュー>Eclipse/プラグイン開発のTIPS集/GooglePlugin/検索結果一覧を表示するビューの作成]]
-[[検索ロジックをビューに実装>Eclipse/プラグイン開発のTIPS集/GooglePlugin/実際の検索ロジックをビューに実装]]
----
#contents
**覚え書き [#j62d232a]
***サンプルのダウンロード [#w152c277]
ヘルプに リッチ・クライアント・プラットフォーム・アプリケーションのビルド という項目があったので、見てみるとサンプルがEclipseのCVS
:pserver:anonymous@dev.eclipse.org:/home/eclipse
からダウンロード可能とのこと。
*** アクティブなエディタへの参照の取得 [#uf7ea3d1]
// ワークベンチの取得
IWorkbench workbench = PlatformUI.getWorkbench();
IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
//アクティブなエディタの取得
IEditorPart editor = window.getActivePage().getActiveEditor();
AbstractTextEditor aEditor = (AbstractTextEditor) editor;
*** エディタ内のドキュメントを取得 [#o1b1fa35]
IDocument document =
aEditor.getDocumentProvider().getDocument(editor.getEditorInput());
***プラグインのディレクトリを取得する(2.0系) [#rf1a32e3]
Log4jの初期化のためにlog4j.xmlを読み込むなど、プラグインディレクトリのパスを取得する場面は結構ありますが、その方法です。
String pluginDirectory = Platform
.resolve(getDefault().getDescriptor().getInstallURL()).getPath();
で取得できます。
ちなみにLog4jの初期化などはAbstractUIPluginのサブクラス(勝手に作られるヤツ)で
public void startup() throws CoreException {
super.startup();
String pluginDirectory = null;
try {
pluginDirectory =
Platform
.resolve(getDefault().getDescriptor().getInstallURL())
.getPath();
} catch (IOException e) {
e.printStackTrace();
}
DOMConfigurator.configure(new File(pluginDirectory, "lib/log4j.xml").toString());
}
などとstartup()をOverrideすればよいでしょうか。
***プラグインのディレクトリを取得する(3.0系) [#ae45800c]
Eclipse3.0から上のやり方は deprecated になりました。2.0で
String pluginDirectory = Platform
.resolve(getDefault().getDescriptor().getInstallURL()).getPath();
だったのを3.0では
URL entry = getDefault().getBundle().getEntry("/");
String pluginDirectory = Platform.resolve(entry).getPath();
と書き換えます。
http://www3.vis.ne.jp/~asaki/p_diary/diary.cgi?Date=2004-09-05
***外部のライブラリを使用する [#dc5c9f14]
プラグインディレクトリにlibディレクトリなどを作成しておいて、plugin.xmlで
<runtime>
<library name="hoge.jar"/>
<library name="lib/fuga.jar"/> <-外部ライブラリ
</runtime>
とすればOKです。
*** プロジェクトへの参照を取得する [#u15a6a98]
いわゆるEclipseのプロジェクトへの参照を取得する方法です。
IWorkspaceRoot myWorkspaceRoot =
ResourcesPlugin.getWorkspace().getRoot();
IProject project = myWorkspaceRoot.getProject([プロジェクト名の文字列]);
***ポップアップメニューの拡張 [#sfc14d79]
<extension point="org.eclipse.ui.popupMenus">
<objectContribution
objectClass="org.eclipse.core.resources.IResource" <- ファイルとか、フォルダだったら表示
objectClass="org.eclipse.jdt.core.ICompilationUnit" <- いわゆるソースファイルだったら
objectClass="org.eclipse.core.resources.IFile" <- ファイルだったら表示
objectClass="org.eclipse.core.resources.IFolder" <- フォルダだったら表示
id="nu.mine.kino.IResource">
<action label="スクリプト生成(&R)"
class="nu.mine.kino.HogeAction"
menubarPath="additions" <- すでにあるメニューに追加
enablesFor="1" <- 選択したファイルが1つだけの時有効
id="nu.mine.kino.HogeAction">
</action>
</objectContribution>
</extension>
***デバッグするためのダイアログを出したい [#a91aa3cd]
IWorkbench workbench = PlatformUI.getWorkbench();
IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
Shell shell = window.getShell();
MessageDialog.openInformation(shell, "タイトル","メッセージ");
が定番でしょう。windowオブジェクトはメソッドを記述するクラスによってはフィールドから得られたりしますが。。
***ウィンドウに配置されているViewを取得する。 [#z76cff34]
IWorkbenchPage page = workbench.getActiveWorkbenchWindow().getActivePage();
IViewReference[] references = page.getViewReferences();
for (int i = 0; i < references.length; i++) {
IViewPart view = references[i].getView(false); <- Viewへの参照が取得できました
MessageDialog.openInformation(window.getShell(), "ViewのtoString()", view.toString());
}
***ウィンドウに配置されているViewを、ID指定で取得する。 [#i39484e4]
IWorkbench workbench = PlatformUI.getWorkbench();
IWorkbenchPage workbenchPage = workbench
.getActiveWorkbenchWindow().getActivePage();
//IWorkbenchPage workbenchPage = editor.getSite().getPage();
try {
HogeView view =
(HogeView) workbenchPage.showView("HogeViewのID");
} catch (PartInitException e) {
}
***おなじViewを複数開く [#t81ac22d]
Eclipse3.0から(だと思う)同じウィンドウを複数開くことができるようです。
IWorkbench workbench = PlatformUI.getWorkbench();
IWorkbenchPage workbenchPage = workbench
.getActiveWorkbenchWindow().getActivePage();
try {
HogeView view =
(HogeView) workbenchPage
.showView("HogeViewのID", "HogeViewの別のID(Uniqueならよい?)",
IWorkbenchPage.VIEW_ACTIVATE);
} catch (PartInitException e) {
}
http://d.hatena.ne.jp/muimy/20040804 から情報をいただきました。
***プラグインのパッケージング手順 [#i4b96068]
-build.propertiesに、パッケージしたいものを記述する(bin.includesにlib/hoge.jarとかicons/*とか)
-plugin.xmlの右クリック >> Antビルドファイルの作成 でbuild.xml作成
-javac要素はソースコードのエンコーディングが考慮されてないので、追加(encoding="EUC-JP"など)。
-ant zip.pluginでZIPが作成される。
-完了。
トラブル(↓メモ書き状態)
-plugin.xmlの右クリック>>Antビルドファイルの作成 は、コンパイルのエンコーディングが考慮されない(encoding="EUC-JP"などを追加する必要あり)
-build.propertiesに、パッケージしたいものを記述する(bin.includesに書く)
***パッケージ化するとインスタンスを生成できない。 [#kecb2ad7]
[[パッケージ化するとインスタンスを生成できない。:http://groups.yahoo.co.jp/group/eclipse-ml/message/1019?expand=1]]
私も同じトラブルに遭遇しました。
プラグインをパッケージングすると、何故かエラーになってしまうというもの。ビューを開こうとすると
インスタンスを生成できませんでした。
と言われてしまうんだけど、エラーを調べようにもどこにエラーが表示されているのかも分からないので困っていました。
そこでネットを探していたところ、同じような内容の投稿が。とりあえずこれを見て、プラグインのログは
-ウィンドウ→ビューの表示→その他→PDEランタイム→エラー・ログ で「エラーログビュー」を開く。
-エラーログビューで、該当エラーをダブルクリックし「エラーのプロパティー」を開く。
-「状況詳細」を選択します(状況詳細はない場合もあります)。→ここにStackTraceなどが表示されます。
というところまで分かりました。感謝!!
そのエラーログを見ると、xml関連のライブラリがないと。どうもプラグインをパッケージした場合と、ランタイムワークベンチで稼動しているVMのバージョンの違いが原因でした。((WebSphereStudioはJ2SE1.3だったためだ〜))
plugin.xmlに、
<library name="lib/xercesImpl.jar"/>
<library name="lib/xml-apis.jar"/>
を追加して、ようやく動きました。疲れた...。。。
***プラグインがロードされるタイミング [#lf696913]
http://www-6.ibm.com/jp/developerworks/opensource/040604/j_os-ecspy1.html
***拡張ポイントクラス(IExtension)から、そのクラスローダでメソッドを実行する [#ncca9c7b]
-2.1バージョン
// IExtensionからそれが宣言されているプラグインをIPluginDescriptorとして取り出す。
IPluginDescriptor descriptor =
extension.getDeclaringPluginDescriptor();
// そのプラグイン用のクラスローダを取得。
ClassLoader classLoader = descriptor.getPluginClassLoader();
DOMConfigurator configurator = (DOMConfigurator) classLoader
.loadClass("org.apache.log4j.xml.DOMConfigurator")
.newInstance();
-3.0バージョン
String namespace = extension.getNamespace();
Bundle bundleOfExtension = Platform.getBundle(namespace);
DOMConfigurator configurator = (DOMConfigurator) bundleOfExtension
.loadClass("org.apache.log4j.xml.DOMConfigurator")
.newInstance();
***プラグインクラスに定義しておきたいメソッド [#bf1fd810]
○○Pluginなど、プラグインクラスにはそのプラグインでやりたいビジネスロジックや、ログ出力などのロジックを記述します。ログ出力に関するメソッドはだいたい以下のようなメソッドを定義しておけばよいでしょう。
public static void log(String message, Exception e) {
IStatus status = new Status(IStatus.ERROR, getPluginId(),
IStatus.ERROR, message, e);
getDefault().getLog().log(status);
}
public static void log(String message) {
log(message, null);
}
public static void log(Exception e) {
StringWriter stringWriter = new StringWriter();
e.printStackTrace(new PrintWriter(stringWriter));
String message = stringWriter.getBuffer().toString();
log(message, e);
}
public static String getPluginId() {
return getDefault().getBundle().getSymbolicName();
}
***リファクタリング >> ストリングの外部化 [#m6e7d7f7]
Eclipse自体のTIPSですが、メモメモ。
Eclipseはハードコーディングされた文字列を外部ファイル(*.properties)に外出しするリファクタリングをすることができます。で、それをやるとStringの一覧のダイアログが出るんですけど、なんかわかりにくかったんでまとめておきます。各チェックの意味は以下の通り。
|チェック|Externalize|外部化して、//$NON-NLS-1$ をつける|
|×|Ignore|以後無視するよう、//$NON-NLS-1$ をつける|
|×'|Internalize|//$NON-NLS-1$ をはずすもしくはなにもしない|
*** Viewerにポップアップメニューをつける。 [#w21d509e]
下記のメソッドをcreatePartControl(Composite parent)で実行する
private void hookContextMenu() {
MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager manager) {
fillContextMenu(manager);
}
});
Menu menu = menuMgr.createContextMenu(viewer.getControl());
viewer.getControl().setMenu(menu);
getSite().registerContextMenu(menuMgr, viewer);
// getSite().registerContextMenu("hogeID",menuMgr, viewer);
// ↑別のIDをつける場合(ここではhogeID)
}
private void fillContextMenu(IMenuManager manager) {
manager.add(action1);
// Other plug-ins can contribute there actions here
manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS
+ "-end"));
}
これで、ポップアップの追加・他のプラグインへの公開の準備ができたことになります。
***他のプラグインから、既存のビューのポップアップにアクションを追加する。 [#m473b99d]
上で、
getSite().registerContextMenu(menuMgr, viewer);
manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
としたことで、
-このビューのポップアップはmenuMgrですよ
-ポップアップに追加するときに指定するtargetIDはビューのIDですよ((もしくはgetSite().registerContextMenu("hogeID",menuMgr, viewer);とやってIDを指定できる。))
-menubarPathはIWorkbenchActionConstants.MB_ADDITIONSという文字列(("additions"という文字列))ですよ
という事になります。ここまでできてると別のプラグインからこのビューのポップアップにアクションを追加することができます。追加するにはplugin.xmlで以下のように宣言すればOKです。
<viewerContribution targetID="hoge"
id="nu.mine.kino.plugin.samples.viewerContribution2">
<action
label="追加したアクション"
class="nu.mine.kino.plugin.samples.Action4"
↑ IViewActionDelegateの実装クラス
menubarPath="additions"
↑ additionsは IWorkbenchActionConstants.MB_ADDITIONSの文字列
id="nu.mine.kino.plugin.samples.action4"/>
</viewerContribution>
***plugin.xmlのimport要素の記述の意味 [#p33d3a4d]
Eclipse付属のマニュアルは以下のようになっています。
'''それぞれの依存性は、<import> エレメントを使用して指定されます。これには以下の属性が含まれています。 '''
-plugin - 必要なプラグインの ID
-version - (オプション) バージョン指定
-match - バージョン・マッチング規則。 version 属性が指定されていない場合は無視されます。依存性が 指定されたバージョンと 正確に一致するプラグインのみ、サービスまたは修飾子がこれよりも新しいプラグイン、すべての互換バージョン (プラグインの最新マイナー・バ ージョンを含む)、またはこのプラグインよりも新しいバージョンのどれによって満たされるかを決定します。
-export - このプラグインのユーザーに依存プラグイン・クラスを可視にする ((再度) エクスポートする) かどうかを指定します。デフォルトでは、依存クラスはエクスポートされません (可視になりません)
-optional - この依存性が、厳密に強制されるかどうかを指定します。 <true> に設定すると、依存性は満たされず、依存性は無視されます。
とくに
:export|たぶん、プラグインAをimportするプラグインBがあるとき、プラグインBがimportするプラグインCを、Aから使えるようにするか、ってことだと思う。。
A -> B -> C
プラグインBで、プラグインCのexportをtrueにしておけば、AはCをimportしなくてもつかえるってこと?
:optional|プラグインAでimportするプラグインBをoptionalにしておけば、プラグインディレクトリにプラグインBがなくてもプラグインAを活性化できる、ってこと?
***未使用の依存関係の検索でいるモノが出てきちゃう [#x7b39836]
Log4jのライブラリをさまざまなプラグインで使用するので、ひとつのプラグインにしているんだけど、そのプラグインがいっつも不要なプラグインで出てきちゃう。。jarを共有するためだけの場合は、使ってることが検出できないのかな。
ワークスペース内のプラグインプロジェクトを、全て「クラスパスの更新」をやったら、検出できるようになった。ふしぎだ。
***フィーチャー・バージョンの意味 [#x659c9c6]
-フィーチャー・バージョンをプラグインに強制 :すべてフィーチャーのバージョンになる
-プラグインからバージョンをコピー :feature.xmlにワークスペースのプラグインプロジェクトのバージョンを適用する
-フィーチャーで定義されたバージョンをプラグインに強制 :feature.xmlに書いてあるバージョンをワークスペースのプラグインプロジェクトに適用する
1番目と最後の違いは、1番目はフィーチャー自体のバージョンに他のバージョンをあわせるので、全てのプラグインのバージョンは同じになります。最後のはxmlファイルに書いてあるそれぞれプラグインのバージョンをそれぞれのプラグインに適用する、という違いですね。
*** org.eclipse.osgi.util.NLS でプレースホルダ(Eclipse3.1) [#z1311e44]
if (productName == null) {
message = "Exit application?";
} else {
// プレースホルダが使えるの?
message = NLS.bind("Exit {0}?", productName);
}
という感じで使える。。
*** RCPで、終了するときに、終了してよいかをたずねるようにする(たぶんEclipse3.1から) [#r83fa929]
WorkbenchWindowAdvisorのサブクラスでpreWindowShellCloseを以下のようにOverrideする。
public boolean preWindowShellClose() {
// 複数上がってる場合はダイアログ出さないで閉じちゃう。
if (getWorkbench().getWorkbenchWindowCount() > 1) {
return true;
}
// the user has asked to close the last window, while will cause the
// workbench to close in due course - prompt the user for confirmation
IPreferenceStore store = ApplicationsPlugin.getDefault()
.getPreferenceStore();
// この設定値("EXIT_PROMPT_ON_CLOSE_LAST_WINDOW")をみて、ダイアログを出すかを決定する。
boolean promptOnExit = store
.getBoolean("EXIT_PROMPT_ON_CLOSE_LAST_WINDOW");
// storeの設定がtrueだったら
if (promptOnExit) {
String message;
String productName = null;
IProduct product = Platform.getProduct();
if (product != null) {
productName = product.getName();
}
if (productName == null) {
message = "Exit application?";
} else {
message = NLS.bind("Exit {0}?", productName);
}
MessageDialogWithToggle dlg = MessageDialogWithToggle
.openOkCancelConfirm(getWindowConfigurer().getWindow()
.getShell(), "終了の確認", message, "常にプロンプトなしで終了",
false, null, null);
if (dlg.getReturnCode() != IDialogConstants.OK_ID) {
return false;
}
if (dlg.getToggleState()) {
// チェックボックスを付けた(はずした?)とき、falseで保存する。
store.setValue("EXIT_PROMPT_ON_CLOSE_LAST_WINDOW", false);
ApplicationsPlugin.getDefault().savePluginPreferences();
}
}
return true;
}
*** 上で、チェックボックスなしのダイアログを使う [#t1258a6c]
上のやり方は、Eclipse3.1のIDEをパクリました。「常にプロンプトなしで終了」チェックボックスを出さないダイアログは以下でよいと思います。
return MessageDialog.openConfirm(getWindowConfigurer().getWindow()
.getShell(), "終了の確認", message);
***ビューワにコンテキストヘルプを実装する [#v62250e1]
たとえばnu.mine.kino.pluginというプラグインでコンテキストヘルプ(F1のイベントを拾ってヘルプを表示する機能)を使用するには以下のようにします。
viewer.addHelpListener(new HelpListener() {
public void helpRequested(HelpEvent e) {
String contextId = "nu.mine.kino.plugin.workbench_window_context";
nu.mine.kino.pluginはプラグインID
workbench_window_contextは後述のcontext.xml内のキー値。
WorkbenchHelp.displayHelp(contextId);
}
});
実際のコンテキストに表示される内容は拡張ポイントorg.eclipse.help.contextsで指定します。
nu.mine.kino.plugin#plugin.xmlに
<extension point="org.eclipse.help.contexts">
<contexts file="context.xml">
</contexts>
</extension>
とします。
で、context.xmlは以下のよう:
<?xml version="1.0" encoding="UTF-8"?>
<?NLS TYPE="org.eclipse.help.contexts"?>
<contexts>
<context id="workbench_window_context"> <-さっきのキー値。
<description>ヘルプです。</description>
<topic label="てすとワークベンチ" href="concepts/concepts-2.htm"/>
<topic label="てすとパースペクティブ" href="concepts/concepts-4.htm"/>
<topic label="てすとワークベンチの管理" href="tasks/tasks-1.htm"/>
</context>
</contexts>
こうするとviewer上でF1を押したとき、ヘルプが表示されます。
***違うプラグイン上のヘルプファイルを見たい [#me6b0414]
viewer.addHelpListener(new HelpListener() {
public void helpRequested(HelpEvent e) {
String contextId = "nu.mine.kino.doc.workbench_window_context";
// nu.mine.kino.doc はこのソースのプラグインとは別のプラグインとします
WorkbenchHelp.displayHelp(contextId);
}
});
nu.mine.kino.doc#plugin.xmlには以下の内容を記述しておきます。
<extension point="org.eclipse.help.contexts">
<contexts file="context.xml" >
</contexts>
</extension>
context.xmlの書き方は同じでかまいません。
いろいろ処理を調べてみたところ、どうも指定したcontextIdの最後のドットを見てパースし、手前までをプラグインID、その後をキー値としてるみたいだ((org.eclipse.help_3.1.0.jarのorg.eclipse.help.internal.context.ContextManager#getContext(String)))など。
ところで、Eclipse3.1から、
WorkbenchHelp.displayHelp(contextId);
はdeprecatedとなったため、3.1以後は
PlatformUI.getWorkbench().getHelpSystem()
.displayHelp(contextId);
とするほうがよいようです。
**[[Eclipseプラグイン開発:http://yoichiro.cocolog-nifty.com/eclipse/]] [#yd461a90]
#showrss(http://yoichiro.cocolog-nifty.com/eclipse/index.rdf,,24,1)
**[[Eclipse開発 Blog:http://eclipse3.seesaa.net/]] [#yd461a90]
#showrss(http://eclipse3.seesaa.net/index20.rdf,,24,1)
----
この記事は
#vote(おもしろかった[9],そうでもない[1])
#comment
#topicpath
SIZE(10){現在のアクセス:&counter;}