2010年5月18日火曜日

プラグインを作ってみよう:テキスト形式での出力

第2回です。もうちょっと更新頻度上げます。はい。

さて、前回は単純なイベントハンドリングのみでしたが、実用的なプラグインを作るために
  • プラグインへのJavaコードの埋め込み
を見ていきたいと思います。
BEITELのプラグインとJavaコードの連携方法を知ることで、既存のJavaライブラリを活用することが可能になります。


例として、BEITELのデータをテキストファイルに出力する/テキストファイルから読み込むプラグインを考えてみます。
特に今回は、出力を考えることにしましょう。入力に関しては次の回で取り上げます。
(BEITELにははじめからテキスト出力機能が用意されていますが、ほぼ今回のチュートリアルと同じ方法で実現されています。(BEITELのディレクトリ)/ext/text.jsですので、必要に応じて参照してみてください。)

テキストの出力機能は、具体的には、こんなイメージで実装することにしましょう。



以下のようなユーザインタフェースを実装します。
  1. ファイルメニューもしくは右クリックメニューから[テキスト形式で出力]を選択
  2. 保存先ファイルの選択ダイアログが開くのでここから保存先ファイルを選択
  3. 保存処理を実行



では、プラグインを作成していきましょう。
  1. 前回と同様、メニューに対する項目の追加処理をJavaScriptで実装します。
    今回は右クリックメニューだけでなく、ファイルメニューにも項目を追加します。項目選択時の具体的な処理は2.以降で記述していきます。
    なお、文字コードはUTF-8で保存してください。
    window.popup.appendChild(window.popup.createSeparator());
    var comp = window.popup.createMenuItem("テキスト形式で出力", function(ev){
    myExportText(ev.currentTarget);
    });
    window.popup.appendChild(comp);

    window.menu.file.appendChild(window.menu.createSeparator());
    comp = window.menu.createMenuItem("テキスト形式で出力", function(ev){
    myExportText(document.rootNode);
    });
    window.menu.file.appendChild(comp);

    // 出力用関数
    function myExportText(node)
    {
    // テキストへの出力処理
    }

    ここでは、myExportTextという関数を用意し、右クリックメニュー(window.popup)とファイルメニュー(window.menu.file)に区切り線と項目を追加しています。
    使用可能なAPIに関する詳細は、ヘルプを参照してください。

  2. myExportText関数にファイルダイアログを開く処理を実装します。
    JavaScriptからJavaのクラスを呼び出すことができます。
    java.*, javax.*パッケージに対しては (パッケージ名).(クラス名) でインスタンス化、呼び出しが可能です。ここでは、保存ダイアログを開きたいので、javax.swing.JFileChooserを使用し、showSaveDialogメソッドを呼び出すことにします。
    var dlg = new javax.swing.JFileChooser();
    var result = dlg.showSaveDialog(window.swingFrame);
    if(result != javax.swing.JFileChooser.APPROVE_OPTION) {
    return;
    }
    var path = dlg.selectedFile.absolutePath;

    ここでは、現在のフレーム(window.swingFrame)を親として、JFileChooser.showSaveDialogを呼び出しています。結果がキャンセル(APPROVE_OPTION以外)ならば処理を中断し、保存の場合は選択されたファイルの絶対パスを取得し、変数pathに格納しています。
    使用可能なクラスなどは、Java2 SDK 1.6のAPIドキュメントを参照してください。

  3. テキスト出力処理をJavaで実装します。

    1. クラスパスにBEITELのクラスライブラリを追加します。
      今回は選択されたTreeNodeオブジェクトをJavaコードに取り込む必要があるため、beitel.jarをクラスパスに追加する必要があります。
      (BEITELのディレクトリ)/lib/beitel.jarをクラスパスに追加してください。

    2. Javaコードを記述します。
      JavaScriptからjava.io.PrintStreamなどのインスタンスを作成し、出力する処理を記述してもよいのですが、ここではサンプルとしてJavaで記述してみましょう。
      jp.carabiner.beitel.sample.TextFormatUtilsクラスを作成し、ここに静的メソッドとしてテキスト保存メソッドexportText(TreeNode, path)を実装することにします。
      package jp.carabiner.beitel.sample;

      import java.io.FileOutputStream;
      import java.io.IOException;
      import java.io.PrintStream;

      import jp.carabiner.treeeditor.TreeNode;
      import jp.carabiner.treeeditor.js.model.JSTreeNode;

      /**
      * テキスト形式を処理するユーティリティです。
      */
      public class TextFormatUtils {

      /**
      * ファイルに対して文字列としてエキスポートします。
      *
      * @param node
      * ノード。nullは不可。
      * @param filepath
      * ファイルパス。nullは不可。
      * @throws IOException
      * 入出力時のエラー。
      */
      public static void exportText(JSTreeNode node, String filepath)
      throws IOException {
      if (node == null || filepath == null) {
      throw new IllegalArgumentException();
      }
      PrintStream ps = new PrintStream(new FileOutputStream(filepath));
      writeNode(node.getCore(), ps, 0);
      ps.close();
      }

      /**
      * ノードを書き出します。
      *
      * @param node
      * ノード。nullは不可。
      * @param ps
      * 出力先。nullは不可。
      * @param level
      * レベル。
      */
      private static void writeNode(TreeNode node, PrintStream ps, int level) {
      if (node == null || ps == null) {
      throw new IllegalArgumentException();
      }
      for (int i = 0; i < level; i++) {
      ps.print("\t");
      }
      ps.println(node.getText());
      for (int c = 0; c < node.getChildrenCount(); c++) {
      TreeNode cnode = node.getChild(c);
      writeNode(cnode, ps, level + 1);
      }
      }
      }

      JSTreeNodeはJavaScriptのTreeNodeオブジェクトに対応するJavaクラスであり、getCore()メソッドでデータを保持しているJavaオブジェクトを取得することができます。
      このオブジェクトについては特にリファレンスはありませんが、基本的な構造はJavaScriptオブジェクトと同様です。Eclipseのコード補完機能などを利用して、どのようなメソッドがあるか確認してみてください。

    3. コンパイルし、jarファイルにまとめます。

    4. ext以下にjarファイルを配置します。
      ext直下に配置する必要はなく、サブディレクトリを設けることもできます。

  4. myExportText関数に作成したメソッドへの呼び出し処理を記述します。
    自分で作成したJavaクラスを参照する場合はPackages.(パッケージ名).(クラス名)で参照します。
    Packages.jp.carabiner.beitel.sample.TextFormatUtils.exportText(node, path);


  5. プラグインをBEITELにインポートします。(beitelのフォルダ)/extの直下に作成したJavaScriptコードを配置します。

  6. BEITELを起動します。jarの更新をおこなった場合は、BEITELの全ウィンドウを閉じ、BEITELを再起動してください。



これで、ファイルメニューと右クリックメニューに[テキスト形式で出力]項目があらわれれば成功です。
クリックし、適当なテキストファイルを指定して保存してください。
レベルごとにタブでインデントされたテキストファイルが出力されれば成功です。


次回は、この形式のテキストファイルを読み込む処理を考えてみたいと思います。
それぞれの処理の詳細についてはヘルプ、APIドキュメントなどを参照してください。

1 件のコメント:

  1. ライフワークだね。
    ブログのオプションとしての高級エディタとして、
    AJAX, DHTMLの組み合わせで、WEBエディタになれば
    面白いんじゃない。
    GAE上で実現してみるとかね。

    返信削除