#topicpath ---- //ここにコンテンツを記述します。 #include(Eclipse/プラグイン開発のTIPS集/記事一覧) #contents **覚え書き [#j62d232a] ***とりあえずやってみる [#k6a964ed] JavaWorldの2004年3月号に特集されていたので、Eclipseのプラグイン開発ツールを触ってみました。 Eclipseはこのプラグインの固まりで、すべての機能はプラグインで作成されているみたいです。ようするにEclipseを機能拡張したい場合はこのプラグインという作法に則って作成するわけですね。 まだ全然やり方がわかりません。とりあえずView(パースペクティブ内の一つのタイルのこと)を拡張して、選択しているファイルのファイル名を表示するプラグインを作成しています。 簡単なやり方は - プラグイン開発 >> プラグイン・プロジェクト >> プロジェクト名~ (プロジェクト名はたとえばnu.mine.kino.sampleとか) -プラグイン・コード生成プログラム >> デフォルト・プラグイン構造~ (何も追加しない単純なテンプレート) 後はすべてデフォルトでOKでよいです。ウィザードが完了すると、単純なプラグイン・プロジェクトの作成完了です。 基本的な構成はできたので、次はプラグインファイル(plugin.xml)の記述です。手順は -プラグインエディタの拡張タブ >> 追加 >> 汎用ウィザード >> スキーマベースの拡張 -拡張ポイントを org.eclipse.ui.views を選択 -プラグインエディタの拡張タブより、org.eclipse.ui.viewsを右クリック >> 新規 >> Category を追加(Viewを属させるグループの作成) -さらに拡張タブより、org.eclipse.ui.viewsを右クリック >> 新規 >> View を追加(実際のViewの作成) とするとViewを追加できます。後はプロパティViewより必要事項を入力します。 ただのビューを表示するだけなら <extension point="org.eclipse.ui.views"> <category name="サンプルMyView" <- viewが属するカテゴリ名 id="com.samples.myview"> <- カテゴリのID </category> <view name="シンプルView" <- viewのバーのタイトル category="com.samples.myview" <- viewが属するカテゴリID class="com.samples.myview.SimpleView" <- viewを実装するクラス名 id="com.samples.myview.simpleview"> <- viewのID </view> </extension> で十分です。プロパティViewよりclassを選択すると対応するクラス(ここではcom.samples.myview.SimpleView)のスケルトンもウィザードが作ってくれます。 ***サンプルのダウンロード [#w152c277] ヘルプに リッチ・クライアント・プラットフォーム・アプリケーションのビルド という項目があったので、見てみるとサンプルがEclipseのCVS :pserver:anonymous@dev.eclipse.org:/home/eclipse からチェックアウト可能とのこと。パスワードはなしですね。 WEBからアクセスする場合は http://dev.eclipse.org/viewcvs/index.cgi/ ***プラグインのディレクトリを取得する(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 ***プラグインのディレクトリを取得する(3.2系) [#s7717b57] Eclipse3.2からまたdeprecatedになっちゃいました。今度は、 URL entry = ClientPlugin.getDefault().getBundle().getEntry("/"); String pluginDirectory = FileLocator.resolve(entry).getPath(); みたいですね。FileLocatorは org.eclipse.core.runtime.FileLocator みたいです。 ***外部のライブラリを使用する [#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([プロジェクト名の文字列]); ***デバッグするためのダイアログを出したい [#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(); どうも、↑こうやってもDOMConfiguratorはlog4j.jarの入ってるプラグインで実行されているっぽい。。[[EclipseCon2005 TUTORIALS 26 Developing for the Rich Client Platform :http://www.eclipsecon.org/2005/tutorials.php]] のFrequent problems with third party libraries によれば Thread currentThread = Thread.currentThread(); ClassLoader oldClassLoader = currentThread.getContextClassLoader(); try { currentThread.setContextClassLoader(plugin.getClass().getClassLoader()); // 普通に処理を書く } finally { currentThread.setContextClassLoader(oldClassLoader); } が正解っぽい??すいません。時間切れ。。 ***プラグインクラスに定義しておきたいメソッド [#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$ をはずすもしくはなにもしない| ***plugin.xmlのimport要素の記述の意味 [#p33d3a4d] Eclipse付属のマニュアルは以下のようになっています。 '''それぞれの依存性は、<import> エレメントを使用して指定されます。これには以下の属性が含まれています。 ''' -plugin - 必要なプラグインの ID -version - (オプション) バージョン指定 -match - バージョン・マッチング規則。 version 属性が指定されていない場合は無視されます。依存性が 指定されたバージョンと 正確に一致するプラグインのみ、サービスまたは修飾子がこれよりも新しいプラグイン、すべての互換バージョン (プラグインの最新マイナー・バ ージョンを含む)、またはこのプラグインよりも新しいバージョンのどれによって満たされるかを決定します。 -export - このプラグインのユーザーに依存プラグイン・クラスを可視にする ((再度) エクスポートする) かどうかを指定します。デフォルトでは、依存クラスはエクスポートされません (可視になりません) -optional - この依存性が、厳密に強制されるかどうかを指定します。 <true> に設定すると、依存性は満たされず、依存性は無視されます。 とくに :export|たぶん、プラグインBをimportするプラグインAがあるとき、プラグイン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); } という感じで使える。。 ***ビューワにコンテキストヘルプを実装する [#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); とするほうがよいようです。 *** ステータスバーに文字を表示する [#w46781b5] [[リレーショナル・データベース・サーバーをEclipseに埋め込む:http://www-06.ibm.com/jp/developerworks/opensource/040220/j_os-echsql.html#N1006E]] みてて知ったTIPS window 変数をIWorkbenchWindow の インスタンスとしたとき ((ApplicationWindow)window).setStatus("HSQLDB Server already running."); で、ステータスバーに文字列を表示することが出来る ***パースペクティブを操作する [#o0831edf] まずはパースペクティブのレジストリへのアクセス方法です。パースペクティブはorg.eclipse.ui.IPerspectiveRegistry というレジストリで管理されています。 IPerspectiveRegistry pRegistry = PlatformUI.getWorkbench().getPerspectiveRegistry(); でレジストリへの参照を取得できます。 続いてパースペクティブ自体にアクセスします。パースペクティブは、何となくわかってきましたがIPerspectiveDescriptorと一対一対応します。IPerspectiveDescriptorには public String getDescription(); public String getId(); public ImageDescriptor getImageDescriptor(); public String getLabel(); などのメソッドがあります。 IPerspectiveDescriptorへの参照は以下のように取得できます。 -一覧を取得 IPerspectiveDescriptor[] perspectives = pRegistry.getPerspectives(); -キー値指定で個別に取得 IPerspectiveDescriptor descriptor = pRegistry.findPerspectiveWithId("plugin.xmlのパースペクティブID"); ***パースペクティブをプログラムから切り替える [#necf3bc2] パースペクティブをセットするメソッドがIWorkbenchWindowとかIWorkbenchPageにあるはず、、と思って探したら、ありました。 PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(). setPerspective(descriptor);<-descriptorはIPerspectiveDescriptor でレジストリから取って来る なげぇよ、長すぎるよ。あもちろんwindowとか取れる場合はPlatformUIとかからやらなくていいですけどね。めんどくさくなると、すぐPlatformUIよんでしまう。。 ***リンク付きのラベルを使用する [#d932a074] Eclipse3.1から導入された、ウィジェット上にリンクを表示するLinkクラスの使い方です。 #ref(link.png) コード Link link = new Link(container, SWT.NONE); link.setText("<a>リンク</a>, <a>portable</a> <a href=\"native\">operating systems</a> on which it is implemented."); link.addListener(SWT.Selection, new Listener() { public void handleEvent(Event event) { System.out.println("Selection: " + event.text); ↑event.textで、href属性があればその中の文字列(上ならnative)、 href属性がなければ<a>○○</a>の中に囲まれた「○○」が取得できる } }); このようにして、SWT.Selectionのイベントを見て処理をすればよいようです。クリックしたらウィザードを起動するとか、ベタにブラウザを起動するとか、なんでもできますね。 ***各ビューで選択されているオブジェクトを取得する [#waa835e9] Eclipseには、[[ISelectionProviderという、「選択されているオブジェクトを外部に公開するクラス」を、Viewごとに設定する>Eclipse/プラグイン開発のTIPS集/org.eclipse.ui.ISelectionListener]]ことができます。このオブジェクトはViewごとに存在するので、各Viewのこのインスタンスを取得できれば、選択されているオブジェクトを getSite().getSelectionProvider().getSelection(); と取得できます。 さらにもっと便利なメソッドがありました。 ISelection selection = page.getSelection([viewid]); で一発で取得できます。pageはIWorkbenchPageのインスタンスです。これは便利!! -このサイト内の、Eclipseプラグイン開発のコンテンツ一覧 #ls2 #include(Eclipse/プラグイン開発のTIPS集/GooglePlugin) **[[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(おもしろかった[11],そうでもない[2]) -SpringのクラスをラップしてSpring Pluginを作ろうと思ったんだけど、ApplicationContext自体がこのプラグインのクラスローダでロードされるから、Springを使用したいプラグイン側のクラスが見えないっ。。そもそもXMLファイル自体をSpringプラグインのパスで探しちゃうし。。それぞれのプラグインでjarを持つのももったいないしなあ -- [[きの]] &new{2006-03-09 19:55:29 (木)}; #comment #topicpath SIZE(10){現在のアクセス:&counter;}