2013/05/25

EclipseのPluginをSWT Browserで作る

Eclipse の Plugin を作ろうと思ったのだが調べてみると敷居が高い高い。

テンプレのプロジェクトは用意されているがいきなりこんな画面が現れて ぼーぜん とすることになる。 ちなみに下部のタブは其々違う設定画面が現れる。


Plugin開発の チュートリアル も有ることは有るが目次を見ただけで気が遠くなる。
しかも、この先には膨大な javadoc が待っている。

正直諦めそうになったのだが以前、 Eclipse内のライブラリからブラウザを起動してみた事を思い出して 内部ブラウザでPluginを作れないかと考えた。

で、ググったら出て来ましたよ、本家IBMのサイトが。

ブラウザの起動方法と最低限の通信方法の説明だけですが本家が可能性として有りだと言ってます。

          ...

そして、設定画面&Javadocと格闘しつつでっち上げたのがこれです。



HTMLのソースはこれだけです。
Eclipse.* は eclipse 側から呼んで貰うためのJavaScriptです。

<html>
<head>

<script src="./jquery-1.8.2.js"></script>

<script>
var Eclipse = {};
Eclipse.setContent = function(content) {
    var data = JSON.parse(content);
    var form = document.parson;
    form.name.value = data.name;
    form.addr.value = data.addr;
    form.email.value = data.email;
};
Eclipse.getContent = function() {
    var data = {};
    var form = document.parson;
    data.name  = form.name.value  ;
    data.addr  = form.addr.value  ;
    data.email = form.email.value ;
    return JSON.stringify(data);
};
Eclipse.fireEvent = function(type) {
    window.status = type;
    window.status = null;
};

window.onload = function() {
    Eclipse.fireEvent("load");
}
window.onerror = function(err) {
    Eclipse.fireEvent("log,"+err);
}
$(function(){
    $("input").bind("change",function() {
        Eclipse.fireEvent("change");
    });
});
</script>

</head>
<body>
    <h1>Browser plugin sample</h1>

    <form name="parson">
        <table>
            <tr><td>Name:</td><td><input name="name" /></td></tr>
            <tr><td>Addr:</td><td><input name="addr" /></td></tr>
            <tr><td>E-Mail:</td><td><input name="email" /></td></tr>
        </table>
    </form>
</body>
</html>



保存した後にテキストエディタで見るとJSON形式でちゃんと保存されている事がわかります。



Plugin側で作成したソースコードは1本だけです。
継承すべき TextEditor クラスを探すのは苦労しましたがその先はすんなり行きました。

package org.kotemaru.eclipse.browserpluginsample.editors;

import 省略;

public class BrowserEditor extends TextEditor {

    private static final String ENCODING = "utf-8";

    private Browser browser;
    private boolean isDirty = false;

    public BrowserEditor() {
        super();
    }

    @Override
    public void init(IEditorSite site, IEditorInput input)
            throws PartInitException {
        setSite(site);
        setInput(input);
        setPartName(input.getName());
    }


    @Override
    public void createPartControl(Composite parent) {
        try {
            browser = new Browser(parent, SWT.NONE);
            browser.setJavascriptEnabled(true);         
            browser.addStatusTextListener(new MyStatusTextListener());

            URL aboutURL = this.getClass().getResource("/webapps/editor.html");
            URL url = FileLocator.resolve(aboutURL);
            browser.setUrl(url.toString());
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    private class MyStatusTextListener implements StatusTextListener {
        @Override
        public void changed(StatusTextEvent ev) {
            log("status="+ev.text);
            String[] params = ev.text.split(",");
            String method = params[0];
            if ("load".equals(method)) {
                onLoad(params);
            } else if ("change".equals(method)) {
                onChange(params);
            } else if ("log".equals(method)) {
                log(ev.text);
            }
        }
    }

    private void onLoad(String[] params) {
        StringBuilder sbuf = new StringBuilder();
        try {
            IFileEditorInput input = (IFileEditorInput)getEditorInput();
            InputStream in = input.getFile().getContents();
            try {
                Reader reader = new InputStreamReader(in, ENCODING);
                int n;
                char[] buff = new char[1024];
                while ((n=reader.read(buff))>=0) {
                    sbuf.append(buff,0,n);
                }
            } finally {
                in.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        String data = sbuf.toString();
        data = data.replaceAll("'", "\\'").replaceAll("\n", "\\n");

        browser.execute("Eclipse.setContent('"+data+"')");
    }

    private void onChange(String[] params) {
        setDirty(true);
    }


    @Override
    public void doSave(IProgressMonitor monitor) {
        String content = (String) browser.evaluate("return Eclipse.getContent();");
        try {
            IFile file = ((IFileEditorInput) getEditorInput()).getFile();
            file.setContents(
                new ByteArrayInputStream(content.getBytes(ENCODING)),
                true,  // keep saving, even if IFile is out of sync with the Workspace
                false, // dont keep history
                monitor); // progress monitor
            setDirty(false);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    public void setDirty(boolean b) {
        isDirty = b;
        firePropertyChange(EditorPart.PROP_DIRTY); 
    }

    @Override
    public boolean isDirty() {
        return isDirty;
    }


    @Override
    public void dispose() {
        browser.dispose();
        super.dispose();
    }

    @Override
    public void setFocus() {
    }
    @Override
    public boolean isSaveAsAllowed() {
        return false;
    }
    @Override
    public void doSaveAs() {
        // Unsupported
    }

    private void log(String msg) {
        System.out.println(msg); // TODO:ちゃんとログ。
    }

}



本格的なPluginを作るにはまだ色々必要ですが JavaScript でEclipse plugin開発ができる事が分かりました。

このサンプルのSVNリポジトリは以下にあります。


2013/05/21

Eclipse4.2のPluginのuninstallではまったのでメモ(2)

追記。

プラグインのアンインストールで残っちゃうのはEclipse-3.7でも同じだった。

Linuxの場合は ~/.eclipse/org.eclipse.platform_{バージョン番号}/plugins/ 配下にインストールされてるのでややこしい。

Eclipse plugin はバージョン番号に qualifier を付けると日付に置き換えてくれる機能があって これを使えばアンインストールしなくても更新されるって事らしい。

初期状態で付いてたのを意味が分からなかったんで削除してた orz


2013/05/19

Eclipse4.2のPluginのuninstallではまったのでメモ

Eclipse-4.2ではプラグインのアンインストールが完全に行われない。

通常の手順でアンインストールを行うと一見削除されたように見えるのだが 実際は無効にしただけで削除していない。

この状態でプラグインを再インストールすると実際のインストールは行わず有効に戻すだけとなる。

これで何が問題になるかと言うと自分でプラグイン開発をしている場合、 修正を行って再インストールをしても修正が反映されない。 開発環境で実行すると正常に動作するのでかなり混乱する。

Eclipseのプラグイン開発は初めてやったので訳が分からず1日潰れてしまった。(;_;)

解決方法のメモ:

  1. %ECLIPSE_HOME%\plugins\ から 自前のプラグイン.jar のファイルを削除。
  2. %ECLIPSE_HOME%\artifacts.xml から自前のプラグインの <artifact> タグを探して削除。
  3. eclipse -clean

で完全に削除できる。

因みに 2. をやらないと再インストールでこんな感じのエラーとなる。

An error occurred during the org.eclipse.equinox.internal.p2.engine.phases.CheckTrust
phase. session context  was:(profile=epp.package.jee, 
phase=org.eclipse.equinox.internal.p2.engine.phases.CheckTrust, operand=, action=). 
Error reading signed content. 
The file "%ECLIPSE_HOME%\plugins\自前のプラグイン.jar" does not exist

Eclipseのプラグイン開発は敷居高過ぎ。


2011/07/20

eclipseのアノテーションの設定ではまる、その2

Velocityを使う場合の別の問題が発生。
  1. Velocity は singleton で環境を持っている。
  2. eclipse の標準ビルダーはアノテーション処理の実行環境をワークスペース内で共有するらしい。
  3. Velocity は環境の再初期化ができない。
結果、
  • Velocityを使うアノテーション処理が複数プロジェクトにあると誤動作しまくり。
動いたり動かなかったりなので本当に訳わかめ。

1日潰れてしまった。
eclipse 好きになりかていたのですがまた嫌いになりました。


2011/07/19

eclipseのアノテーションの設定ではまる

Verocity でアノテーション処理をするライブラリを作ろうと したのだが eclipse の設定ではまったのでメモ。

そもそも eclipse はアノテーション処理に問題が有って処理が 失敗していても何もエラーが起こらない。 そのままコンパイルを実行してしまう。

したがってアノテーション処理にバグや設定ミスが有っても 原因がさっぱりわからない。

今回はまったのは velocity 等の外部モジュールを アノテーション処理から使う場合、 velocity.jar もファクトリーパスに入れ ておかないと実行時エラーになると言うもの。
しかもエラーがどこにも出ない!!

原因は ant から タスクを使っていろいろ実験した結果 から勘で突き止めた。

アノテーション処理を自前で作る人は少ないかも知れないが もうちょっと何とかしてほしいわ。

eclipse の issue に上げればいいのかね?

ちなみに ant で動作確認する場合の設定はこれ。

<path id="aptpath"> <!-- ここにファクトリーパスを設定 --> <fileset dir="lib"> <include name="my-apt-processor.jar" /> </fileset> </path> <target name="apt-test"> <apt srcdir="${source}" preprocessdir=".apt_generated" destdir="${classes}" debug="on" encoding="${encoding}" compile="true" factorypathref="aptpath"> </apt> </target>

追記:
Linux でコマンドラインから eclipse を起動すれば標準出力にエラーが出ることが判明。 DOS窓は未確認。


2011/06/11

Eclipse/SWTのBrowserではまった。

EclipseでGUIを作る場合、どんなのが適当かなーと 思ってたら SWT からブラウザが起動できるらしいので 試して見たがえらくはまった。

SWTから起動したブラウザはイベントをJavaで拾えるので ローカルアプリとの連係ができる。
通常のブラウザはセキュリティ上の制限が厳しくWebアプリと ローカルアプリを連係させるのは難しかったが これで簡単にできるかもしれない。

SWT の開発環境は以前はデフォルトで入っていたらしいのだが 最近の版では別途インストールが必要らしい。 しかもプラットフォーム毎に異なるバイナリが使う必要がある。

以下のURLから使っているEclipseと同じ版の「SWT Binary and Source」 を落してきてインストールする。

  • http://download.eclipse.org/eclipse/downloads/

FreeBSDの場合は ports の x11-toolkits/swt-devel からインストール でるので楽なのだがカテゴリが java/ でも develop/ でも 無いので探すのに苦労した。 しかもインストール先が /usr/local/share/java/classes/ なのですごく分かりにくい。

追記:Linux系の場合は libwebkitgtk-1.0 をインストールするのが楽。

コンパイルは ビルドパス にインストール先の swt-devel.jar を 追加するだけで通るようになる。

はまったのは実行で何も考えずに実行するとこんなエラーがでる。

org.eclipse.swt.SWTError: No more handles [Unknown Mozilla path (MOZILLA_FIVE_HOME not set)]

ググった情報を元に eclipse の起動スクリプトに設定を追加してみた。

export MOZILLA_FIVE_HOME=/usr/local/lib/firefox3 export LD_LIBRARY_PATH=$MOZILLA_FIVE_HOME:$LD_LIBRARY_PATH

しかし別のエラーが...

UnsatisfiedLinkError: no swt-mozilla-gtk-3555 or swt-mozilla-gtk in swt.library.path, java.library.path or the jar file

しかし、 swt-develでインストールされるライブラリはこれだけだ。

libswt-atk-gtk-3631.so libswt-awt-gtk-3631.so libswt-cairo-gtk-3631.so libswt-glx-gtk-3631.so libswt-gnome-gtk-3631.so libswt-gtk-3631.so libswt-pi-gtk-3631.so libswt-xulrunner-gtk-3631.so

本来なら libswt-xulrunner-gtk-3631.so が使われるべきと 思うのだがググっても良く分からない。

探し回ったらこんな所に居やがったのだが明らかに旧版。

~/eclipse/org.eclipse.platform_3.4.0_185596441/configuration/org.eclipse.osgi/bundles/129/1/.cp/libswt-mozilla-gtk-3452.so

バージョンの混乱が起こっているようなのだが原因がわからないので SWT のソースを読みまくってやっと状況が見えてきた。

最初に libswt-xulrunner-gtk の使える環境か否か調べて だめなら libswt-mozilla-gtk を使うようになっていた。

で、ソースをさらに読むとシステムプロパティに org.eclipse.swt.browser.XULRunnerPath が設定されていないと xulrunner を使わないようになっている事が判明。

実行環境に設定したら動いたよ。

-Dorg.eclipse.swt.browser.XULRunnerPath=/usr/local/lib/firefox3

言及しているサイトはあんまり無いけどFirefoxのみの設定だからか?

あちこちにあるサンプルだけど一応置いとく。

import org.eclipse.swt.widgets.*; import org.eclipse.swt.SWT; import org.eclipse.swt.browser.*; import org.eclipse.swt.events.*; import org.eclipse.swt.layout.*; public class BrowserTest { public static void main(String[] args) { Display display = new Display(); final Shell shell = new Shell(display); shell.setText("BrowserTest"); shell.setLayout(new FillLayout()); Browser browser = new Browser(shell, SWT.NONE); browser.setUrl("http://www.yahoo.co.jp"); shell.setSize(800, 600); shell.open(); while (!shell.isDisposed ()){ if (!display.readAndDispatch ()){ display.sleep (); } } shell.dispose(); display.dispose(); } }

実行結果:



プロフィール
20年勤めた会社がリーマンショックで消滅、紆余曲折を経て現在はフリーランスのSE。 失業をきっかけにこのブログを始める。

サイト内検索

登録
RSS/2.0

カテゴリ

最近の投稿【eclipse】

リンク

アーカイブ