Top / Eclipse / プラグイン開発のTIPS集


Eclipse/プラグイン開発のTIPS集/GooglePlugin

Top / Eclipse / プラグイン開発のTIPS集 / GooglePlugin

Google Web APIs でプラグインを作る

Eclipseプラグイン開発の練習として、Google Web APIsを使ったプラグインを作ってみました。要件としては

といった感じですかね。

shortcut.png


shortcut2.png

Eclipse自体を見ていると、プラグイン開発はGUI部分とビジネスロジックのCore部分を分けて作るのが基本みたいです。なので今回作成するプラグイン構成は

な感じにしました。

インストール

更新サイトよりインストール可能です。 URLはこちら。

Eclipse3.1で開発しているので、今のところ3.1でしか稼動しないかも?

ライセンス

基本的にCPLとか、適当にやっちゃいたいところですが、Google Web APIsが個人・非商用のみOKなのでそれに準じる、とするべきなんですかねえ。Google Web APIsのライセンスについてはTerms and Conditions for Google Web API Serviceをご確認ください*5

結局、ライセンスはとりあえず無難にGPLにすることにしました。


Top / Eclipse / プラグイン開発のTIPS集 / GooglePlugin

現在のアクセス:148570

覚え書き

サンプルのダウンロード

ヘルプに リッチ・クライアント・プラットフォーム・アプリケーションのビルド という項目があったので、見てみるとサンプルがEclipseのCVS

:pserver:anonymous@dev.eclipse.org:/home/eclipse

からダウンロード可能とのこと。

アクティブなエディタへの参照の取得

// ワークベンチの取得
IWorkbench workbench = PlatformUI.getWorkbench();
IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();

//アクティブなエディタの取得
IEditorPart editor = window.getActivePage().getActiveEditor();
AbstractTextEditor aEditor = (AbstractTextEditor) editor;

エディタ内のドキュメントを取得

IDocument document =
  aEditor.getDocumentProvider().getDocument(editor.getEditorInput());

プラグインのディレクトリを取得する(2.0系)

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系)

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

外部のライブラリを使用する

プラグインディレクトリにlibディレクトリなどを作成しておいて、plugin.xmlで

<runtime>
  <library name="hoge.jar"/>
  <library name="lib/fuga.jar"/> <-外部ライブラリ
</runtime>

とすればOKです。

プロジェクトへの参照を取得する

いわゆるEclipseのプロジェクトへの参照を取得する方法です。

IWorkspaceRoot myWorkspaceRoot =
  ResourcesPlugin.getWorkspace().getRoot();
IProject project = myWorkspaceRoot.getProject([プロジェクト名の文字列]);

ポップアップメニューの拡張

<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="スクリプト生成(&amp;R)"
       class="nu.mine.kino.HogeAction"
       menubarPath="additions"  <- すでにあるメニューに追加
       enablesFor="1" <- 選択したファイルが1つだけの時有効
       id="nu.mine.kino.HogeAction">
     </action>
   </objectContribution>
</extension>

デバッグするためのダイアログを出したい

IWorkbench workbench = PlatformUI.getWorkbench();
IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
Shell shell = window.getShell();
MessageDialog.openInformation(shell, "タイトル","メッセージ");

が定番でしょう。windowオブジェクトはメソッドを記述するクラスによってはフィールドから得られたりしますが。。

ウィンドウに配置されているViewを取得する。

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指定で取得する。

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を複数開く

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 から情報をいただきました。

プラグインのパッケージング手順

トラブル(↓メモ書き状態)

パッケージ化するとインスタンスを生成できない。

パッケージ化するとインスタンスを生成できない。 私も同じトラブルに遭遇しました。

プラグインをパッケージングすると、何故かエラーになってしまうというもの。ビューを開こうとすると

インスタンスを生成できませんでした。

と言われてしまうんだけど、エラーを調べようにもどこにエラーが表示されているのかも分からないので困っていました。

そこでネットを探していたところ、同じような内容の投稿が。とりあえずこれを見て、プラグインのログは

というところまで分かりました。感謝!!

そのエラーログを見ると、xml関連のライブラリがないと。どうもプラグインをパッケージした場合と、ランタイムワークベンチで稼動しているVMのバージョンの違いが原因でした。*1 plugin.xmlに、

<library name="lib/xercesImpl.jar"/>
<library name="lib/xml-apis.jar"/>

を追加して、ようやく動きました。疲れた...。。。

プラグインがロードされるタイミング

http://www-6.ibm.com/jp/developerworks/opensource/040604/j_os-ecspy1.html

拡張ポイントクラス(IExtension)から、そのクラスローダでメソッドを実行する

プラグインクラスに定義しておきたいメソッド

○○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();
}

リファクタリング >> ストリングの外部化

Eclipse自体のTIPSですが、メモメモ。

Eclipseはハードコーディングされた文字列を外部ファイル(*.properties)に外出しするリファクタリングをすることができます。で、それをやるとStringの一覧のダイアログが出るんですけど、なんかわかりにくかったんでまとめておきます。各チェックの意味は以下の通り。

チェックExternalize外部化して、//$NON-NLS-1$ をつける
×Ignore以後無視するよう、//$NON-NLS-1$ をつける
×'Internalize//$NON-NLS-1$ をはずすもしくはなにもしない

Viewerにポップアップメニューをつける。

下記のメソッドを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"));
}

これで、ポップアップの追加・他のプラグインへの公開の準備ができたことになります。

他のプラグインから、既存のビューのポップアップにアクションを追加する。

上で、

getSite().registerContextMenu(menuMgr, viewer);
manager.add(new Separator(IWorkbenchActionConstants.MB_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要素の記述の意味

Eclipse付属のマニュアルは以下のようになっています。

それぞれの依存性は、<import> エレメントを使用して指定されます。これには以下の属性が含まれています。

とくに

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を活性化できる、ってこと?

未使用の依存関係の検索でいるモノが出てきちゃう

Log4jのライブラリをさまざまなプラグインで使用するので、ひとつのプラグインにしているんだけど、そのプラグインがいっつも不要なプラグインで出てきちゃう。。jarを共有するためだけの場合は、使ってることが検出できないのかな。

ワークスペース内のプラグインプロジェクトを、全て「クラスパスの更新」をやったら、検出できるようになった。ふしぎだ。

フィーチャー・バージョンの意味

1番目と最後の違いは、1番目はフィーチャー自体のバージョンに他のバージョンをあわせるので、全てのプラグインのバージョンは同じになります。最後のはxmlファイルに書いてあるそれぞれプラグインのバージョンをそれぞれのプラグインに適用する、という違いですね。

org.eclipse.osgi.util.NLS でプレースホルダ(Eclipse3.1)

if (productName == null) {
    message = "Exit application?";
} else {
    // プレースホルダが使えるの?
    message = NLS.bind("Exit {0}?", productName);
}

という感じで使える。。

RCPで、終了するときに、終了してよいかをたずねるようにする(たぶんEclipse3.1から)

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;
}

上で、チェックボックスなしのダイアログを使う

上のやり方は、Eclipse3.1のIDEをパクリました。「常にプロンプトなしで終了」チェックボックスを出さないダイアログは以下でよいと思います。

return MessageDialog.openConfirm(getWindowConfigurer().getWindow()
 .getShell(), "終了の確認", message);

ビューワにコンテキストヘルプを実装する

たとえば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を押したとき、ヘルプが表示されます。

違うプラグイン上のヘルプファイルを見たい

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、その後をキー値としてるみたいだ*4)など。

ところで、Eclipse3.1から、

WorkbenchHelp.displayHelp(contextId);

はdeprecatedとなったため、3.1以後は

PlatformUI.getWorkbench().getHelpSystem()
 .displayHelp(contextId);

とするほうがよいようです。

Eclipseプラグイン開発






Last-Modified:1970/01/01 09:00:00

Eclipse開発 Blog














Last-Modified:1970/01/01 09:00:00


この記事は

選択肢 投票
おもしろかった 9  
そうでもない 1  

Top / Eclipse / プラグイン開発のTIPS集

現在のアクセス:140186


*1 WebSphereStudio?はJ2SE1.3だったためだ〜
*2 もしくはgetSite().registerContextMenu?("hogeID",menuMgr, viewer);とやってIDを指定できる。
*3 "additions"という文字列
*4 org.eclipse.help_3.1.0.jarのorg.eclipse.help.internal.context.ContextManager?#getContext(String
*5 具体的にはgoogleapi.jarを使わないでWSDLから直接ライブラリを作成してるので、このライセンスに準じるべきなのかどうかなどもようわからんです

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS