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

0 件のコメント:

コメントを投稿