ラベル プラグイン の投稿を表示しています。 すべての投稿を表示
ラベル プラグイン の投稿を表示しています。 すべての投稿を表示

2010年5月20日木曜日

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

はい。第3回です。

今回は、前回作成したテキスト書き出しに対応して、読み出し処理を作成することにします。
前回の復習をしつつ、書き出しと同様にJavaScriptコードとJavaコードを記述していきましょう。


テキストの入力機能は、以下のようなユーザインタフェースで実現することにしましょう。
(前回のインタフェースと基本的な考え方は同じなので、手書きの図は省略します。)
  1. ファイルメニューもしくは右クリックメニューから[テキスト形式で入力]を選択
  2. オープンするファイルの選択ダイアログが開くのでここから読み込み対象ファイルを選択
  3. 読み込み処理を実行 ... ファイルメニューから実行された場合はドキュメント全体を置き換え、右クリックメニューから実行された場合はそのノード以下に追加

ということにしてみましょう。
なお、ここでは、簡単化のため、現在開いているファイルが保存されていない場合の「閉じてよろしいですか」の問い合わせなどは行わないこととします。また、ノードあたりのテキストには改行が含まれていないものとみなし、テキストファイルでの1行=1ノードとなっているものだと考えます。


では、プラグインを作成していきましょう。
  1. 前回と同様、メニューに対する項目の追加処理をJavaScriptで実装します。
    実装する内容は前回とほぼ同様です。一部、項目名と関数名が変わっています。
    BEITELは全プラグインのスクリプトを同じJavaScriptのコンテキストで実行しますので、関数名などはプラグイン間で重ならないように注意してください。
    いつも通り、文字コードはUTF-8で保存してください。
    window.popup.appendChild(window.popup.createSeparator());
    var comp = window.popup.createMenuItem("テキスト形式で入力", function(ev){
    myImportText(ev.currentTarget);
    });
    window.popup.appendChild(comp);

    window.menu.file.appendChild(window.menu.createSeparator());
    comp = window.menu.createMenuItem("テキスト形式で入力", function(ev){
    myImportText(null);
    });
    window.menu.file.appendChild(comp);

    // 入力用関数
    function myImportText(targetNode)
    {
    // テキストの入力処理
    }


  2. myImportText関数にファイルダイアログを開く処理を実装します。
    これも前回と同様です。ここでは、開くダイアログを開きたいので、javax.swing.JFileChooserを使用し、showOpenDialogメソッドを呼び出すことにします。
    var dlg = new javax.swing.JFileChooser();
    var result = dlg.showOpenDialog(window.swingFrame);
    if(result != javax.swing.JFileChooser.APPROVE_OPTION) {
    return;
    }
    var path = dlg.selectedFile.absolutePath;


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

    1. クラスパスにBEITELのクラスライブラリを追加します。
      (BEITELのディレクトリ)/lib/beitel.jarをクラスパスに追加してください。

    2. Javaコードを記述します。
      前回作成したjp.carabiner.beitel.sample.TextFormatUtilsクラスに対して、テキスト読み込みメソッドTreeNode importText(Document, path)を実装することにします。
      package jp.carabiner.beitel.sample;

      import java.io.BufferedReader;
      import java.io.FileInputStream;
      import java.io.FileOutputStream;
      import java.io.IOException;
      import java.io.InputStreamReader;
      import java.io.PrintStream;

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

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

      // ... 前回記述した保存処理 ...

      /**
      * テキストをインポートします。
      *
      * @param doc
      * ドキュメント。nullは不可。
      * @param filepath
      * ファイルパス。nullは不可。
      * @return テキスト。
      * @throws IOException
      * 入出力時のエラー。
      */
      public static JSTreeNode importText(JSDocument doc, String filepath)
      throws IOException {
      if (doc == null || filepath == null) {
      throw new IllegalArgumentException();
      }
      BufferedReader br = null;
      try {
      br = new BufferedReader(new InputStreamReader(new FileInputStream(
      filepath)));
      JSTreeNode rootNode = null;
      JSTreeNode node = null;
      int prevLevel = -1;
      while (true) {
      String line = br.readLine();
      if (line == null) {
      break;
      }
      int level = getLevel(line);
      line = line.trim();

      JSTreeNode newNode = doc.createTreeNode(line);
      if (level == -1) {
      continue;
      } else if (level == 0) {
      rootNode = newNode;
      } else if (prevLevel < level) {
      node.appendChild(newNode);
      } else {
      int delta = prevLevel - level;
      for (int i = 0; i < delta + 1; i++) {
      node = node.getParentNode();
      }
      node.appendChild(newNode);
      }
      node = newNode;
      prevLevel = level;
      }
      return rootNode;
      } finally {
      if (br != null) {
      try {
      br.close();
      } catch (IOException ioe) {
      ;
      }
      br = null;
      }
      }
      }

      /**
      * レベルを取得します。
      *
      * @param text
      * 文字列。nullは不可。
      * @return レベル。
      */
      private static int getLevel(String text) {
      if (text == null) {
      throw new IllegalArgumentException();
      }
      for (int i = 0; i < text.length(); i++) {
      int ch = text.charAt(i);
      if (ch != '\t') {
      return i;
      }
      }
      return -1;
      }

      }

      JavaScriptでのDocumentに対応するクラスとしてJSDocument, TreeNodeに対応するクラスとしてJSTreeNodeを参照しています。これらのオブジェクトの変換はBEITELのJavaScript実行環境によって自動的におこなわれます。

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

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

  4. myImportText関数に作成したメソッドへの呼び出し処理を記述します。
    自分で作成したJavaクラスを参照する場合はPackages.(パッケージ名).(クラス名)で参照します。
    var node = Packages.jp.carabiner.beitel.sample.TextFormatUtils.importText(document, path);
    if(targetNode != null) {
    targetNode.appendChild(node);
    }else{
    document.set(path, node);
    }


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

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



これで、ファイルメニューと右クリックメニューに[テキスト形式で入力]項目があらわれれば成功です。
クリックし、タブでインデントされた適当なテキストファイルを指定して入力してください。
ドキュメント全体が置き換え、もしくは選択したノードにインポートされれば成功です。


それぞれの処理の詳細についてはヘルプ、APIドキュメントなどを参照してください。

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ドキュメントなどを参照してください。

2010年4月27日火曜日

プラグイン作成をはじめてみよう

ここでは、BEITELの活用方法と言うことで、BEITELプラグインの作成方法について
不定期連載していきたいと思います。

実際に中の人が作って利用しているプラグインなども例に説明していきながら、
プラグインを使ったBEITELの強化・活用方法をお見せできれば・・・と考えています。
ぜひお付き合いください。



さて、今回は第一弾として、非常に簡単なプラグインを作り、
BEITELで動かしてみたいと思います。
BEITELでのプラグインの作成は非常に簡単です。
簡単なJavaScriptの知識さえあれば、プラグインを作成、動作させることができます。

今回は、手始めということで、右クリックメニューへのメニュー項目の追加、
メッセージボックスの表示を試してみましょう。
具体的には、こんなイメージです。(作業前のメモそのままですが。)


... 右クリックメニューに区切り線[テスト!]という項目を追加する。


... [テスト!]をクリックすると、選択されているノードの文字列がメッセージボックスで表示される。


では、プラグインを作っていきましょう。BEITELをダウンロードし、インストールを
すませたら、下の手順にしたがってプラグインを記述してみてください。

  1. プラグインのソースコードを記述します。ここではtest.jsとしましょう。
    特に日本語を含める場合、文字エンコーディングはUTF-8で保存してください。

    window.popup.appendChild(window.popup.createSeparator());

    var comp = window.popup.createMenuItem("テスト!", function(ev){
    alert("クリックされました:\n[" + ev.currentTarget.text + "]");
    });
    window.popup.appendChild(comp);

    見ての通り、シンプルなJavaScriptのコードです。

    まず、window.popupオブジェクトに対してwindow.popup.createSeparator()で生成した区切り線を追加し、
    次に、createMenuItem(...)で生成したメニュー項目を追加しています。
    メニュー項目生成の際に、メニュー名、クリック時の処理を指定しています。

    BEITELは、ウィンドウを開く際にこのコードを実行し、その内容に応じてメニューへの項目追加を行います。
    使用可能なAPIに関する詳細は、ヘルプを参照してください。

  2. プラグインをBEITELにインポートします。(beitelのフォルダ)/extの直下にtest.jsをコピーします。

  3. BEITELを起動します。もしすでにBEITELを起動しているのなら、[ファイル]メニューの[ウィンドウの再オープン]を実行してみてください。


これで、以下のように右クリックメニューに[テスト!]項目があらわれれば成功です。



クリックしてみると、こんなメッセージボックスが表示されます。





今回はメッセージボックスを表示するだけの単純な例でしたが、今後、HTML形式で出力する、テキスト形式で出力するなどの具体例を説明していきたいと思います。

BEITELはアウトラインエディタですが、プラグイン機構を利用することで、
アウトライン文書から別の形式のドキュメントを生成したり、
他の情報ソースをアウトライン文書として取り込んだり、
アウトライン文書に対して任意の変換を加えたりすることができるようになります。
ぜひ活用してみてください。