« 2004年6月 | トップページ | 2004年8月 »

2004.07.30

あるファイルがエディタで開かれているかを取得する方法

今回は,あるファイルが何らかのエディタで開かれているかどうかを取得する方法を紹介する。

早速コードを下記に示す。

  IFile targetFile = ...; // 対象のファイルのハンドル

  IEditorInput input = new FileEditorInput(targetFile);
  IWorkbench workbench = PlatformUI.getWorkbench();
  IWorkbenchWindow[] windows = workbench.getWorkbenchWindows();
  for (int i = 0; i < windows.length; i++) {
    IWorkbenchPage[] pages = windows[i].getPages();
    for (int j = 0; j < pages.length; j++) {
      IEditorPart editor = pages[j].findEditor(input);
      if (editor != null) {
        // エディタで開かれている
        return true;
      }
    }
  }
  // エディタで開かれていない
  return false;

Eclipseのエディタは編集対象をIEditorInputオブジェクトで扱うため,まずは対象のファイルのハンドルを元にFileEditorInputクラスのインスタンスを生成する。この入力オブジェクトがエディタを探すためのキーとなる。

あるエディタを探し出すために,EclipseのUI構成を辿る処理を行う。Eclipseでは,

  「ワークベンチ → ワークベンチウィンドウ → ワークベンチページ → エディタパート」

というコンポジット構造になっている。これをプログラム上でぐるぐる回して,該当するエディタを探し出す。

まずワークベンチ(IWorkbench)オブジェクトをPlatformUIクラスのgetWorkbenchクラスメソッドを呼び出して取得する。ここが基点。ワークベンチは複数のワークベンチウィンドウにより視覚化されるため,次はワークベンチからワークベンチウィンドウ(IWorkbenchWindow)オブジェクトの配列をgetWorkbenchWindowsメソッドを用いて取得する。各ワークベンチウィンドウはいくつかのワークベンチパートを持っているため,さらにワークベンチウィンドウからワークベンチパート(IWorkbenchPart)オブジェクトの配列をgetPagesメソッドを用いて取得する

IWorkbenchPartインタフェースには,入力オブジェクトに対応するエディタを探してくれるfindEditorメソッドが用意されている。各ワークベンチパートオブジェクトに対して,findEditorメソッドに最初に生成したIEditorInputオブジェクトを渡して,IEditorPartオブジェクトを取得する。この際,指定した入力オブジェクトを入力とするエディタが存在すればIEditorPartオブジェクトが返却され,もし存在しなければnullが返却される

つまりコンポジット構造の走査中に,findEditorメソッドの戻り値としてIEditorPartオブジェクトが得られれば対象のファイルがエディタで開かれていることになり,findEditorメソッドの全呼び出しがnullになってfor文を抜けてしまった場合は対象のファイルはエディタで開かれていない,ということになる。

| | コメント (0) | トラックバック (0)

テキストバッファを使ったIDocumentオブジェクトの取得

Eclipseでの作業のほとんどは,エディタに対してテキスト(Javaのソースコードなど)を編集する作業だろう。そして各種プラグインがエディタに機能を提供し,編集作業の補佐を行っている。プラグインからエディタで編集されているテキストを操作するためには,「テキストエディタからのIEditorInput,IDocumentオブジェクトの取得」で紹介した方法でエディタからIDocumentオブジェクトを取得し,それに対して各種メソッドを呼び出して内容を操作すればよい。

しかし,時にはエディタで開かれていないファイルに対しても,その内容について何らかの操作を行いたくなる。「プラグイン内で自動的に対象のファイルをエディタを開いて,IDocumentオブジェクトを取得してテキストを操作すればいいじゃん」というのは確かにありだが,対象のファイルが数多くある場合には,この方法は良い選択とは言えない。このような,エディタを開かずにファイルの内容をIDocumentオブジェクトとして取得したい時のために,Eclipseではテキストバッファと呼ばれる機構を用意してくれている。

テキストバッファの機構は,org.eclipse.core.filebuffersプラグインにより提供されているので,下記のようにプラグイン・マニフェスト内でorg.eclipse.core.filebuffersプラグインの使用を宣言する。

  <plugin ...>
    ...
    <requires>
      ...
      <import plugin="org.eclipse.core.filebuffers"/>
    </requires>
    ...
  </plugin>

では,IDocumentオブジェクトの取得までのコードを見てみよう。

  IPath targetFilePath = ...; // 対象のファイルのパス

  ITextFileBufferManager manager = FileBuffers.getTextFileBufferManager();
  manager.connect(targetFilePath, null);
  ITextFileBuffer buffer = manager.getTextFileBuffer(targetFilePath);
  IDocument document = buffer.getDocument();

最初にテキストバッファを管理してくれるITextFileBufferManagerオブジェクトをFileBuffersクラスのgetTextFileBufferManagerメソッドを使って生成する。その後,connectメソッドに処理対象のファイルのパス(IPathオブジェクト)を渡して,管理オブジェクトにファイルを接続する。第2引数にはIProgressMonitorインタフェースを渡せるようになっている。

管理オブジェクトへファイルを接続できれば,あとはgetTextFileBufferメソッドを使ってITextFileBufferオブジェクトを取得する。この時点でテキストバッファがVM内に存在するようになる。そして,getDocumentメソッドを呼び出すことでIDocumentオブジェクトを取得することができる。IDocumentオブジェクトへの操作は,テキストバッファ内の内容に反映される

IDocumentインタフェースを通じたテキストへの操作は,テキストバッファには反映されているが,ファイルに即座に反映されるわけではない。テキストバッファの内容をファイルに反映するためのコードが下記である。

  buffer.commit(null, true);
  manager.disconnect(targetFilePath, null);

ITextFileBufferオブジェクトのcommitメソッドを呼び出すことにより,テキストバッファの内容がファイルに書き出される。進捗状況を表示したいときは,第1引数にIProgressMonitorオブジェクトを渡す。第2引数は,commitメソッドの呼び出し時に,もしテキストバッファとファイルシステム上のファイルの内容が同期が取れていなかった場合に,問答無用でテキストバッファ内の内容でファイルを上書きするかどうかを指定する。

最後にITextFileBufferManagerオブジェクトのdisconnectメソッドを呼び出して,ファイルを管理オブジェクトから切断する。もちろん,commitメソッドを呼び出さずにdisconnectメソッドを呼び出せば,テキストバッファの内容は破棄されてファイルの内容も元のままとなる。

上記の方法を使えば,エディタに頼ることなく,ファイルの内容をIDocumentオブジェクトとして取り出すことができ,エディタからIDocumentオブジェクトを取得して内容を操作するときと全く同じことを,エディタを開かずに行うことができるようになる。いい感じ。

| | コメント (0) | トラックバック (0)

2004.07.17

Javaエディタのコンテキストメニュー

Eclipseを使っているほとんどの開発者は,Javaの開発が目的で利用していることだろう。Javaの開発者がEclipseに期待することといえば,やはりJavaのソースコードを編集するための充実した機能だ。しかし,ベーシックな機能だけでは物足りないことも出てくる。人間,欲に限りはない。今回は,Javaエディタのコンテキストメニューに独自の項目を追加する方法を紹介する。

ビューのコンテキストメニューに項目を追加する方法は,「特定ビューへのコンテキストメニュー項目の追加」ですでに紹介している。Javaエディタのコンテキストメニューに項目を追加する方法も基本的には同じ。

プラグイン・マニフェスト中にviewerContribution要素を記述してビューのコンテキストメニューに項目を追加するのだが,その際に対象となるビューをtargetID属性で指定する。Javaエディタの場合,targetID属性の値として#CompilationUnitEditorContextを指定する

  <extension point="org.eclipse.ui.popupMenus">
    <viewerContribution
      id="yoichiro.sample.popupMenus.javaeditor"
      targetID="#CompilationUnitEditorContext">
      <action
        id="yoichiro.sample.JavaEditorSampleAction"
        label="Sample Action"
        menubarPath="additions"
        class="yoichiro.sample.JavaEditorSampleAction">
      </action>
    </viewerContribution>
  </extension>

これにより,以下のようにJavaエディタのコンテキストメニューに項目が追加される。

javaeditor-menu1.gif

そして,メニュー項目が選択されたときに駆動されるクラス(class属性で指定するクラス)は,IEditorActionDelegateインタフェースを実装することが必要となる。

  public class JavaEditorSampleAction implements IEditorActionDelegate {
    private IEditorPart targetEditor;
    public void setActiveEditor(IAction action, IEditorPart targetEditor) {
      this.targetEditor = targetEditor;
    }
    public void run(IAction action) {
      if (targetEditor != null) {
        ...
      }
    }
    public void selectionChanged(IAction action, ISelection selection) {
    }
  }

IEditorActionDelegateインタフェースを実装することにより,setActiveEditorメソッド,runメソッド,そしてselectionChangedメソッドを実装することになる。通常は,setActiveEditorメソッドに渡される対象のエディタのオブジェクト(引数のtargetEditor)をフィールドに保持しておき,実際にメニューが選択されたときに呼び出されるrunメソッド内で,保持しておいたエディタオブジェクトに対して何らかの処理を行う。プラグイン・マニフェストでtargetID属性値に#CompilationUnitEditorContextを指定しているので,上記の例の場合はtargetEditorはJavaエディタのオブジェクトとなる。

メニュー項目の追加位置を,

javaeditor-menu2.gif

というようにSourceグループの中にしたいときは,プラグイン・マニフェストのmenubarPath属性を,

  menubarPath="org.eclipse.jdt.ui.source.menu/additions"

というように指定する。

| | コメント (0) | トラックバック (0)

2004.07.14

ダイアログボタンの変更

前回の「ダイアログの自作」では,JFaceのDialogクラスを拡張して,独自のダイアログを作成してみた。そこでは,[OK]ボタンと[Cancel]ボタンが自動的にダイアログに追加されていることが見て取れた。しかし,場合によっては他のボタンを配置したいときもあるだろう。今回は,自作したダイアログに対して[OK][Cancel]以外のボタンを配置する方法を紹介する。

[OK]ボタンと[Cancel]ボタンの配置は,DialogクラスのcreateButtonsForButtonBarメソッドで行われている。つまり,ボタンを自作したい場合は,createButtonsForButtonBarメソッドをオーバーライドしてあげればよいボタンの作成については,createButtonメソッドが準備されているので,それをcreateButtonsForButtonBarメソッドの中で使用してあげればよい。

以下のコードは,前回の「ダイアログの自作」で取り上げたソースコードに対して追記したものである。ダイアログのボタンを[Close]ボタンに変更している。

  public class MyDialog extends Dialog {
    ...
    public static final int CLOSE_ID = 777;
    ...
    protected void createButtonsForButtonBar(Composite parent) {
      createButton(parent, CLOSE_ID, "Close", true);
    }
    protected void buttonPressed(int buttonId) {
      if (buttonId == CLOSE_ID) {
        setReturnCode(CLOSE_ID);
        close();
      } else {
        super.buttonPressed(buttonId);
      }
    }
  }

まず,[Close]ボタンのIDをCLOSE_ID定数として作成しておく。そして,オーバーライドしたcreateButtonsForButtonBarメソッドの中で,createButtonメソッドを使って[Close]ボタンを作成している。createButtonメソッドの引数は,貼り付け先のCompositeオブジェクト,ボタンのID(先ほど作ったCLOSE_ID),ボタンの表示文字列,デフォルトボタンにするかどうか,である。

createButtonsForButtonBarメソッドのオーバーライドにより,表示されるダイアログは以下のようなものになる。

my-dialog2.gif

実行してみればわかるのだが,createButtonsForButtonBarメソッドをオーバーライドしただけでは,[Close]ボタンを押下しても何も起きない。[Close]ボタンが押されたときの処理として,openメソッドの戻り値となる値をセットしてダイアログを閉じる,という動作を記載しなければならない。ダイアログ上に配置されたボタンが押されたときは,buttonPressedメソッドが呼び出されるので,その中でボタンが押された後の処理を記述する。上記のコードでは,引数に渡されたボタンのIDがCLOSE_IDであるかどうかをチェックし,もしそうだった場合はsetReturnCodeメソッドを使ってopenメソッドの戻り値となる値をセットし,closeメソッドを呼び出してダイアログを閉じている。引数の値がCLOSE_ID以外だった場合(この場合ダイアログの[閉じる]ボタンが押されたとき)は,親クラスのbuttonPressedメソッドを呼び出して処理を行わせている。

上記の例では[Close]ボタン1つだったが,もちろんcreateButtonsForButtonBarメソッドの中で複数回createButtonメソッドを使用することによって,複数のボタンを配置することも可能である。

| | コメント (0) | トラックバック (0)

2004.07.13

ダイアログの自作

Eclipseでは,ウィザードやプロパティ編集のためのダイアログが標準でいくつか準備されている。しかし,ダイアログを自作したいときも出てくるだろう。今回はカスタムダイアログの作成方法について紹介する。

ダイアログの作成は,SWTのDailogクラスを拡張する方法と,JFaceのDialogクラスを拡張する方法の2種類がある。JFaceの方がもちろんダイアログを作りやすくしてくれているので,JFraceのDialogクラスを用いる。自作ダイアログは,Dialogクラスを継承して作成する

  public class MyDialog extends Dialog {
    public MyDialog(Shell parent) {
      super(parent);
    }
    protected Point getInitialSize() {
      return new Point(400, 300);
    }
    protected void configureShell(Shell newShell) {
      super.configureShell(newShell);
      newShell.setText("Title of MyDialog");
    }
    protected Control createDialogArea(Composite parent) {
      Composite composite = (Composite)super.createDialogArea(parent);
      Text text = new Text(composite,
        SWT.MULTI | SWT.V_SCROLL | SWT.BORDER | SWT.WRAP);
      text.setLayoutData(new GridData(GridData.FILL_BOTH));
      text.setText("Hello!");
      return composite;
    }
  }

どんなウィジェット(AWTとかMotifとかGTKとかXawとか)でも,大抵ダイアログを表示するためには,その親となるウィンドウが必要となる。JFaceのDialogクラスの場合も,コンストラクタの呼び出しにShellオブジェクトを必要とする。もちろんこれはnullが許容されるが,ダイアログは何らかのウィンドウに属することは必然だと思うので,実際にはnullを渡すことは避けるべき。

ダイアログに関する各種設定やクライアント領域のコンテンツの作成などは,Dialogクラスで規定されたメソッドをオーバーライドすることにより記述する。

まずはダイアログの大きさを決めるために,getInitialSizeメソッドをオーバーライドし,縦横の大きさを持つPointオブジェクトを返すようにする。ダイアログが開かれる際にこのメソッドが自動的に呼び出され,返却された値がダイアログのサイズとして使用される。

次にダイアログのタイトルバーに表示する文字列だが,これはダイアログのShellオブジェクトに設定することになる。ダイアログが開かれるとき,新しく内部(親のWindowクラスのcreateShellメソッド内)でShellオブジェクトが作られる。作成されたShellオブジェクトに対して操作を行うために,configureShellメソッドをオーバーライドする。configureShellメソッドにはShellオブジェクトが渡されてくるので,まずは親のcnofigureShellメソッドを呼び出し(デフォルトイメージ・レイアウトの設定が行われる),その後でsetTextメソッドを使ってタイトルバーの文字列をセットしている。ここでShellオブジェクトのsetImageメソッドを使えば,イメージを変えることも可能。

そして一番肝心なメソッドがcreateDialogAreaメソッド。createDialogAreaメソッドをオーバーライドし,その中でダイアログのクライアント領域に対してコンポーネントを配置していくコードを記述する。引数で渡されてくるCompositeオブジェクトに対してコンポーネントを配置するのが基本なのだが,実はそれよりも上記のコードのように,一旦親のcreateDialogAreaメソッドを呼び出し,その結果得られるCompositeオブジェクトに対してコンポーネントを配置するほうが良い。親のcreateDialogAreaメソッドの中では,クライアント領域の上下左右に余白が作られ,フォントの設定も施されたCompositeオブジェクトを返却してくれる。上記のコードでは,Textコンポーネントを配置している。

これで基本的には「タイトルバーに文字列が表示され,大きさが300x200のテキストエリアを持つダイアログ」が表示できるようになった。

  Shell shell = ...;
  MyDialog dialog = new MyDialog(shell);
  dialog.open();

というコードを実行することで,以下のようなダイアログが表示される。

my-dialog.gif

JFaceのDialogクラスでは,何もしなくても[OK]ボタンと[Cancel]ボタンを配置してくれる。そしてopenメソッドの戻り値として,何のボタンが押されたかが返却されるので,

  int ret = dialog.open();
  if (ret == IDialogConstants.OK_ID) {
    // [OK]ボタン押下
  } else if (ret == IDialogConstants.CANCEL_ID) {
    // [Cancel]ボタン押下
  }

という判断ができる。ちなみに,ウィンドウの[閉じる]ボタン押下時は,IDialogConstants.CANCEL_IDが返却される。

| | コメント (0) | トラックバック (0)

2004.07.03

ワークベンチ・ウィンドウの表示・消去時の処理

「最初のリッチクライアント(1)(2)(3)(4)」シリーズで紹介したリッチクライアント・アプリケーションは,ホントに簡素なものだった。ウィンドウの大きさも不定だし,タイトルバーにも何も表示されていない。

リッチクライアントの場合,WorkbenchAdvisorクラス(のサブクラス)にてワークベンチ・ウィンドウへの設定を行う。「最初のリッチクライアント(2)」で作成したSmileWorkbenchAdvisorクラスを例として取り上げよう。

  public class SmileWorkbenchAdvisor extends WorkbenchAdvisor {
    ...
    public void preWindowOpen(IWorkbenchWindowConfigurer configurer) {
      super.preWindowOpen(configurer);
      configurer.setTitle("Smile application");
      configurer.setInitialSize(new Point(400, 300));
      configurer.setShowCoolBar(false);
      configurer.setShowStatusLine(false);
    }
  }

最初のリッチクライアント(2)」の時のコードに加えて,preWindowOpenメソッドをオーバーライドしている。preWindowOpenメソッドは,ワークベンチ・ウィンドウが開かれる直前にEclipseランタイムから呼び出されるコールバックメソッドである。preWindowOpenメソッドに引数として渡されるIWorkbenchWindowConfigurerオブジェクトの各メソッドを呼び出すことによって,ワークベンチ・ウィンドウに対して設定を行うことができる。

上記のコードでは,setTitleメソッドによりワークベンチ・ウィンドウのタイトルバーに文字列をセットしている。また,setInitialSizeメソッドにPointオブジェクトを渡すことで,ワークベンチ・ウィンドウの大きさを指定している。残りのsetShowCoolBarメソッドおよびsetShowStatusLineメソッドにfalseを渡すことで,名前の通りクールバー領域およびステータス表示領域をワークベンチ・ウィンドウから消去している。

これにより,アプリケーションを起動すると,以下のようなワークベンチ・ウィンドウが表示される。

rcp-wbw1.gif

最初のリッチクライアント(3)」の場合のワークベンチ・ウィンドウと比べると,クライアント領域内の上下の余白がなくなっているのがわかるだろう。

WorkbenchAdvisorクラスでは,ワークベンチ・ウィンドウが閉じられるときの処理もちゃんと考慮されている。ワークベンチ・ウィンドウ(正確にはワークベンチ・ウィンドウのShellオブジェクト)が閉じられるときには,preWindowShellCloseメソッドがコールバックされる

  public boolean preWindowShellClose(IWorkbenchWindowConfigurer configurer) {
    Shell shell = configurer.getWindow().getShell();
    return MessageDialog.openConfirm(shell, "Confirm", "Are you sure?");
  }

preWindowShellCloseメソッドの戻り値にfalseを渡すことによって,ワークベンチ・ウィンドウのクローズを拒否することができる。上記のコードでは,ワークベンチ・ウィンドウが閉じられようとした際に確認ダイアログを表示し,[Cancel]ボタンが押下された場合はワークベンチ・ウィンドウを閉じないようにしている。

rcp-wbw2.gif

ワークベンチ・ウィンドウが開かれた直後にはpostWindowOpenメソッドが呼び出されるので,この中でコンポーネントにフォーカスを当てるなどの処理を行うことができる。

| | コメント (0) | トラックバック (0)

最初のリッチクライアント(4) - 単独で実行

前回「デバッガで実行」で実行したリッチクライアント,一刻も早く単独で動かしたいところだろう。リッチクライアントはIDEの拡張機能ではなく,単独で動作するGUI付きのアプリケーションなので,最終的にはRun-time Workbenchで実行していても意味がない。今回は,作成したリッチクライアントをEclipse-IDEから切り離し,単独で動作させるための方法を紹介する。

プラグインの開発後,いろんな人に使ってもらうために,プラグインをエクスポートするだろう。リッチクライアントいえどプラグインに代わりはないので,まずは前回までに作成したyoichiro.rcp.smileプラグインをエクスポートする。Package Explorerビューのyoichiro.rcp.smileプロジェクトで右クリックを行い,表示されたコンテキストメニューの[Export...]を選択する。

表示されたExportダイアログでは,[Select an export destination]欄の中から[Deployable plug-ins and fragments]を選択し,[Next]ボタンを押下する。そして次のページでは,[Available Plug-ins and Fragments]欄で[yoichiro.rcp.smile]にチェックが入っていることを確認する。また,[Export Options]内の[Deploy as]は[a directory structure]を選択し,[Destination]の[Directory]に適当なディレクトリを入力する(例えば「C:\SmileApplication」)。

rcp-run1.gif

ウィザードの最後に[Finish]ボタンを押せば,指定したディレクトリにyoichiro.rcp.smileプラグインがエクスポートされる。指定したディレクトリに移動すると,pluginsディレクトリ内にyoichiro.rcp.smile_1.0.0プラグインディレクトリが存在し,その中にplugin.xml,smile.jarファイルが生成されているのが確認できる。

rcp-run2.gif

エクスポートは完了したが,それだけで動かせるほど世の中甘くない。いくつかファイルをEclipseからコピーする必要がある。

まずはEclipseをインストールしたディレクトリにあるstartup.jarを,先ほどエクスポートしたディレクトリにコピーする。次に,実行に必要な依存プラグインを,エクスポートしたディレクトリにあるpluginsディレクトリ内にコピーする。ここで「依存プラグインって,どれだよ!?」と思うのは当然。「プラグイン・マニフェストの作成」で記載した2つの依存プラグインだけであればそれらのみをコピーすればよいのだが,実は他にもいくつか必要なプラグインが存在する。

実行に必要なプラグインがどれなのかを調べるにはどうすればよいか,実はその答えは前回の「デバッガで実行」で既に示している。デバッガで実行する際に,Debugダイアログ内の[Plug-ins]タブにおいて,一旦全プラグインのチェックをはずし,再度依存しているプラグインのみにチェックを入れるための方法を示した。そこでチェックが自動的に入ったプラグインについて,startup.jarファイルと同様に,Eclipseをインストールしたディレクトリからコピーする。

しかし,上記の方法だけで発見した依存プラグインをコピーしただけでは,実行に失敗してしまう。Eclipseランタイムがプラグインを発見できないのが理由である。これを解決するためには,org.eclipse.update.configuratorプラグインもコピーする必要がある。

依存プラグインのコピー後,エクスポートしたディレクトリ内はこんな構造になっているはずである。

rcp-run3.gif

以上でファイルが揃ったので,実行できるようになる。コマンドプロンプトでエクスポートしたディレクトリに移動し,以下のコマンドを実行してほしい。

javaw.exe -cp startup.jar org.eclipse.core.launcher.Main -application yoichiro.rcp.smile.SmileApplication

前回と同じように空のウィンドウが表示されれば,単独実行は成功である。

もちろん,ユーザにコマンドプロンプトで起動させるわけにはいかないので,通常はバッチファイルやショートカットを作成しておくことが必要になるだろう。

| | コメント (0) | トラックバック (0)

2004.07.02

最初のリッチクライアント(3) - デバッガで実行

プラグイン・マニフェストの作成」「クラスの作成」が完了したところで,Eclipseのデバッガを使えば実行を行うことができる。今回は,早速作成したリッチクライアントをデバッガで実行する方法を紹介する。

通常のプラグイン開発と同じように,Run-time Workbenchを使って実行を行う。ただし,Eclipse-SDKに含まれるさまざまなプラグインを読み込まないようにしなければならないなど,いくつかの設定変更を行う必要がある。

まず,[Run]-[Debug...]メニューを選択し,Debugダイアログを表示させる。そして左の[Configurations]内のRun-time Workbenchを選択し,[New]ボタンを押下する。

このままでは普通にワークベンチが起動してしまうので,作成したアプリケーションが実行されるように設定しなければならない。これを行うのが[Arguments]タブ内の[Program to Run]の部分である。この部分の[Run an application]にチェックを入れ,右のコンボボックスから[yoichiro.rcp.smile.SmileApplication]を選択する。これにより,SmileApplicationクラスのインスタンスが生成され,runメソッドが呼び出されるようになる。

rcp-debug1.gif

次に,[Plug-ins]タブを選択する。ここでは,実行に必要な最低限のプラグインを選択する。まず,[Choose plug-ins and fragments to launch from the list]にチェックを入れる。すると,プラグインのリストが表示される。ここで[Deselect All]ボタンを押下し,全プラグインのチェックを一旦はずす。次に,[yoichiro.rcp.smile]プラグインにチェックを入れる。最後に[Add Required Plug-ins]ボタンを押下すると,実行に必要なプラグインが自動的に検出され,チェックが入る。

rcp-debug2.gif

以上で設定は終了。[Name]に適当に名称を入れ,[Debug]ボタンを押下する。以下のようなウィンドウが開かれれば,成功である。

rcp-debug3.gif

これが最初のリッチクライアントである。ウィンドウ内に描画されている線をEclipse-IDEのウィンドウと見比べてみると,確かにEclipseのワークベンチ・ウィンドウっぽいことがわかるだろう。[閉じる]ボタンを押せば,ちゃんと(?)終了することができる。

| | コメント (0) | トラックバック (0)

2004.07.01

最初のリッチクライアント(2) - クラスの作成

前回はリッチクライアントの作成の第1歩として,「プラグイン・マニフェストの作成」の方法を紹介した。もちろんプラグイン・マニフェストだけではなく,いくつかクラスを作成することも必要となる。今回は,最低限必要となるクラスの作成方法について紹介する。

リッチクライアントを作成するために最低限必要なクラスは,以下の3つである。

  (1) IPlatformRunnableインタフェースの実装クラス
  (2) WorkbenchAdvisor抽象クラスのサブクラス
  (3) IPerspectiveFactoryインタフェースの実装クラス

IPlatformRunnableインタフェースの実装クラスは,アプリケーションのエントリポイントとなるクラスである。つまり,リッチクライアントの起動は,IPlatformRunnableインタフェースの実装クラスのインスタンス生成&runメソッド呼び出しから開始される。

WorkbenchAdvisor抽象クラスのサブクラスは,リッチクライアントの土台となるワークベンチへの各種設定を行うためのクラスである。例えば,デフォルトのパースペクティブを決定するのはWorkbenchAdvisorオブジェクトである。また,アプリケーションのライフサイクルを管理する役目も持つ。つまり,アプリケーションの動作中のさまざまなタイミングで,WorkbenchAdvisorオブジェクトの各種メソッドがコールバックされる。

前回「最低1つのパースペクティブを持つ」と解説した。その解説どおり,パースペクティブを準備するためにIPerspectiveFactoryインタフェースの実装クラスが必要となる

では順番にクラスを作成していく。まずは(1)から。

  public class SmileApplication implements IPlatformRunnable {
    public Object run(Object args) throws Exception {
      WorkbenchAdvisor advisor = new SmileWorkbenchAdvisor();
      Display display = PlatformUI.createDisplay();
      try {
        int ret = PlatformUI.createAndRunWorkbench(display, advisor);
        if (ret == PlatformUI.RETURN_RESTART) {
          return IPlatformRunnable.EXIT_RESTART;
        } else {
          return IPlatformRunnable.EXIT_OK;
        }
      } finally {
        display.dispose();
      }
    }
  }

IPlatformRunnableインタフェースで規定されているrunメソッドを実装する。runメソッド内では,最初にWorkbenchオブジェクトに対する設定を行うためのWorkbenchAdvisorオブジェクトのインスタンスを生成する。次に,PlatformUIクラスのcreateDisplayメソッドを使って,Displayオブジェクトを生成する。そしてこの2つのオブジェクトを使ってPlatformUIクラスのcreateAndRunWorkbenchメソッドを呼び出し,ワークベンチを開始する

ワークベンチが何らかの理由で終了されるまで,createAndRunWorkbenchメソッドはブロックされる。ワークベンチ終了後,createAndRunWorkbenchメソッドは,以下のいずれかの値を返してくる

  PlatformUI.RETURN_OK - 通常終了
  PlatformUI.RETURN_RESTART - 再起動要求による終了
  PlatformUI.RETURN_UNSTARTABLE - ワークベンチ開始失敗
  PlatformUI.RETURN_EMERGENCY_CLOSE - 異常終了

runメソッドの戻り値は,IPlatformRunnableインタフェースに定義された定数(EXIT_OK,EXIT_RESTART,EXIT_RELAUNCH)のどれかである。上記のコードでは,createAndRunWorkbenchメソッドの戻り値がPlatformUI.RETURN_RESTARTだった場合はIPlatformRunnable.EXIT_RESTARTを,そうでない場合はIPlatformRunnable.EXIT_OKをrunメソッドの戻り値として返却している。

ワークベンチが終了したからといってDisplayオブジェクトが破棄されるわけではないので,必ずDisplayオブジェクトのdisposeメソッドを後始末として呼び出すようにする。

次に,(2)のWorkbenchAdvisorサブクラス。

  public class SmileWorkbenchAdvisor extends WorkbenchAdvisor {
    public String getInitialWindowPerspectiveId() {
      return "yoichiro.rcp.smile.SmilePerspective";
    }
  }

WorkbenchAdvisorクラスのサブクラスでは,最低限getInitialWindowPerspectiveIdメソッドを実装することが求められる。getInitialWindowPerspectiveIdメソッドは,ワークベンチに必要となるパースペクティブのIDの文字列を返却する

最後に(3)のIPerspectiveFactoryインタフェースの実装クラスを以下に示す。

  public class SmilePerspective implements IPerspectiveFactory {
    public void createInitialLayout(IPageLayout layout) {
    }
  }

ホントはcreateInitialLayoutメソッド内でビューやエディタなどを組み立てる必要があるが,今回は最低限のアプリケーションなので,何も行わない。

以上でクラスの作成は終了。これによるアプリケーションは単にウィンドウが開くだけなのだが,思ったよりも簡単だと思われるのではないだろうか。次回は,このリッチクライアント・アプリケーションの実行方法を紹介する予定。

| | コメント (0) | トラックバック (0)

最初のリッチクライアント(1) - プラグイン・マニフェストの作成

Eclipse3.0が2004年6月30日に正式リリースされた。この3.0で非常に重要な点は,リッチクライアントのプラットフォームとして3.0が仕立て上げられたということである。Webアプリケーションからリッチクライアントへと時代が流れている今日,Eclipseはリッチクライアントを開発,運用する上で非常に優位な選択肢になったということができる。今回は,成長したEclipse3.0で,簡単なリッチクライアントを作成する方法を紹介する。もちろんEclipse3.0が必要なので,Eclipse2.1系の方はバージョンアップが必要。

早速始めよう。リッチクライアントといえど,要は今までのプラグイン開発と何ら変わらない。まずはPlug-in Projectの新規作成ウィザードを使って,プラグインの雛形を作成する。ほぼデフォルトの設定でOKなのだが,ウィザードの2枚目にあるPlug-in Classの作成は行わないようにする(理由は後述)。ここでは,

  [1枚目]
    Project name: yoichiro.rcp.smile
  [2枚目]
    Generate the Java class ... plug-in's life cycle: OFF

として[Finish]ボタンを押下し,プラグインの雛形を作成する。

作成されたプラグイン・マニフェストを見てみると,2行目に<?eclipse version="3.0"?>と記載されているあたりに「進化したんだなぁ」と実感することだろう。3行目以降は,今までどおりの見慣れた記述が並んでいるはず。これに対して,リッチクライアント開発に必要な記述を行っていく。

まずは必要最低限の依存プラグインとして,org.eclipse.core.runtimeとorg.eclipse.uiをrequires要素を使って記述する

  <plugin ...>
    ...
    <requires>
      <import plugin="org.eclipse.core.runtime"/>
      <import plugin="org.eclipse.ui"/>
    </requires>
  </plugin>

次に,リッチクライアントとして作成するアプリケーションの定義を行う。アプリケーションの定義は,org.eclipse.core.runtime.applications拡張ポイントを使って記述する

  <extension
      point="org.eclipse.core.runtime.applications"
      id="SmileApplication">
    <application>
      <run class="yoichiro.rcp.smile.SmileApplication"/>
    </application>
  </extension>

id属性を使って,アプリケーションの識別子を記述する。実際のアプリケーションの識別子は,プラグインIDが先頭に付与された形になるので,yoichiro.rcp.smile.SmileApplicationが正式なアプリケーションの識別子となる。org.eclipse.core.runtime.applications拡張ポイントでは,子要素としてapplication要素を必要とする。application要素の子要素にrun要素を記述し,そのclass属性にアプリケーションのエントリポイントとなるクラスの名前を記述する。ここで記述するクラスは,IPlatformRunnableインタフェースの実装クラスである。

Eclipseのリッチクライアント・アプリケーションは,最低1つのパースペクティブを持つことになるので,パースペクティブの定義もプラグイン・マニフェストに必要となる。org.eclipse.ui.perspectives拡張ポイントを使って,パースペクティブの定義を以下のように記述する

  <extension
      point="org.eclipse.ui.perspectives">
    <perspective
        name="Smile perspective"
        class="yoichiro.rcp.smile.SmilePerspective"
        id="yoichiro.rcp.smile.SmilePerspective">
    </perspective>
  </extension>

perspective要素のname,class,idの各属性にそれぞれ名前,IPerspectiveFactoryインタフェース実装クラス名,そしてパースペクティブのIDを記述する

プラグイン・マニフェストに対するリッチクライアントのための必要最低限の記述は以上のとおりとなる。アプリケーションとパースペクティブの関連などは,Javaソースコード中に記載される。プラグイン・マニフェスト上では,リッチクライアントは単なるプラグインに過ぎないことがわかるだろう。

次回は,リッチクライアントの作成で最低限作成しなければならないクラスの紹介を行う予定。

| | コメント (1) | トラックバック (0)

« 2004年6月 | トップページ | 2004年8月 »