ancestorsを作ってみる

rubyも少しやってた身としてはancestorsがなにげに便利。
ということで、Scala版を作った。

class Any2Ancestors(c:Class[_]) {
  def ancestors() = {
    def ans(o:Class[_], l:List[String]):List[String] = {
      if (o.getSuperclass == null)
        l
      else
        ans(o.getSuperclass, l:::o.getName::Nil)
    }
    ans(c,Nil)
  }
}
implicit def any2Ancestors(any:Any):Any2Ancestors = new Any2Ancestors(any.getClass)

暗黙の変換便利すぎwww
なんか、もっときれいになりそうな気もするけど。

scala> List(1,2,3).ancestors
res9: List[String] = List(scala.collection.immutable.$colon$colon, scala.collection.immutable.List)

デシリアライズくらい簡単に出来るかと思ったらはまった

昨日の最小コードがあれば、後は簡単と思ってたらそうでもなかった。

はまったポイント

昨日のコードで下のように書いたけど

@Override
protected IDocument createDocument(Object element)
        throws CoreException {
    // このメソッドで返したIDocumentの値が表示される
    IDocument document = super.createDocument(element);
    
    if (document != null) {
        document.set("Hello Editor");
    }
    return document;
}

IDocument#get()で取れる文字列を元に出シリアライズすればいいと思って、InputStreamやら、OutputStreamやらいじっててどうしても出来ないと思ったら、IDocument#get()の時点ですでにエンコードされてるから、正しいバイナリの値が取れてなかったみたい。

こんな感じで書いてた(ダメな例)

protected IDocument createDocument(Object element)
        throws CoreException {
    // このメソッドで返したIDocumentの値が表示される
    IDocument document = super.createDocument(element);
    
    ByteArrayInputStream bais = new ByteArrayInputStream(document.get().getBytes());
    
    try {
        ObjectInputStream ois = new ObjectInputStream(bais);
        
        // oisからオブジェクト取り出したりしてdocumentに書き込む
        Object obj = ois.readObject();
        
        // objから文字列を作ってdocumentに書き込む(省略)
        String text = "";
        
        document.set(text);
        
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
    
    return document;
}

するとこんな感じの例外が発生する

java.io.StreamCorruptedException: invalid stream header: AC3F0573
	at java.io.ObjectInputStream.readStreamHeader(Unknown Source)
	at java.io.ObjectInputStream.<init>(Unknown Source)
	at DeserializeEditor$1.createDocument(DeserializeEditor.java:36)
...

今考えればかなり初歩的なミス・・・

正しくは

正しいかは知らないけど、こっちは上手く動いているっぽい

protected IDocument createDocument(Object element)
        throws CoreException {
    IPathEditorInput input = (IPathEditorInput)element;
    
    File file = input.getPath().toFile();
    
    // 空のドキュメントを作る
    IDocument document = createEmptyDocument();
    
    ObjectInputStream ois = null;
    try {
        ois = new ObjectInputStream(new FileInputStream(file));
        
        // oisからオブジェクト取り出したりしてdocumentに書き込む
        Object obj = ois.readObject();
        
        // objから文字列を作ってdocumentに書き込む(省略)
        String text = "";
        
        document.set(text);                 
        
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } finally {
        if (ois != null) {
            try {
                ois.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    return document;
}

elementはこの場合、FileEditorInputなのでそれを使ってファイルを直接とって、ObjectInputStreamに入れちゃうって戦法ですね。
ちなみにFileEditorInputにキャストするには「org.eclipse.ui.ide」を依存関係に追加しないといけないので、今回はIPathEditorInputにキャストしてみた。
正確には型チェックとかしないとなのかもだけど、とりあえずこれでOK

テキストを加工してエディタに表示する

訳あって、シリアライズされたファイルを扱うことがあったから、何とかデシリアライズして見れないものかと思って、調べてみた。

以下、最小構成

依存関係

plugin.xml

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
   <extension point="org.eclipse.ui.editors">
      <editor
            class="DeserializeEditor"
            default="false"
            extensions="properties"
            icon="icons/sample.gif"
            id="DeserializeViewer.editor1"
            name="name">
      </editor>
   </extension>
</plugin>

ここでとりあえず大事なのはclass指定くらいかな?
extensionsは対象の拡張子。
iconはなにげに必須。

ソース

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.IVerticalRuler;
import org.eclipse.jface.text.source.projection.ProjectionSupport;
import org.eclipse.jface.text.source.projection.ProjectionViewer;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.editors.text.FileDocumentProvider;
import org.eclipse.ui.editors.text.TextEditor;


public class DeserializeEditor extends TextEditor {
    
    public DeserializeEditor() {
        super();
        
        setDocumentProvider(new FileDocumentProvider(){
            
            @Override
            protected IDocument createDocument(Object element)
                    throws CoreException {
                // このメソッドで返したIDocumentの値が表示される
                IDocument document = super.createDocument(element);
                
                if (document != null) {
                    document.set("Hello Editor");
                }
                return document;
            }
            
            @Override
            protected void doSaveDocument(IProgressMonitor monitor,
                    Object element, IDocument document, boolean overwrite)
                    throws CoreException {
                // 保存処理
            }
        });
    }

    @Override
    protected ISourceViewer createSourceViewer(Composite parent,
            IVerticalRuler ruler, int styles) {
        ISourceViewer viewer = new ProjectionViewer(parent, ruler,
                getOverviewRuler(), isOverviewRulerVisible(), styles);
    
        getSourceViewerDecorationSupport(viewer);
    
        return viewer;
    }

    @Override
    public void createPartControl(Composite parent) {
        super.createPartControl(parent);
        ProjectionViewer viewer = (ProjectionViewer) getSourceViewer();

        ProjectionSupport projectionSupport = new ProjectionSupport(viewer,
                getAnnotationAccess(), getSharedColors());
        projectionSupport.install();
    }
}

実行すると、どんなporpertiesファイルを開いても"Hello Editor"と表示される。

FileDocumentProvider#createDocument()で返すのは表示する文字列。elementに元のデータが入っている。
FileDocumentProvider#doSaveDocument()は保存時の処理。
表示内容と、生データが異なるので上手いこと保存しろってことだと思う(後で調べる)

DeserializeEditor()→コンストラクタ内でDocumentProviderをセット
DeserializeEditor#createSourceViewer()→ViewerにProjectionViewerを使うことを教えてる?(後で調べる)
DeserializeEditor#createPartControl()→よくわかんない(あとで調べる)

まとめ

英語力の無さに泣けてきた。
ざっくりとしかわからないのがつらい。

TextEditorを読み込み専用で開きたい

org.eclipse.ui.editors.text.TextEditorを継承したクラスで下のようにすればいいのか?

http://dev.eclipse.org/newslists/news.eclipse.tools/msg50392.html

protected void doSetInput(IEditorInput input) throws CoreException {
    super.doSetInput(input);
    ((IFileEditorInput)input).getFile().setReadOnly(true);
}

org.eclipse.ui.IFileEditorInputはパッケージがorg.eclipse.uiなのにorg.eclipse.ui.ideプラグインを入れないと使えない。

ちなみに、今Eclipse3.6でやってみたら、setReadOnly()はdeprecatedになっていた。

正しくはこっち

protected void doSetInput(IEditorInput input) throws CoreException {
    super.doSetInput(input);
    
    IFile file = ((IFileEditorInput) input).getFile();
    
    ResourceAttributes attributes = file.getResourceAttributes();
    attributes.setReadOnly(true);
    
    file.setResourceAttributes(attributes);
}

Mon, Oct 26

  • 23:42  @iharakenji カメラ→保存・整理→プリントまでを簡単にならないかなと。flickrがアップは簡単だけどダウンが使えなかった。  [in reply to iharakenji]
  • 23:15  1年振り位に親に息子の写真を送った。写真の管理が面倒で送れてなかったけど、あいかわらず写真をどう管理していいのか解決策が見つからない。
  • 23:11  寒い
  • 18:33  rssリーダも無料なのか。とりあえず落としとこ。 TwitBird Pro : 今日だけ無料!!全員ダウンロードして損はない!秀逸すぎるTwitterアプリ! http://bit.ly/3JcAzW
  • 00:59  特定の文字が入ってるとダメみたいだ。眠いから、また明日にしよう。 RT @as_a_rimit はてブポケットからtwitterrificへの連携がうまくいかなくなってる。再起動したけど、ダメだった。便利だったのに。
  • 00:56  はてブポケットからtwitterrificへの連携がうまくいかなくなってる。再起動したけど、ダメだった。便利だったのに。
  • 00:33  寒い。寝よう

Powered by twtr2src